159c993d1SWarner Losh /*- 259c993d1SWarner Losh * Copyright (C) 2008-2011 MARVELL INTERNATIONAL LTD. 359c993d1SWarner Losh * All rights reserved. 459c993d1SWarner Losh * 559c993d1SWarner Losh * Developed by Semihalf. 659c993d1SWarner Losh * 759c993d1SWarner Losh * Redistribution and use in source and binary forms, with or without 859c993d1SWarner Losh * modification, are permitted provided that the following conditions 959c993d1SWarner Losh * are met: 1059c993d1SWarner Losh * 1. Redistributions of source code must retain the above copyright 1159c993d1SWarner Losh * notice, this list of conditions and the following disclaimer. 1259c993d1SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 1359c993d1SWarner Losh * notice, this list of conditions and the following disclaimer in the 1459c993d1SWarner Losh * documentation and/or other materials provided with the distribution. 1559c993d1SWarner Losh * 3. Neither the name of MARVELL nor the names of contributors 1659c993d1SWarner Losh * may be used to endorse or promote products derived from this software 1759c993d1SWarner Losh * without specific prior written permission. 1859c993d1SWarner Losh * 1959c993d1SWarner Losh * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2059c993d1SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2159c993d1SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2259c993d1SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 2359c993d1SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2459c993d1SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2559c993d1SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2659c993d1SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2759c993d1SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2859c993d1SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2959c993d1SWarner Losh * SUCH DAMAGE. 3059c993d1SWarner Losh */ 3159c993d1SWarner Losh 3259c993d1SWarner Losh #include <sys/cdefs.h> 3359c993d1SWarner Losh __FBSDID("$FreeBSD$"); 3459c993d1SWarner Losh 3559c993d1SWarner Losh #include <sys/param.h> 3659c993d1SWarner Losh #include <sys/systm.h> 3759c993d1SWarner Losh #include <sys/bus.h> 3859c993d1SWarner Losh #include <sys/kernel.h> 3959c993d1SWarner Losh #include <sys/malloc.h> 4059c993d1SWarner Losh #include <sys/kdb.h> 4159c993d1SWarner Losh #include <sys/reboot.h> 4259c993d1SWarner Losh 4359c993d1SWarner Losh #include <dev/fdt/fdt_common.h> 4459c993d1SWarner Losh #include <dev/ofw/openfirm.h> 4559c993d1SWarner Losh 4659c993d1SWarner Losh #include <machine/bus.h> 4759c993d1SWarner Losh #include <machine/fdt.h> 4859c993d1SWarner Losh #include <machine/vmparam.h> 4959c993d1SWarner Losh 5059c993d1SWarner Losh #include <arm/mv/mvreg.h> 5159c993d1SWarner Losh #include <arm/mv/mvvar.h> 5259c993d1SWarner Losh #include <arm/mv/mvwin.h> 5359c993d1SWarner Losh 5459c993d1SWarner Losh 5559c993d1SWarner Losh MALLOC_DEFINE(M_IDMA, "idma", "idma dma test memory"); 5659c993d1SWarner Losh 5759c993d1SWarner Losh #define IDMA_DEBUG 5859c993d1SWarner Losh #undef IDMA_DEBUG 5959c993d1SWarner Losh 6059c993d1SWarner Losh #define MAX_CPU_WIN 5 6159c993d1SWarner Losh 6259c993d1SWarner Losh #ifdef DEBUG 6359c993d1SWarner Losh #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 6459c993d1SWarner Losh printf(fmt,##args); } while (0) 6559c993d1SWarner Losh #else 6659c993d1SWarner Losh #define debugf(fmt, args...) 6759c993d1SWarner Losh #endif 6859c993d1SWarner Losh 6959c993d1SWarner Losh #ifdef DEBUG 7059c993d1SWarner Losh #define MV_DUMP_WIN 1 7159c993d1SWarner Losh #else 7259c993d1SWarner Losh #define MV_DUMP_WIN 0 7359c993d1SWarner Losh #endif 7459c993d1SWarner Losh 7559c993d1SWarner Losh static int win_eth_can_remap(int i); 7659c993d1SWarner Losh 7759c993d1SWarner Losh #ifndef SOC_MV_FREY 7859c993d1SWarner Losh static int decode_win_cpu_valid(void); 7959c993d1SWarner Losh #endif 8059c993d1SWarner Losh static int decode_win_usb_valid(void); 8159c993d1SWarner Losh static int decode_win_eth_valid(void); 8259c993d1SWarner Losh static int decode_win_pcie_valid(void); 8359c993d1SWarner Losh static int decode_win_sata_valid(void); 8459c993d1SWarner Losh 8559c993d1SWarner Losh static int decode_win_idma_valid(void); 8659c993d1SWarner Losh static int decode_win_xor_valid(void); 8759c993d1SWarner Losh 8859c993d1SWarner Losh #ifndef SOC_MV_FREY 8959c993d1SWarner Losh static void decode_win_cpu_setup(void); 9059c993d1SWarner Losh #endif 9159c993d1SWarner Losh #ifdef SOC_MV_ARMADAXP 9259c993d1SWarner Losh static int decode_win_sdram_fixup(void); 9359c993d1SWarner Losh #endif 9459c993d1SWarner Losh static void decode_win_usb_setup(u_long); 9559c993d1SWarner Losh static void decode_win_eth_setup(u_long); 9659c993d1SWarner Losh static void decode_win_sata_setup(u_long); 9759c993d1SWarner Losh 9859c993d1SWarner Losh static void decode_win_idma_setup(u_long); 9959c993d1SWarner Losh static void decode_win_xor_setup(u_long); 10059c993d1SWarner Losh 10159c993d1SWarner Losh static void decode_win_usb_dump(u_long); 10259c993d1SWarner Losh static void decode_win_eth_dump(u_long base); 10359c993d1SWarner Losh static void decode_win_idma_dump(u_long base); 10459c993d1SWarner Losh static void decode_win_xor_dump(u_long base); 10559c993d1SWarner Losh 10659c993d1SWarner Losh static int fdt_get_ranges(const char *, void *, int, int *, int *); 10759c993d1SWarner Losh 10859c993d1SWarner Losh static int win_cpu_from_dt(void); 10959c993d1SWarner Losh static int fdt_win_setup(void); 11059c993d1SWarner Losh 11159c993d1SWarner Losh static uint32_t dev_mask = 0; 11259c993d1SWarner Losh static int cpu_wins_no = 0; 11359c993d1SWarner Losh static int eth_port = 0; 11459c993d1SWarner Losh static int usb_port = 0; 11559c993d1SWarner Losh 11659c993d1SWarner Losh static struct decode_win cpu_win_tbl[MAX_CPU_WIN]; 11759c993d1SWarner Losh 11859c993d1SWarner Losh const struct decode_win *cpu_wins = cpu_win_tbl; 11959c993d1SWarner Losh 12059c993d1SWarner Losh typedef void (*decode_win_setup_t)(u_long); 12159c993d1SWarner Losh typedef void (*dump_win_t)(u_long); 12259c993d1SWarner Losh 12359c993d1SWarner Losh struct soc_node_spec { 12459c993d1SWarner Losh const char *compat; 12559c993d1SWarner Losh decode_win_setup_t decode_handler; 12659c993d1SWarner Losh dump_win_t dump_handler; 12759c993d1SWarner Losh }; 12859c993d1SWarner Losh 12959c993d1SWarner Losh static struct soc_node_spec soc_nodes[] = { 13059c993d1SWarner Losh { "mrvl,ge", &decode_win_eth_setup, &decode_win_eth_dump }, 13159c993d1SWarner Losh { "mrvl,usb-ehci", &decode_win_usb_setup, &decode_win_usb_dump }, 13259c993d1SWarner Losh { "mrvl,sata", &decode_win_sata_setup, NULL }, 13359c993d1SWarner Losh { "mrvl,xor", &decode_win_xor_setup, &decode_win_xor_dump }, 13459c993d1SWarner Losh { "mrvl,idma", &decode_win_idma_setup, &decode_win_idma_dump }, 13559c993d1SWarner Losh { "mrvl,pcie", &decode_win_pcie_setup, NULL }, 13659c993d1SWarner Losh { NULL, NULL, NULL }, 13759c993d1SWarner Losh }; 13859c993d1SWarner Losh 13959c993d1SWarner Losh struct fdt_pm_mask_entry fdt_pm_mask_table[] = { 14059c993d1SWarner Losh { "mrvl,ge", CPU_PM_CTRL_GE(0) }, 14159c993d1SWarner Losh { "mrvl,ge", CPU_PM_CTRL_GE(1) }, 14259c993d1SWarner Losh { "mrvl,usb-ehci", CPU_PM_CTRL_USB(0) }, 14359c993d1SWarner Losh { "mrvl,usb-ehci", CPU_PM_CTRL_USB(1) }, 14459c993d1SWarner Losh { "mrvl,usb-ehci", CPU_PM_CTRL_USB(2) }, 14559c993d1SWarner Losh { "mrvl,xor", CPU_PM_CTRL_XOR }, 14659c993d1SWarner Losh { "mrvl,sata", CPU_PM_CTRL_SATA }, 14759c993d1SWarner Losh 14859c993d1SWarner Losh { NULL, 0 } 14959c993d1SWarner Losh }; 15059c993d1SWarner Losh 15159c993d1SWarner Losh static __inline int 15259c993d1SWarner Losh pm_is_disabled(uint32_t mask) 15359c993d1SWarner Losh { 15459c993d1SWarner Losh #if defined(SOC_MV_KIRKWOOD) 15559c993d1SWarner Losh return (soc_power_ctrl_get(mask) == mask); 15659c993d1SWarner Losh #else 15759c993d1SWarner Losh return (soc_power_ctrl_get(mask) == mask ? 0 : 1); 15859c993d1SWarner Losh #endif 15959c993d1SWarner Losh } 16059c993d1SWarner Losh 16159c993d1SWarner Losh /* 16259c993d1SWarner Losh * Disable device using power management register. 16359c993d1SWarner Losh * 1 - Device Power On 16459c993d1SWarner Losh * 0 - Device Power Off 16559c993d1SWarner Losh * Mask can be set in loader. 16659c993d1SWarner Losh * EXAMPLE: 16759c993d1SWarner Losh * loader> set hw.pm-disable-mask=0x2 16859c993d1SWarner Losh * 16959c993d1SWarner Losh * Common mask: 17059c993d1SWarner Losh * |-------------------------------| 17159c993d1SWarner Losh * | Device | Kirkwood | Discovery | 17259c993d1SWarner Losh * |-------------------------------| 17359c993d1SWarner Losh * | USB0 | 0x00008 | 0x020000 | 17459c993d1SWarner Losh * |-------------------------------| 17559c993d1SWarner Losh * | USB1 | - | 0x040000 | 17659c993d1SWarner Losh * |-------------------------------| 17759c993d1SWarner Losh * | USB2 | - | 0x080000 | 17859c993d1SWarner Losh * |-------------------------------| 17959c993d1SWarner Losh * | GE0 | 0x00001 | 0x000002 | 18059c993d1SWarner Losh * |-------------------------------| 18159c993d1SWarner Losh * | GE1 | - | 0x000004 | 18259c993d1SWarner Losh * |-------------------------------| 18359c993d1SWarner Losh * | IDMA | - | 0x100000 | 18459c993d1SWarner Losh * |-------------------------------| 18559c993d1SWarner Losh * | XOR | 0x10000 | 0x200000 | 18659c993d1SWarner Losh * |-------------------------------| 18759c993d1SWarner Losh * | CESA | 0x20000 | 0x400000 | 18859c993d1SWarner Losh * |-------------------------------| 18959c993d1SWarner Losh * | SATA | 0x04000 | 0x004000 | 19059c993d1SWarner Losh * --------------------------------| 19159c993d1SWarner Losh * This feature can be used only on Kirkwood and Discovery 19259c993d1SWarner Losh * machines. 19359c993d1SWarner Losh */ 19459c993d1SWarner Losh static __inline void 19559c993d1SWarner Losh pm_disable_device(int mask) 19659c993d1SWarner Losh { 19759c993d1SWarner Losh #ifdef DIAGNOSTIC 19859c993d1SWarner Losh uint32_t reg; 19959c993d1SWarner Losh 20059c993d1SWarner Losh reg = soc_power_ctrl_get(CPU_PM_CTRL_ALL); 20159c993d1SWarner Losh printf("Power Management Register: 0%x\n", reg); 20259c993d1SWarner Losh 20359c993d1SWarner Losh reg &= ~mask; 20459c993d1SWarner Losh soc_power_ctrl_set(reg); 20559c993d1SWarner Losh printf("Device %x is disabled\n", mask); 20659c993d1SWarner Losh 20759c993d1SWarner Losh reg = soc_power_ctrl_get(CPU_PM_CTRL_ALL); 20859c993d1SWarner Losh printf("Power Management Register: 0%x\n", reg); 20959c993d1SWarner Losh #endif 21059c993d1SWarner Losh } 21159c993d1SWarner Losh 21259c993d1SWarner Losh int 21359c993d1SWarner Losh fdt_pm(phandle_t node) 21459c993d1SWarner Losh { 21559c993d1SWarner Losh uint32_t cpu_pm_ctrl; 21659c993d1SWarner Losh int i, ena, compat; 21759c993d1SWarner Losh 21859c993d1SWarner Losh ena = 1; 21959c993d1SWarner Losh cpu_pm_ctrl = read_cpu_ctrl(CPU_PM_CTRL); 22059c993d1SWarner Losh for (i = 0; fdt_pm_mask_table[i].compat != NULL; i++) { 22159c993d1SWarner Losh if (dev_mask & (1 << i)) 22259c993d1SWarner Losh continue; 22359c993d1SWarner Losh 22459c993d1SWarner Losh compat = fdt_is_compatible(node, fdt_pm_mask_table[i].compat); 22559c993d1SWarner Losh #if defined(SOC_MV_KIRKWOOD) 22659c993d1SWarner Losh if (compat && (cpu_pm_ctrl & fdt_pm_mask_table[i].mask)) { 22759c993d1SWarner Losh dev_mask |= (1 << i); 22859c993d1SWarner Losh ena = 0; 22959c993d1SWarner Losh break; 23059c993d1SWarner Losh } else if (compat) { 23159c993d1SWarner Losh dev_mask |= (1 << i); 23259c993d1SWarner Losh break; 23359c993d1SWarner Losh } 23459c993d1SWarner Losh #else 23559c993d1SWarner Losh if (compat && (~cpu_pm_ctrl & fdt_pm_mask_table[i].mask)) { 23659c993d1SWarner Losh dev_mask |= (1 << i); 23759c993d1SWarner Losh ena = 0; 23859c993d1SWarner Losh break; 23959c993d1SWarner Losh } else if (compat) { 24059c993d1SWarner Losh dev_mask |= (1 << i); 24159c993d1SWarner Losh break; 24259c993d1SWarner Losh } 24359c993d1SWarner Losh #endif 24459c993d1SWarner Losh } 24559c993d1SWarner Losh 24659c993d1SWarner Losh return (ena); 24759c993d1SWarner Losh } 24859c993d1SWarner Losh 24959c993d1SWarner Losh uint32_t 25059c993d1SWarner Losh read_cpu_ctrl(uint32_t reg) 25159c993d1SWarner Losh { 25259c993d1SWarner Losh 25359c993d1SWarner Losh return (bus_space_read_4(fdtbus_bs_tag, MV_CPU_CONTROL_BASE, reg)); 25459c993d1SWarner Losh } 25559c993d1SWarner Losh 25659c993d1SWarner Losh void 25759c993d1SWarner Losh write_cpu_ctrl(uint32_t reg, uint32_t val) 25859c993d1SWarner Losh { 25959c993d1SWarner Losh 26059c993d1SWarner Losh bus_space_write_4(fdtbus_bs_tag, MV_CPU_CONTROL_BASE, reg, val); 26159c993d1SWarner Losh } 26259c993d1SWarner Losh 26359c993d1SWarner Losh #if defined(SOC_MV_ARMADAXP) 26459c993d1SWarner Losh uint32_t 26559c993d1SWarner Losh read_cpu_mp_clocks(uint32_t reg) 26659c993d1SWarner Losh { 26759c993d1SWarner Losh 26859c993d1SWarner Losh return (bus_space_read_4(fdtbus_bs_tag, MV_MP_CLOCKS_BASE, reg)); 26959c993d1SWarner Losh } 27059c993d1SWarner Losh 27159c993d1SWarner Losh void 27259c993d1SWarner Losh write_cpu_mp_clocks(uint32_t reg, uint32_t val) 27359c993d1SWarner Losh { 27459c993d1SWarner Losh 27559c993d1SWarner Losh bus_space_write_4(fdtbus_bs_tag, MV_MP_CLOCKS_BASE, reg, val); 27659c993d1SWarner Losh } 27759c993d1SWarner Losh 27859c993d1SWarner Losh uint32_t 27959c993d1SWarner Losh read_cpu_misc(uint32_t reg) 28059c993d1SWarner Losh { 28159c993d1SWarner Losh 28259c993d1SWarner Losh return (bus_space_read_4(fdtbus_bs_tag, MV_MISC_BASE, reg)); 28359c993d1SWarner Losh } 28459c993d1SWarner Losh 28559c993d1SWarner Losh void 28659c993d1SWarner Losh write_cpu_misc(uint32_t reg, uint32_t val) 28759c993d1SWarner Losh { 28859c993d1SWarner Losh 28959c993d1SWarner Losh bus_space_write_4(fdtbus_bs_tag, MV_MISC_BASE, reg, val); 29059c993d1SWarner Losh } 29159c993d1SWarner Losh #endif 29259c993d1SWarner Losh 29359c993d1SWarner Losh void 29459c993d1SWarner Losh cpu_reset(void) 29559c993d1SWarner Losh { 29659c993d1SWarner Losh 29759c993d1SWarner Losh #if defined(SOC_MV_ARMADAXP) 29859c993d1SWarner Losh write_cpu_misc(RSTOUTn_MASK, SOFT_RST_OUT_EN); 29959c993d1SWarner Losh write_cpu_misc(SYSTEM_SOFT_RESET, SYS_SOFT_RST); 30059c993d1SWarner Losh #else 30159c993d1SWarner Losh write_cpu_ctrl(RSTOUTn_MASK, SOFT_RST_OUT_EN); 30259c993d1SWarner Losh write_cpu_ctrl(SYSTEM_SOFT_RESET, SYS_SOFT_RST); 30359c993d1SWarner Losh #endif 30459c993d1SWarner Losh while (1); 30559c993d1SWarner Losh } 30659c993d1SWarner Losh 30759c993d1SWarner Losh uint32_t 30859c993d1SWarner Losh cpu_extra_feat(void) 30959c993d1SWarner Losh { 31059c993d1SWarner Losh uint32_t dev, rev; 31159c993d1SWarner Losh uint32_t ef = 0; 31259c993d1SWarner Losh 31359c993d1SWarner Losh soc_id(&dev, &rev); 31459c993d1SWarner Losh 31559c993d1SWarner Losh switch (dev) { 31659c993d1SWarner Losh case MV_DEV_88F6281: 31759c993d1SWarner Losh case MV_DEV_88F6282: 31859c993d1SWarner Losh case MV_DEV_88RC8180: 31959c993d1SWarner Losh case MV_DEV_MV78100_Z0: 32059c993d1SWarner Losh case MV_DEV_MV78100: 32159c993d1SWarner Losh __asm __volatile("mrc p15, 1, %0, c15, c1, 0" : "=r" (ef)); 32259c993d1SWarner Losh break; 32359c993d1SWarner Losh case MV_DEV_88F5182: 32459c993d1SWarner Losh case MV_DEV_88F5281: 32559c993d1SWarner Losh __asm __volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (ef)); 32659c993d1SWarner Losh break; 32759c993d1SWarner Losh default: 32859c993d1SWarner Losh if (bootverbose) 32959c993d1SWarner Losh printf("This ARM Core does not support any extra features\n"); 33059c993d1SWarner Losh } 33159c993d1SWarner Losh 33259c993d1SWarner Losh return (ef); 33359c993d1SWarner Losh } 33459c993d1SWarner Losh 33559c993d1SWarner Losh /* 33659c993d1SWarner Losh * Get the power status of device. This feature is only supported on 33759c993d1SWarner Losh * Kirkwood and Discovery SoCs. 33859c993d1SWarner Losh */ 33959c993d1SWarner Losh uint32_t 34059c993d1SWarner Losh soc_power_ctrl_get(uint32_t mask) 34159c993d1SWarner Losh { 34259c993d1SWarner Losh 34359c993d1SWarner Losh #if !defined(SOC_MV_ORION) && !defined(SOC_MV_LOKIPLUS) && !defined(SOC_MV_FREY) 34459c993d1SWarner Losh if (mask != CPU_PM_CTRL_NONE) 34559c993d1SWarner Losh mask &= read_cpu_ctrl(CPU_PM_CTRL); 34659c993d1SWarner Losh 34759c993d1SWarner Losh return (mask); 34859c993d1SWarner Losh #else 34959c993d1SWarner Losh return (mask); 35059c993d1SWarner Losh #endif 35159c993d1SWarner Losh } 35259c993d1SWarner Losh 35359c993d1SWarner Losh /* 35459c993d1SWarner Losh * Set the power status of device. This feature is only supported on 35559c993d1SWarner Losh * Kirkwood and Discovery SoCs. 35659c993d1SWarner Losh */ 35759c993d1SWarner Losh void 35859c993d1SWarner Losh soc_power_ctrl_set(uint32_t mask) 35959c993d1SWarner Losh { 36059c993d1SWarner Losh 36159c993d1SWarner Losh #if !defined(SOC_MV_ORION) && !defined(SOC_MV_LOKIPLUS) 36259c993d1SWarner Losh if (mask != CPU_PM_CTRL_NONE) 36359c993d1SWarner Losh write_cpu_ctrl(CPU_PM_CTRL, mask); 36459c993d1SWarner Losh #endif 36559c993d1SWarner Losh } 36659c993d1SWarner Losh 36759c993d1SWarner Losh void 36859c993d1SWarner Losh soc_id(uint32_t *dev, uint32_t *rev) 36959c993d1SWarner Losh { 37059c993d1SWarner Losh 37159c993d1SWarner Losh /* 37259c993d1SWarner Losh * Notice: system identifiers are available in the registers range of 37359c993d1SWarner Losh * PCIE controller, so using this function is only allowed (and 37459c993d1SWarner Losh * possible) after the internal registers range has been mapped in via 37559c993d1SWarner Losh * pmap_devmap_bootstrap(). 37659c993d1SWarner Losh */ 37759c993d1SWarner Losh *dev = bus_space_read_4(fdtbus_bs_tag, MV_PCIE_BASE, 0) >> 16; 37859c993d1SWarner Losh *rev = bus_space_read_4(fdtbus_bs_tag, MV_PCIE_BASE, 8) & 0xff; 37959c993d1SWarner Losh } 38059c993d1SWarner Losh 38159c993d1SWarner Losh static void 38259c993d1SWarner Losh soc_identify(void) 38359c993d1SWarner Losh { 38459c993d1SWarner Losh uint32_t d, r, size, mode; 38559c993d1SWarner Losh const char *dev; 38659c993d1SWarner Losh const char *rev; 38759c993d1SWarner Losh 38859c993d1SWarner Losh soc_id(&d, &r); 38959c993d1SWarner Losh 39059c993d1SWarner Losh printf("SOC: "); 39159c993d1SWarner Losh if (bootverbose) 39259c993d1SWarner Losh printf("(0x%4x:0x%02x) ", d, r); 39359c993d1SWarner Losh 39459c993d1SWarner Losh rev = ""; 39559c993d1SWarner Losh switch (d) { 39659c993d1SWarner Losh case MV_DEV_88F5181: 39759c993d1SWarner Losh dev = "Marvell 88F5181"; 39859c993d1SWarner Losh if (r == 3) 39959c993d1SWarner Losh rev = "B1"; 40059c993d1SWarner Losh break; 40159c993d1SWarner Losh case MV_DEV_88F5182: 40259c993d1SWarner Losh dev = "Marvell 88F5182"; 40359c993d1SWarner Losh if (r == 2) 40459c993d1SWarner Losh rev = "A2"; 40559c993d1SWarner Losh break; 40659c993d1SWarner Losh case MV_DEV_88F5281: 40759c993d1SWarner Losh dev = "Marvell 88F5281"; 40859c993d1SWarner Losh if (r == 4) 40959c993d1SWarner Losh rev = "D0"; 41059c993d1SWarner Losh else if (r == 5) 41159c993d1SWarner Losh rev = "D1"; 41259c993d1SWarner Losh else if (r == 6) 41359c993d1SWarner Losh rev = "D2"; 41459c993d1SWarner Losh break; 41559c993d1SWarner Losh case MV_DEV_88F6281: 41659c993d1SWarner Losh dev = "Marvell 88F6281"; 41759c993d1SWarner Losh if (r == 0) 41859c993d1SWarner Losh rev = "Z0"; 41959c993d1SWarner Losh else if (r == 2) 42059c993d1SWarner Losh rev = "A0"; 42159c993d1SWarner Losh else if (r == 3) 42259c993d1SWarner Losh rev = "A1"; 42359c993d1SWarner Losh break; 42459c993d1SWarner Losh case MV_DEV_88RC8180: 42559c993d1SWarner Losh dev = "Marvell 88RC8180"; 42659c993d1SWarner Losh break; 42759c993d1SWarner Losh case MV_DEV_88RC9480: 42859c993d1SWarner Losh dev = "Marvell 88RC9480"; 42959c993d1SWarner Losh break; 43059c993d1SWarner Losh case MV_DEV_88RC9580: 43159c993d1SWarner Losh dev = "Marvell 88RC9580"; 43259c993d1SWarner Losh break; 43359c993d1SWarner Losh case MV_DEV_88F6781: 43459c993d1SWarner Losh dev = "Marvell 88F6781"; 43559c993d1SWarner Losh if (r == 2) 43659c993d1SWarner Losh rev = "Y0"; 43759c993d1SWarner Losh break; 43859c993d1SWarner Losh case MV_DEV_88F6282: 43959c993d1SWarner Losh dev = "Marvell 88F6282"; 44059c993d1SWarner Losh if (r == 0) 44159c993d1SWarner Losh rev = "A0"; 44259c993d1SWarner Losh else if (r == 1) 44359c993d1SWarner Losh rev = "A1"; 44459c993d1SWarner Losh break; 44559c993d1SWarner Losh case MV_DEV_MV78100_Z0: 44659c993d1SWarner Losh dev = "Marvell MV78100 Z0"; 44759c993d1SWarner Losh break; 44859c993d1SWarner Losh case MV_DEV_MV78100: 44959c993d1SWarner Losh dev = "Marvell MV78100"; 45059c993d1SWarner Losh break; 45159c993d1SWarner Losh case MV_DEV_MV78160: 45259c993d1SWarner Losh dev = "Marvell MV78160"; 45359c993d1SWarner Losh break; 45459c993d1SWarner Losh case MV_DEV_MV78260: 45559c993d1SWarner Losh dev = "Marvell MV78260"; 45659c993d1SWarner Losh break; 45759c993d1SWarner Losh case MV_DEV_MV78460: 45859c993d1SWarner Losh dev = "Marvell MV78460"; 45959c993d1SWarner Losh break; 46059c993d1SWarner Losh default: 46159c993d1SWarner Losh dev = "UNKNOWN"; 46259c993d1SWarner Losh break; 46359c993d1SWarner Losh } 46459c993d1SWarner Losh 46559c993d1SWarner Losh printf("%s", dev); 46659c993d1SWarner Losh if (*rev != '\0') 46759c993d1SWarner Losh printf(" rev %s", rev); 46859c993d1SWarner Losh printf(", TClock %dMHz\n", get_tclk() / 1000 / 1000); 46959c993d1SWarner Losh 47059c993d1SWarner Losh mode = read_cpu_ctrl(CPU_CONFIG); 47159c993d1SWarner Losh printf(" Instruction cache prefetch %s, data cache prefetch %s\n", 47259c993d1SWarner Losh (mode & CPU_CONFIG_IC_PREF) ? "enabled" : "disabled", 47359c993d1SWarner Losh (mode & CPU_CONFIG_DC_PREF) ? "enabled" : "disabled"); 47459c993d1SWarner Losh 47559c993d1SWarner Losh switch (d) { 47659c993d1SWarner Losh case MV_DEV_88F6281: 47759c993d1SWarner Losh case MV_DEV_88F6282: 47859c993d1SWarner Losh mode = read_cpu_ctrl(CPU_L2_CONFIG) & CPU_L2_CONFIG_MODE; 47959c993d1SWarner Losh printf(" 256KB 4-way set-associative %s unified L2 cache\n", 48059c993d1SWarner Losh mode ? "write-through" : "write-back"); 48159c993d1SWarner Losh break; 48259c993d1SWarner Losh case MV_DEV_MV78100: 48359c993d1SWarner Losh mode = read_cpu_ctrl(CPU_CONTROL); 48459c993d1SWarner Losh size = mode & CPU_CONTROL_L2_SIZE; 48559c993d1SWarner Losh mode = mode & CPU_CONTROL_L2_MODE; 48659c993d1SWarner Losh printf(" %s set-associative %s unified L2 cache\n", 48759c993d1SWarner Losh size ? "256KB 4-way" : "512KB 8-way", 48859c993d1SWarner Losh mode ? "write-through" : "write-back"); 48959c993d1SWarner Losh break; 49059c993d1SWarner Losh default: 49159c993d1SWarner Losh break; 49259c993d1SWarner Losh } 49359c993d1SWarner Losh } 49459c993d1SWarner Losh 49559c993d1SWarner Losh static void 49659c993d1SWarner Losh platform_identify(void *dummy) 49759c993d1SWarner Losh { 49859c993d1SWarner Losh 49959c993d1SWarner Losh soc_identify(); 50059c993d1SWarner Losh 50159c993d1SWarner Losh /* 50259c993d1SWarner Losh * XXX Board identification e.g. read out from FPGA or similar should 50359c993d1SWarner Losh * go here 50459c993d1SWarner Losh */ 50559c993d1SWarner Losh } 50659c993d1SWarner Losh SYSINIT(platform_identify, SI_SUB_CPU, SI_ORDER_SECOND, platform_identify, 50759c993d1SWarner Losh NULL); 50859c993d1SWarner Losh 50959c993d1SWarner Losh #ifdef KDB 51059c993d1SWarner Losh static void 51159c993d1SWarner Losh mv_enter_debugger(void *dummy) 51259c993d1SWarner Losh { 51359c993d1SWarner Losh 51459c993d1SWarner Losh if (boothowto & RB_KDB) 51559c993d1SWarner Losh kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); 51659c993d1SWarner Losh } 51759c993d1SWarner Losh SYSINIT(mv_enter_debugger, SI_SUB_CPU, SI_ORDER_ANY, mv_enter_debugger, NULL); 51859c993d1SWarner Losh #endif 51959c993d1SWarner Losh 52059c993d1SWarner Losh int 52159c993d1SWarner Losh soc_decode_win(void) 52259c993d1SWarner Losh { 52359c993d1SWarner Losh uint32_t dev, rev; 52459c993d1SWarner Losh int mask, err; 52559c993d1SWarner Losh 52659c993d1SWarner Losh mask = 0; 52759c993d1SWarner Losh TUNABLE_INT_FETCH("hw.pm-disable-mask", &mask); 52859c993d1SWarner Losh 52959c993d1SWarner Losh if (mask != 0) 53059c993d1SWarner Losh pm_disable_device(mask); 53159c993d1SWarner Losh 53259c993d1SWarner Losh /* Retrieve data about physical addresses from device tree. */ 53359c993d1SWarner Losh if ((err = win_cpu_from_dt()) != 0) 53459c993d1SWarner Losh return (err); 53559c993d1SWarner Losh 53659c993d1SWarner Losh /* Retrieve our ID: some windows facilities vary between SoC models */ 53759c993d1SWarner Losh soc_id(&dev, &rev); 53859c993d1SWarner Losh 53959c993d1SWarner Losh #ifdef SOC_MV_ARMADAXP 54059c993d1SWarner Losh if ((err = decode_win_sdram_fixup()) != 0) 54159c993d1SWarner Losh return(err); 54259c993d1SWarner Losh #endif 54359c993d1SWarner Losh 54459c993d1SWarner Losh #ifndef SOC_MV_FREY 54559c993d1SWarner Losh if (!decode_win_cpu_valid() || !decode_win_usb_valid() || 54659c993d1SWarner Losh !decode_win_eth_valid() || !decode_win_idma_valid() || 54759c993d1SWarner Losh !decode_win_pcie_valid() || !decode_win_sata_valid() || 54859c993d1SWarner Losh !decode_win_xor_valid()) 54959c993d1SWarner Losh return (EINVAL); 55059c993d1SWarner Losh 55159c993d1SWarner Losh decode_win_cpu_setup(); 55259c993d1SWarner Losh #else 55359c993d1SWarner Losh if (!decode_win_usb_valid() || 55459c993d1SWarner Losh !decode_win_eth_valid() || !decode_win_idma_valid() || 55559c993d1SWarner Losh !decode_win_pcie_valid() || !decode_win_sata_valid() || 55659c993d1SWarner Losh !decode_win_xor_valid()) 55759c993d1SWarner Losh return (EINVAL); 55859c993d1SWarner Losh #endif 55959c993d1SWarner Losh if (MV_DUMP_WIN) 56059c993d1SWarner Losh soc_dump_decode_win(); 56159c993d1SWarner Losh 56259c993d1SWarner Losh eth_port = 0; 56359c993d1SWarner Losh usb_port = 0; 56459c993d1SWarner Losh if ((err = fdt_win_setup()) != 0) 56559c993d1SWarner Losh return (err); 56659c993d1SWarner Losh 56759c993d1SWarner Losh return (0); 56859c993d1SWarner Losh } 56959c993d1SWarner Losh 57059c993d1SWarner Losh /************************************************************************** 57159c993d1SWarner Losh * Decode windows registers accessors 57259c993d1SWarner Losh **************************************************************************/ 57359c993d1SWarner Losh #if !defined(SOC_MV_FREY) 57459c993d1SWarner Losh WIN_REG_IDX_RD(win_cpu, cr, MV_WIN_CPU_CTRL, MV_MBUS_BRIDGE_BASE) 57559c993d1SWarner Losh WIN_REG_IDX_RD(win_cpu, br, MV_WIN_CPU_BASE, MV_MBUS_BRIDGE_BASE) 57659c993d1SWarner Losh WIN_REG_IDX_RD(win_cpu, remap_l, MV_WIN_CPU_REMAP_LO, MV_MBUS_BRIDGE_BASE) 57759c993d1SWarner Losh WIN_REG_IDX_RD(win_cpu, remap_h, MV_WIN_CPU_REMAP_HI, MV_MBUS_BRIDGE_BASE) 57859c993d1SWarner Losh WIN_REG_IDX_WR(win_cpu, cr, MV_WIN_CPU_CTRL, MV_MBUS_BRIDGE_BASE) 57959c993d1SWarner Losh WIN_REG_IDX_WR(win_cpu, br, MV_WIN_CPU_BASE, MV_MBUS_BRIDGE_BASE) 58059c993d1SWarner Losh WIN_REG_IDX_WR(win_cpu, remap_l, MV_WIN_CPU_REMAP_LO, MV_MBUS_BRIDGE_BASE) 58159c993d1SWarner Losh WIN_REG_IDX_WR(win_cpu, remap_h, MV_WIN_CPU_REMAP_HI, MV_MBUS_BRIDGE_BASE) 58259c993d1SWarner Losh #endif 58359c993d1SWarner Losh 58459c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_usb, cr, MV_WIN_USB_CTRL) 58559c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_usb, br, MV_WIN_USB_BASE) 58659c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_usb, cr, MV_WIN_USB_CTRL) 58759c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_usb, br, MV_WIN_USB_BASE) 58859c993d1SWarner Losh 58959c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_eth, br, MV_WIN_ETH_BASE) 59059c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_eth, sz, MV_WIN_ETH_SIZE) 59159c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_eth, har, MV_WIN_ETH_REMAP) 59259c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_eth, br, MV_WIN_ETH_BASE) 59359c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_eth, sz, MV_WIN_ETH_SIZE) 59459c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_eth, har, MV_WIN_ETH_REMAP) 59559c993d1SWarner Losh 59659c993d1SWarner Losh WIN_REG_BASE_IDX_RD2(win_xor, br, MV_WIN_XOR_BASE) 59759c993d1SWarner Losh WIN_REG_BASE_IDX_RD2(win_xor, sz, MV_WIN_XOR_SIZE) 59859c993d1SWarner Losh WIN_REG_BASE_IDX_RD2(win_xor, har, MV_WIN_XOR_REMAP) 59959c993d1SWarner Losh WIN_REG_BASE_IDX_RD2(win_xor, ctrl, MV_WIN_XOR_CTRL) 60059c993d1SWarner Losh WIN_REG_BASE_IDX_WR2(win_xor, br, MV_WIN_XOR_BASE) 60159c993d1SWarner Losh WIN_REG_BASE_IDX_WR2(win_xor, sz, MV_WIN_XOR_SIZE) 60259c993d1SWarner Losh WIN_REG_BASE_IDX_WR2(win_xor, har, MV_WIN_XOR_REMAP) 60359c993d1SWarner Losh WIN_REG_BASE_IDX_WR2(win_xor, ctrl, MV_WIN_XOR_CTRL) 60459c993d1SWarner Losh 60559c993d1SWarner Losh WIN_REG_BASE_RD(win_eth, bare, 0x290) 60659c993d1SWarner Losh WIN_REG_BASE_RD(win_eth, epap, 0x294) 60759c993d1SWarner Losh WIN_REG_BASE_WR(win_eth, bare, 0x290) 60859c993d1SWarner Losh WIN_REG_BASE_WR(win_eth, epap, 0x294) 60959c993d1SWarner Losh 61059c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_pcie, cr, MV_WIN_PCIE_CTRL); 61159c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_pcie, br, MV_WIN_PCIE_BASE); 61259c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_pcie, remap, MV_WIN_PCIE_REMAP); 61359c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_pcie, cr, MV_WIN_PCIE_CTRL); 61459c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_pcie, br, MV_WIN_PCIE_BASE); 61559c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_pcie, remap, MV_WIN_PCIE_REMAP); 61659c993d1SWarner Losh WIN_REG_BASE_IDX_RD(pcie_bar, br, MV_PCIE_BAR_BASE); 61759c993d1SWarner Losh WIN_REG_BASE_IDX_WR(pcie_bar, br, MV_PCIE_BAR_BASE); 61859c993d1SWarner Losh WIN_REG_BASE_IDX_WR(pcie_bar, brh, MV_PCIE_BAR_BASE_H); 61959c993d1SWarner Losh WIN_REG_BASE_IDX_WR(pcie_bar, cr, MV_PCIE_BAR_CTRL); 62059c993d1SWarner Losh 62159c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_idma, br, MV_WIN_IDMA_BASE) 62259c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_idma, sz, MV_WIN_IDMA_SIZE) 62359c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_idma, har, MV_WIN_IDMA_REMAP) 62459c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_idma, cap, MV_WIN_IDMA_CAP) 62559c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_idma, br, MV_WIN_IDMA_BASE) 62659c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_idma, sz, MV_WIN_IDMA_SIZE) 62759c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_idma, har, MV_WIN_IDMA_REMAP) 62859c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_idma, cap, MV_WIN_IDMA_CAP) 62959c993d1SWarner Losh WIN_REG_BASE_RD(win_idma, bare, 0xa80) 63059c993d1SWarner Losh WIN_REG_BASE_WR(win_idma, bare, 0xa80) 63159c993d1SWarner Losh 63259c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_sata, cr, MV_WIN_SATA_CTRL); 63359c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_sata, br, MV_WIN_SATA_BASE); 63459c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_sata, cr, MV_WIN_SATA_CTRL); 63559c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_sata, br, MV_WIN_SATA_BASE); 63659c993d1SWarner Losh #ifndef SOC_MV_DOVE 63759c993d1SWarner Losh WIN_REG_IDX_RD(ddr, br, MV_WIN_DDR_BASE, MV_DDR_CADR_BASE) 63859c993d1SWarner Losh WIN_REG_IDX_RD(ddr, sz, MV_WIN_DDR_SIZE, MV_DDR_CADR_BASE) 63959c993d1SWarner Losh WIN_REG_IDX_WR(ddr, br, MV_WIN_DDR_BASE, MV_DDR_CADR_BASE) 64059c993d1SWarner Losh WIN_REG_IDX_WR(ddr, sz, MV_WIN_DDR_SIZE, MV_DDR_CADR_BASE) 64159c993d1SWarner Losh #else 64259c993d1SWarner Losh /* 64359c993d1SWarner Losh * On 88F6781 (Dove) SoC DDR Controller is accessed through 64459c993d1SWarner Losh * single MBUS <-> AXI bridge. In this case we provide emulated 64559c993d1SWarner Losh * ddr_br_read() and ddr_sz_read() functions to keep compatibility 64659c993d1SWarner Losh * with common decoding windows setup code. 64759c993d1SWarner Losh */ 64859c993d1SWarner Losh 64959c993d1SWarner Losh static inline uint32_t ddr_br_read(int i) 65059c993d1SWarner Losh { 65159c993d1SWarner Losh uint32_t mmap; 65259c993d1SWarner Losh 65359c993d1SWarner Losh /* Read Memory Address Map Register for CS i */ 65459c993d1SWarner Losh mmap = bus_space_read_4(fdtbus_bs_tag, MV_DDR_CADR_BASE + (i * 0x10), 0); 65559c993d1SWarner Losh 65659c993d1SWarner Losh /* Return CS i base address */ 65759c993d1SWarner Losh return (mmap & 0xFF000000); 65859c993d1SWarner Losh } 65959c993d1SWarner Losh 66059c993d1SWarner Losh static inline uint32_t ddr_sz_read(int i) 66159c993d1SWarner Losh { 66259c993d1SWarner Losh uint32_t mmap, size; 66359c993d1SWarner Losh 66459c993d1SWarner Losh /* Read Memory Address Map Register for CS i */ 66559c993d1SWarner Losh mmap = bus_space_read_4(fdtbus_bs_tag, MV_DDR_CADR_BASE + (i * 0x10), 0); 66659c993d1SWarner Losh 66759c993d1SWarner Losh /* Extract size of CS space in 64kB units */ 66859c993d1SWarner Losh size = (1 << ((mmap >> 16) & 0x0F)); 66959c993d1SWarner Losh 67059c993d1SWarner Losh /* Return CS size and enable/disable status */ 67159c993d1SWarner Losh return (((size - 1) << 16) | (mmap & 0x01)); 67259c993d1SWarner Losh } 67359c993d1SWarner Losh #endif 67459c993d1SWarner Losh 67559c993d1SWarner Losh #if !defined(SOC_MV_FREY) 67659c993d1SWarner Losh /************************************************************************** 67759c993d1SWarner Losh * Decode windows helper routines 67859c993d1SWarner Losh **************************************************************************/ 67959c993d1SWarner Losh void 68059c993d1SWarner Losh soc_dump_decode_win(void) 68159c993d1SWarner Losh { 68259c993d1SWarner Losh uint32_t dev, rev; 68359c993d1SWarner Losh int i; 68459c993d1SWarner Losh 68559c993d1SWarner Losh soc_id(&dev, &rev); 68659c993d1SWarner Losh 68759c993d1SWarner Losh for (i = 0; i < MV_WIN_CPU_MAX; i++) { 68859c993d1SWarner Losh printf("CPU window#%d: c 0x%08x, b 0x%08x", i, 68959c993d1SWarner Losh win_cpu_cr_read(i), 69059c993d1SWarner Losh win_cpu_br_read(i)); 69159c993d1SWarner Losh 69259c993d1SWarner Losh if (win_cpu_can_remap(i)) 69359c993d1SWarner Losh printf(", rl 0x%08x, rh 0x%08x", 69459c993d1SWarner Losh win_cpu_remap_l_read(i), 69559c993d1SWarner Losh win_cpu_remap_h_read(i)); 69659c993d1SWarner Losh 69759c993d1SWarner Losh printf("\n"); 69859c993d1SWarner Losh } 69959c993d1SWarner Losh printf("Internal regs base: 0x%08x\n", 70059c993d1SWarner Losh bus_space_read_4(fdtbus_bs_tag, MV_INTREGS_BASE, 0)); 70159c993d1SWarner Losh 70259c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) 70359c993d1SWarner Losh printf("DDR CS#%d: b 0x%08x, s 0x%08x\n", i, 70459c993d1SWarner Losh ddr_br_read(i), ddr_sz_read(i)); 70559c993d1SWarner Losh } 70659c993d1SWarner Losh 70759c993d1SWarner Losh /************************************************************************** 70859c993d1SWarner Losh * CPU windows routines 70959c993d1SWarner Losh **************************************************************************/ 71059c993d1SWarner Losh int 71159c993d1SWarner Losh win_cpu_can_remap(int i) 71259c993d1SWarner Losh { 71359c993d1SWarner Losh uint32_t dev, rev; 71459c993d1SWarner Losh 71559c993d1SWarner Losh soc_id(&dev, &rev); 71659c993d1SWarner Losh 71759c993d1SWarner Losh /* Depending on the SoC certain windows have remap capability */ 71859c993d1SWarner Losh if ((dev == MV_DEV_88F5182 && i < 2) || 71959c993d1SWarner Losh (dev == MV_DEV_88F5281 && i < 4) || 72059c993d1SWarner Losh (dev == MV_DEV_88F6281 && i < 4) || 72159c993d1SWarner Losh (dev == MV_DEV_88F6282 && i < 4) || 72259c993d1SWarner Losh (dev == MV_DEV_88RC8180 && i < 2) || 72359c993d1SWarner Losh (dev == MV_DEV_88F6781 && i < 4) || 72459c993d1SWarner Losh (dev == MV_DEV_MV78100_Z0 && i < 8) || 72559c993d1SWarner Losh ((dev & MV_DEV_FAMILY_MASK) == MV_DEV_DISCOVERY && i < 8)) 72659c993d1SWarner Losh return (1); 72759c993d1SWarner Losh 72859c993d1SWarner Losh return (0); 72959c993d1SWarner Losh } 73059c993d1SWarner Losh 73159c993d1SWarner Losh /* XXX This should check for overlapping remap fields too.. */ 73259c993d1SWarner Losh int 73359c993d1SWarner Losh decode_win_overlap(int win, int win_no, const struct decode_win *wintab) 73459c993d1SWarner Losh { 73559c993d1SWarner Losh const struct decode_win *tab; 73659c993d1SWarner Losh int i; 73759c993d1SWarner Losh 73859c993d1SWarner Losh tab = wintab; 73959c993d1SWarner Losh 74059c993d1SWarner Losh for (i = 0; i < win_no; i++, tab++) { 74159c993d1SWarner Losh if (i == win) 74259c993d1SWarner Losh /* Skip self */ 74359c993d1SWarner Losh continue; 74459c993d1SWarner Losh 74559c993d1SWarner Losh if ((tab->base + tab->size - 1) < (wintab + win)->base) 74659c993d1SWarner Losh continue; 74759c993d1SWarner Losh 74859c993d1SWarner Losh else if (((wintab + win)->base + (wintab + win)->size - 1) < 74959c993d1SWarner Losh tab->base) 75059c993d1SWarner Losh continue; 75159c993d1SWarner Losh else 75259c993d1SWarner Losh return (i); 75359c993d1SWarner Losh } 75459c993d1SWarner Losh 75559c993d1SWarner Losh return (-1); 75659c993d1SWarner Losh } 75759c993d1SWarner Losh 75859c993d1SWarner Losh static int 75959c993d1SWarner Losh decode_win_cpu_valid(void) 76059c993d1SWarner Losh { 76159c993d1SWarner Losh int i, j, rv; 76259c993d1SWarner Losh uint32_t b, e, s; 76359c993d1SWarner Losh 76459c993d1SWarner Losh if (cpu_wins_no > MV_WIN_CPU_MAX) { 76559c993d1SWarner Losh printf("CPU windows: too many entries: %d\n", cpu_wins_no); 76659c993d1SWarner Losh return (0); 76759c993d1SWarner Losh } 76859c993d1SWarner Losh 76959c993d1SWarner Losh rv = 1; 77059c993d1SWarner Losh for (i = 0; i < cpu_wins_no; i++) { 77159c993d1SWarner Losh 77259c993d1SWarner Losh if (cpu_wins[i].target == 0) { 77359c993d1SWarner Losh printf("CPU window#%d: DDR target window is not " 77459c993d1SWarner Losh "supposed to be reprogrammed!\n", i); 77559c993d1SWarner Losh rv = 0; 77659c993d1SWarner Losh } 77759c993d1SWarner Losh 77859c993d1SWarner Losh if (cpu_wins[i].remap != ~0 && win_cpu_can_remap(i) != 1) { 77959c993d1SWarner Losh printf("CPU window#%d: not capable of remapping, but " 78059c993d1SWarner Losh "val 0x%08x defined\n", i, cpu_wins[i].remap); 78159c993d1SWarner Losh rv = 0; 78259c993d1SWarner Losh } 78359c993d1SWarner Losh 78459c993d1SWarner Losh s = cpu_wins[i].size; 78559c993d1SWarner Losh b = cpu_wins[i].base; 78659c993d1SWarner Losh e = b + s - 1; 78759c993d1SWarner Losh if (s > (0xFFFFFFFF - b + 1)) { 78859c993d1SWarner Losh /* 78959c993d1SWarner Losh * XXX this boundary check should account for 64bit 79059c993d1SWarner Losh * and remapping.. 79159c993d1SWarner Losh */ 79259c993d1SWarner Losh printf("CPU window#%d: no space for size 0x%08x at " 79359c993d1SWarner Losh "0x%08x\n", i, s, b); 79459c993d1SWarner Losh rv = 0; 79559c993d1SWarner Losh continue; 79659c993d1SWarner Losh } 79759c993d1SWarner Losh 79859c993d1SWarner Losh if (b != (b & ~(s - 1))) { 79959c993d1SWarner Losh printf("CPU window#%d: address 0x%08x is not aligned " 80059c993d1SWarner Losh "to 0x%08x\n", i, b, s); 80159c993d1SWarner Losh rv = 0; 80259c993d1SWarner Losh continue; 80359c993d1SWarner Losh } 80459c993d1SWarner Losh 80559c993d1SWarner Losh j = decode_win_overlap(i, cpu_wins_no, &cpu_wins[0]); 80659c993d1SWarner Losh if (j >= 0) { 80759c993d1SWarner Losh printf("CPU window#%d: (0x%08x - 0x%08x) overlaps " 80859c993d1SWarner Losh "with #%d (0x%08x - 0x%08x)\n", i, b, e, j, 80959c993d1SWarner Losh cpu_wins[j].base, 81059c993d1SWarner Losh cpu_wins[j].base + cpu_wins[j].size - 1); 81159c993d1SWarner Losh rv = 0; 81259c993d1SWarner Losh } 81359c993d1SWarner Losh } 81459c993d1SWarner Losh 81559c993d1SWarner Losh return (rv); 81659c993d1SWarner Losh } 81759c993d1SWarner Losh 81859c993d1SWarner Losh int 81959c993d1SWarner Losh decode_win_cpu_set(int target, int attr, vm_paddr_t base, uint32_t size, 82059c993d1SWarner Losh vm_paddr_t remap) 82159c993d1SWarner Losh { 82259c993d1SWarner Losh uint32_t br, cr; 82359c993d1SWarner Losh int win, i; 82459c993d1SWarner Losh 82559c993d1SWarner Losh if (remap == ~0) { 82659c993d1SWarner Losh win = MV_WIN_CPU_MAX - 1; 82759c993d1SWarner Losh i = -1; 82859c993d1SWarner Losh } else { 82959c993d1SWarner Losh win = 0; 83059c993d1SWarner Losh i = 1; 83159c993d1SWarner Losh } 83259c993d1SWarner Losh 83359c993d1SWarner Losh while ((win >= 0) && (win < MV_WIN_CPU_MAX)) { 83459c993d1SWarner Losh cr = win_cpu_cr_read(win); 83559c993d1SWarner Losh if ((cr & MV_WIN_CPU_ENABLE_BIT) == 0) 83659c993d1SWarner Losh break; 83759c993d1SWarner Losh if ((cr & ((0xff << MV_WIN_CPU_ATTR_SHIFT) | 83859c993d1SWarner Losh (0x1f << MV_WIN_CPU_TARGET_SHIFT))) == 83959c993d1SWarner Losh ((attr << MV_WIN_CPU_ATTR_SHIFT) | 84059c993d1SWarner Losh (target << MV_WIN_CPU_TARGET_SHIFT))) 84159c993d1SWarner Losh break; 84259c993d1SWarner Losh win += i; 84359c993d1SWarner Losh } 84459c993d1SWarner Losh if ((win < 0) || (win >= MV_WIN_CPU_MAX) || 84559c993d1SWarner Losh ((remap != ~0) && (win_cpu_can_remap(win) == 0))) 84659c993d1SWarner Losh return (-1); 84759c993d1SWarner Losh 84859c993d1SWarner Losh br = base & 0xffff0000; 84959c993d1SWarner Losh win_cpu_br_write(win, br); 85059c993d1SWarner Losh 85159c993d1SWarner Losh if (win_cpu_can_remap(win)) { 85259c993d1SWarner Losh if (remap != ~0) { 85359c993d1SWarner Losh win_cpu_remap_l_write(win, remap & 0xffff0000); 85459c993d1SWarner Losh win_cpu_remap_h_write(win, 0); 85559c993d1SWarner Losh } else { 85659c993d1SWarner Losh /* 85759c993d1SWarner Losh * Remap function is not used for a given window 85859c993d1SWarner Losh * (capable of remapping) - set remap field with the 85959c993d1SWarner Losh * same value as base. 86059c993d1SWarner Losh */ 86159c993d1SWarner Losh win_cpu_remap_l_write(win, base & 0xffff0000); 86259c993d1SWarner Losh win_cpu_remap_h_write(win, 0); 86359c993d1SWarner Losh } 86459c993d1SWarner Losh } 86559c993d1SWarner Losh 86659c993d1SWarner Losh cr = ((size - 1) & 0xffff0000) | (attr << MV_WIN_CPU_ATTR_SHIFT) | 86759c993d1SWarner Losh (target << MV_WIN_CPU_TARGET_SHIFT) | MV_WIN_CPU_ENABLE_BIT; 86859c993d1SWarner Losh win_cpu_cr_write(win, cr); 86959c993d1SWarner Losh 87059c993d1SWarner Losh return (0); 87159c993d1SWarner Losh } 87259c993d1SWarner Losh 87359c993d1SWarner Losh static void 87459c993d1SWarner Losh decode_win_cpu_setup(void) 87559c993d1SWarner Losh { 87659c993d1SWarner Losh int i; 87759c993d1SWarner Losh 87859c993d1SWarner Losh /* Disable all CPU windows */ 87959c993d1SWarner Losh for (i = 0; i < MV_WIN_CPU_MAX; i++) { 88059c993d1SWarner Losh win_cpu_cr_write(i, 0); 88159c993d1SWarner Losh win_cpu_br_write(i, 0); 88259c993d1SWarner Losh if (win_cpu_can_remap(i)) { 88359c993d1SWarner Losh win_cpu_remap_l_write(i, 0); 88459c993d1SWarner Losh win_cpu_remap_h_write(i, 0); 88559c993d1SWarner Losh } 88659c993d1SWarner Losh } 88759c993d1SWarner Losh 88859c993d1SWarner Losh for (i = 0; i < cpu_wins_no; i++) 88959c993d1SWarner Losh if (cpu_wins[i].target > 0) 89059c993d1SWarner Losh decode_win_cpu_set(cpu_wins[i].target, 89159c993d1SWarner Losh cpu_wins[i].attr, cpu_wins[i].base, 89259c993d1SWarner Losh cpu_wins[i].size, cpu_wins[i].remap); 89359c993d1SWarner Losh 89459c993d1SWarner Losh } 89559c993d1SWarner Losh #endif 89659c993d1SWarner Losh 89759c993d1SWarner Losh #ifdef SOC_MV_ARMADAXP 89859c993d1SWarner Losh static int 89959c993d1SWarner Losh decode_win_sdram_fixup(void) 90059c993d1SWarner Losh { 90159c993d1SWarner Losh struct mem_region mr[FDT_MEM_REGIONS]; 90259c993d1SWarner Losh uint8_t window_valid[MV_WIN_DDR_MAX]; 90359c993d1SWarner Losh int mr_cnt, memsize, err, i, j; 90459c993d1SWarner Losh uint32_t valid_win_num = 0; 90559c993d1SWarner Losh 90659c993d1SWarner Losh /* Grab physical memory regions information from device tree. */ 90759c993d1SWarner Losh err = fdt_get_mem_regions(mr, &mr_cnt, &memsize); 90859c993d1SWarner Losh if (err != 0) 90959c993d1SWarner Losh return (err); 91059c993d1SWarner Losh 91159c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) 91259c993d1SWarner Losh window_valid[i] = 0; 91359c993d1SWarner Losh 91459c993d1SWarner Losh /* Try to match entries from device tree with settings from u-boot */ 91559c993d1SWarner Losh for (i = 0; i < mr_cnt; i++) { 91659c993d1SWarner Losh for (j = 0; j < MV_WIN_DDR_MAX; j++) { 91759c993d1SWarner Losh if (ddr_is_active(j) && 91859c993d1SWarner Losh (ddr_base(j) == mr[i].mr_start) && 91959c993d1SWarner Losh (ddr_size(j) == mr[i].mr_size)) { 92059c993d1SWarner Losh window_valid[j] = 1; 92159c993d1SWarner Losh valid_win_num++; 92259c993d1SWarner Losh } 92359c993d1SWarner Losh } 92459c993d1SWarner Losh } 92559c993d1SWarner Losh 92659c993d1SWarner Losh if (mr_cnt != valid_win_num) 92759c993d1SWarner Losh return (EINVAL); 92859c993d1SWarner Losh 92959c993d1SWarner Losh /* Destroy windows without corresponding device tree entry */ 93059c993d1SWarner Losh for (j = 0; j < MV_WIN_DDR_MAX; j++) { 93159c993d1SWarner Losh if (ddr_is_active(j) && (window_valid[j] != 1)) { 93259c993d1SWarner Losh printf("Disabling SDRAM decoding window: %d\n", j); 93359c993d1SWarner Losh ddr_disable(j); 93459c993d1SWarner Losh } 93559c993d1SWarner Losh } 93659c993d1SWarner Losh 93759c993d1SWarner Losh return (0); 93859c993d1SWarner Losh } 93959c993d1SWarner Losh #endif 94059c993d1SWarner Losh /* 94159c993d1SWarner Losh * Check if we're able to cover all active DDR banks. 94259c993d1SWarner Losh */ 94359c993d1SWarner Losh static int 94459c993d1SWarner Losh decode_win_can_cover_ddr(int max) 94559c993d1SWarner Losh { 94659c993d1SWarner Losh int i, c; 94759c993d1SWarner Losh 94859c993d1SWarner Losh c = 0; 94959c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) 95059c993d1SWarner Losh if (ddr_is_active(i)) 95159c993d1SWarner Losh c++; 95259c993d1SWarner Losh 95359c993d1SWarner Losh if (c > max) { 95459c993d1SWarner Losh printf("Unable to cover all active DDR banks: " 95559c993d1SWarner Losh "%d, available windows: %d\n", c, max); 95659c993d1SWarner Losh return (0); 95759c993d1SWarner Losh } 95859c993d1SWarner Losh 95959c993d1SWarner Losh return (1); 96059c993d1SWarner Losh } 96159c993d1SWarner Losh 96259c993d1SWarner Losh /************************************************************************** 96359c993d1SWarner Losh * DDR windows routines 96459c993d1SWarner Losh **************************************************************************/ 96559c993d1SWarner Losh int 96659c993d1SWarner Losh ddr_is_active(int i) 96759c993d1SWarner Losh { 96859c993d1SWarner Losh 96959c993d1SWarner Losh if (ddr_sz_read(i) & 0x1) 97059c993d1SWarner Losh return (1); 97159c993d1SWarner Losh 97259c993d1SWarner Losh return (0); 97359c993d1SWarner Losh } 97459c993d1SWarner Losh 97559c993d1SWarner Losh void 97659c993d1SWarner Losh ddr_disable(int i) 97759c993d1SWarner Losh { 97859c993d1SWarner Losh 97959c993d1SWarner Losh ddr_sz_write(i, 0); 98059c993d1SWarner Losh ddr_br_write(i, 0); 98159c993d1SWarner Losh } 98259c993d1SWarner Losh 98359c993d1SWarner Losh uint32_t 98459c993d1SWarner Losh ddr_base(int i) 98559c993d1SWarner Losh { 98659c993d1SWarner Losh 98759c993d1SWarner Losh return (ddr_br_read(i) & 0xff000000); 98859c993d1SWarner Losh } 98959c993d1SWarner Losh 99059c993d1SWarner Losh uint32_t 99159c993d1SWarner Losh ddr_size(int i) 99259c993d1SWarner Losh { 99359c993d1SWarner Losh 99459c993d1SWarner Losh return ((ddr_sz_read(i) | 0x00ffffff) + 1); 99559c993d1SWarner Losh } 99659c993d1SWarner Losh 99759c993d1SWarner Losh uint32_t 99859c993d1SWarner Losh ddr_attr(int i) 99959c993d1SWarner Losh { 100059c993d1SWarner Losh uint32_t dev, rev; 100159c993d1SWarner Losh 100259c993d1SWarner Losh soc_id(&dev, &rev); 100359c993d1SWarner Losh if (dev == MV_DEV_88RC8180) 100459c993d1SWarner Losh return ((ddr_sz_read(i) & 0xf0) >> 4); 100559c993d1SWarner Losh if (dev == MV_DEV_88F6781) 100659c993d1SWarner Losh return (0); 100759c993d1SWarner Losh 100859c993d1SWarner Losh return (i == 0 ? 0xe : 100959c993d1SWarner Losh (i == 1 ? 0xd : 101059c993d1SWarner Losh (i == 2 ? 0xb : 101159c993d1SWarner Losh (i == 3 ? 0x7 : 0xff)))); 101259c993d1SWarner Losh } 101359c993d1SWarner Losh 101459c993d1SWarner Losh uint32_t 101559c993d1SWarner Losh ddr_target(int i) 101659c993d1SWarner Losh { 101759c993d1SWarner Losh uint32_t dev, rev; 101859c993d1SWarner Losh 101959c993d1SWarner Losh soc_id(&dev, &rev); 102059c993d1SWarner Losh if (dev == MV_DEV_88RC8180) { 102159c993d1SWarner Losh i = (ddr_sz_read(i) & 0xf0) >> 4; 102259c993d1SWarner Losh return (i == 0xe ? 0xc : 102359c993d1SWarner Losh (i == 0xd ? 0xd : 102459c993d1SWarner Losh (i == 0xb ? 0xe : 102559c993d1SWarner Losh (i == 0x7 ? 0xf : 0xc)))); 102659c993d1SWarner Losh } 102759c993d1SWarner Losh 102859c993d1SWarner Losh /* 102959c993d1SWarner Losh * On SOCs other than 88RC8180 Mbus unit ID for 103059c993d1SWarner Losh * DDR SDRAM controller is always 0x0. 103159c993d1SWarner Losh */ 103259c993d1SWarner Losh return (0); 103359c993d1SWarner Losh } 103459c993d1SWarner Losh 103559c993d1SWarner Losh /************************************************************************** 103659c993d1SWarner Losh * USB windows routines 103759c993d1SWarner Losh **************************************************************************/ 103859c993d1SWarner Losh static int 103959c993d1SWarner Losh decode_win_usb_valid(void) 104059c993d1SWarner Losh { 104159c993d1SWarner Losh 104259c993d1SWarner Losh return (decode_win_can_cover_ddr(MV_WIN_USB_MAX)); 104359c993d1SWarner Losh } 104459c993d1SWarner Losh 104559c993d1SWarner Losh static void 104659c993d1SWarner Losh decode_win_usb_dump(u_long base) 104759c993d1SWarner Losh { 104859c993d1SWarner Losh int i; 104959c993d1SWarner Losh 105059c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_USB(usb_port - 1))) 105159c993d1SWarner Losh return; 105259c993d1SWarner Losh 105359c993d1SWarner Losh for (i = 0; i < MV_WIN_USB_MAX; i++) 105459c993d1SWarner Losh printf("USB window#%d: c 0x%08x, b 0x%08x\n", i, 105559c993d1SWarner Losh win_usb_cr_read(base, i), win_usb_br_read(base, i)); 105659c993d1SWarner Losh } 105759c993d1SWarner Losh 105859c993d1SWarner Losh /* 105959c993d1SWarner Losh * Set USB decode windows. 106059c993d1SWarner Losh */ 106159c993d1SWarner Losh static void 106259c993d1SWarner Losh decode_win_usb_setup(u_long base) 106359c993d1SWarner Losh { 106459c993d1SWarner Losh uint32_t br, cr; 106559c993d1SWarner Losh int i, j; 106659c993d1SWarner Losh 106759c993d1SWarner Losh 106859c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_USB(usb_port))) 106959c993d1SWarner Losh return; 107059c993d1SWarner Losh 107159c993d1SWarner Losh usb_port++; 107259c993d1SWarner Losh 107359c993d1SWarner Losh for (i = 0; i < MV_WIN_USB_MAX; i++) { 107459c993d1SWarner Losh win_usb_cr_write(base, i, 0); 107559c993d1SWarner Losh win_usb_br_write(base, i, 0); 107659c993d1SWarner Losh } 107759c993d1SWarner Losh 107859c993d1SWarner Losh /* Only access to active DRAM banks is required */ 107959c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) { 108059c993d1SWarner Losh if (ddr_is_active(i)) { 108159c993d1SWarner Losh br = ddr_base(i); 108259c993d1SWarner Losh /* 108359c993d1SWarner Losh * XXX for 6281 we should handle Mbus write 108459c993d1SWarner Losh * burst limit field in the ctrl reg 108559c993d1SWarner Losh */ 108659c993d1SWarner Losh cr = (((ddr_size(i) - 1) & 0xffff0000) | 108759c993d1SWarner Losh (ddr_attr(i) << 8) | 108859c993d1SWarner Losh (ddr_target(i) << 4) | 1); 108959c993d1SWarner Losh 109059c993d1SWarner Losh /* Set the first free USB window */ 109159c993d1SWarner Losh for (j = 0; j < MV_WIN_USB_MAX; j++) { 109259c993d1SWarner Losh if (win_usb_cr_read(base, j) & 0x1) 109359c993d1SWarner Losh continue; 109459c993d1SWarner Losh 109559c993d1SWarner Losh win_usb_br_write(base, j, br); 109659c993d1SWarner Losh win_usb_cr_write(base, j, cr); 109759c993d1SWarner Losh break; 109859c993d1SWarner Losh } 109959c993d1SWarner Losh } 110059c993d1SWarner Losh } 110159c993d1SWarner Losh } 110259c993d1SWarner Losh 110359c993d1SWarner Losh /************************************************************************** 110459c993d1SWarner Losh * ETH windows routines 110559c993d1SWarner Losh **************************************************************************/ 110659c993d1SWarner Losh 110759c993d1SWarner Losh static int 110859c993d1SWarner Losh win_eth_can_remap(int i) 110959c993d1SWarner Losh { 111059c993d1SWarner Losh 111159c993d1SWarner Losh /* ETH encode windows 0-3 have remap capability */ 111259c993d1SWarner Losh if (i < 4) 111359c993d1SWarner Losh return (1); 111459c993d1SWarner Losh 111559c993d1SWarner Losh return (0); 111659c993d1SWarner Losh } 111759c993d1SWarner Losh 111859c993d1SWarner Losh static int 111959c993d1SWarner Losh eth_bare_read(uint32_t base, int i) 112059c993d1SWarner Losh { 112159c993d1SWarner Losh uint32_t v; 112259c993d1SWarner Losh 112359c993d1SWarner Losh v = win_eth_bare_read(base); 112459c993d1SWarner Losh v &= (1 << i); 112559c993d1SWarner Losh 112659c993d1SWarner Losh return (v >> i); 112759c993d1SWarner Losh } 112859c993d1SWarner Losh 112959c993d1SWarner Losh static void 113059c993d1SWarner Losh eth_bare_write(uint32_t base, int i, int val) 113159c993d1SWarner Losh { 113259c993d1SWarner Losh uint32_t v; 113359c993d1SWarner Losh 113459c993d1SWarner Losh v = win_eth_bare_read(base); 113559c993d1SWarner Losh v &= ~(1 << i); 113659c993d1SWarner Losh v |= (val << i); 113759c993d1SWarner Losh win_eth_bare_write(base, v); 113859c993d1SWarner Losh } 113959c993d1SWarner Losh 114059c993d1SWarner Losh static void 114159c993d1SWarner Losh eth_epap_write(uint32_t base, int i, int val) 114259c993d1SWarner Losh { 114359c993d1SWarner Losh uint32_t v; 114459c993d1SWarner Losh 114559c993d1SWarner Losh v = win_eth_epap_read(base); 114659c993d1SWarner Losh v &= ~(0x3 << (i * 2)); 114759c993d1SWarner Losh v |= (val << (i * 2)); 114859c993d1SWarner Losh win_eth_epap_write(base, v); 114959c993d1SWarner Losh } 115059c993d1SWarner Losh 115159c993d1SWarner Losh static void 115259c993d1SWarner Losh decode_win_eth_dump(u_long base) 115359c993d1SWarner Losh { 115459c993d1SWarner Losh int i; 115559c993d1SWarner Losh 115659c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_GE(eth_port - 1))) 115759c993d1SWarner Losh return; 115859c993d1SWarner Losh 115959c993d1SWarner Losh for (i = 0; i < MV_WIN_ETH_MAX; i++) { 116059c993d1SWarner Losh printf("ETH window#%d: b 0x%08x, s 0x%08x", i, 116159c993d1SWarner Losh win_eth_br_read(base, i), 116259c993d1SWarner Losh win_eth_sz_read(base, i)); 116359c993d1SWarner Losh 116459c993d1SWarner Losh if (win_eth_can_remap(i)) 116559c993d1SWarner Losh printf(", ha 0x%08x", 116659c993d1SWarner Losh win_eth_har_read(base, i)); 116759c993d1SWarner Losh 116859c993d1SWarner Losh printf("\n"); 116959c993d1SWarner Losh } 117059c993d1SWarner Losh printf("ETH windows: bare 0x%08x, epap 0x%08x\n", 117159c993d1SWarner Losh win_eth_bare_read(base), 117259c993d1SWarner Losh win_eth_epap_read(base)); 117359c993d1SWarner Losh } 117459c993d1SWarner Losh 117559c993d1SWarner Losh #if defined(SOC_MV_LOKIPLUS) 117659c993d1SWarner Losh #define MV_WIN_ETH_DDR_TRGT(n) 0 117759c993d1SWarner Losh #else 117859c993d1SWarner Losh #define MV_WIN_ETH_DDR_TRGT(n) ddr_target(n) 117959c993d1SWarner Losh #endif 118059c993d1SWarner Losh 118159c993d1SWarner Losh static void 118259c993d1SWarner Losh decode_win_eth_setup(u_long base) 118359c993d1SWarner Losh { 118459c993d1SWarner Losh uint32_t br, sz; 118559c993d1SWarner Losh int i, j; 118659c993d1SWarner Losh 118759c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_GE(eth_port))) 118859c993d1SWarner Losh return; 118959c993d1SWarner Losh 119059c993d1SWarner Losh eth_port++; 119159c993d1SWarner Losh 119259c993d1SWarner Losh /* Disable, clear and revoke protection for all ETH windows */ 119359c993d1SWarner Losh for (i = 0; i < MV_WIN_ETH_MAX; i++) { 119459c993d1SWarner Losh 119559c993d1SWarner Losh eth_bare_write(base, i, 1); 119659c993d1SWarner Losh eth_epap_write(base, i, 0); 119759c993d1SWarner Losh win_eth_br_write(base, i, 0); 119859c993d1SWarner Losh win_eth_sz_write(base, i, 0); 119959c993d1SWarner Losh if (win_eth_can_remap(i)) 120059c993d1SWarner Losh win_eth_har_write(base, i, 0); 120159c993d1SWarner Losh } 120259c993d1SWarner Losh 120359c993d1SWarner Losh /* Only access to active DRAM banks is required */ 120459c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) 120559c993d1SWarner Losh if (ddr_is_active(i)) { 120659c993d1SWarner Losh 120759c993d1SWarner Losh br = ddr_base(i) | (ddr_attr(i) << 8) | MV_WIN_ETH_DDR_TRGT(i); 120859c993d1SWarner Losh sz = ((ddr_size(i) - 1) & 0xffff0000); 120959c993d1SWarner Losh 121059c993d1SWarner Losh /* Set the first free ETH window */ 121159c993d1SWarner Losh for (j = 0; j < MV_WIN_ETH_MAX; j++) { 121259c993d1SWarner Losh if (eth_bare_read(base, j) == 0) 121359c993d1SWarner Losh continue; 121459c993d1SWarner Losh 121559c993d1SWarner Losh win_eth_br_write(base, j, br); 121659c993d1SWarner Losh win_eth_sz_write(base, j, sz); 121759c993d1SWarner Losh 121859c993d1SWarner Losh /* XXX remapping ETH windows not supported */ 121959c993d1SWarner Losh 122059c993d1SWarner Losh /* Set protection RW */ 122159c993d1SWarner Losh eth_epap_write(base, j, 0x3); 122259c993d1SWarner Losh 122359c993d1SWarner Losh /* Enable window */ 122459c993d1SWarner Losh eth_bare_write(base, j, 0); 122559c993d1SWarner Losh break; 122659c993d1SWarner Losh } 122759c993d1SWarner Losh } 122859c993d1SWarner Losh } 122959c993d1SWarner Losh 123059c993d1SWarner Losh static int 123159c993d1SWarner Losh decode_win_eth_valid(void) 123259c993d1SWarner Losh { 123359c993d1SWarner Losh 123459c993d1SWarner Losh return (decode_win_can_cover_ddr(MV_WIN_ETH_MAX)); 123559c993d1SWarner Losh } 123659c993d1SWarner Losh 123759c993d1SWarner Losh /************************************************************************** 123859c993d1SWarner Losh * PCIE windows routines 123959c993d1SWarner Losh **************************************************************************/ 124059c993d1SWarner Losh 124159c993d1SWarner Losh void 124259c993d1SWarner Losh decode_win_pcie_setup(u_long base) 124359c993d1SWarner Losh { 124459c993d1SWarner Losh uint32_t size = 0, ddrbase = ~0; 124559c993d1SWarner Losh uint32_t cr, br; 124659c993d1SWarner Losh int i, j; 124759c993d1SWarner Losh 124859c993d1SWarner Losh for (i = 0; i < MV_PCIE_BAR_MAX; i++) { 124959c993d1SWarner Losh pcie_bar_br_write(base, i, 125059c993d1SWarner Losh MV_PCIE_BAR_64BIT | MV_PCIE_BAR_PREFETCH_EN); 125159c993d1SWarner Losh if (i < 3) 125259c993d1SWarner Losh pcie_bar_brh_write(base, i, 0); 125359c993d1SWarner Losh if (i > 0) 125459c993d1SWarner Losh pcie_bar_cr_write(base, i, 0); 125559c993d1SWarner Losh } 125659c993d1SWarner Losh 125759c993d1SWarner Losh for (i = 0; i < MV_WIN_PCIE_MAX; i++) { 125859c993d1SWarner Losh win_pcie_cr_write(base, i, 0); 125959c993d1SWarner Losh win_pcie_br_write(base, i, 0); 126059c993d1SWarner Losh win_pcie_remap_write(base, i, 0); 126159c993d1SWarner Losh } 126259c993d1SWarner Losh 126359c993d1SWarner Losh /* On End-Point only set BAR size to 1MB regardless of DDR size */ 126459c993d1SWarner Losh if ((bus_space_read_4(fdtbus_bs_tag, base, MV_PCIE_CONTROL) 126559c993d1SWarner Losh & MV_PCIE_ROOT_CMPLX) == 0) { 126659c993d1SWarner Losh pcie_bar_cr_write(base, 1, 0xf0000 | 1); 126759c993d1SWarner Losh return; 126859c993d1SWarner Losh } 126959c993d1SWarner Losh 127059c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) { 127159c993d1SWarner Losh if (ddr_is_active(i)) { 127259c993d1SWarner Losh /* Map DDR to BAR 1 */ 127359c993d1SWarner Losh cr = (ddr_size(i) - 1) & 0xffff0000; 127459c993d1SWarner Losh size += ddr_size(i) & 0xffff0000; 127559c993d1SWarner Losh cr |= (ddr_attr(i) << 8) | (ddr_target(i) << 4) | 1; 127659c993d1SWarner Losh br = ddr_base(i); 127759c993d1SWarner Losh if (br < ddrbase) 127859c993d1SWarner Losh ddrbase = br; 127959c993d1SWarner Losh 128059c993d1SWarner Losh /* Use the first available PCIE window */ 128159c993d1SWarner Losh for (j = 0; j < MV_WIN_PCIE_MAX; j++) { 128259c993d1SWarner Losh if (win_pcie_cr_read(base, j) != 0) 128359c993d1SWarner Losh continue; 128459c993d1SWarner Losh 128559c993d1SWarner Losh win_pcie_br_write(base, j, br); 128659c993d1SWarner Losh win_pcie_cr_write(base, j, cr); 128759c993d1SWarner Losh break; 128859c993d1SWarner Losh } 128959c993d1SWarner Losh } 129059c993d1SWarner Losh } 129159c993d1SWarner Losh 129259c993d1SWarner Losh /* 129359c993d1SWarner Losh * Upper 16 bits in BAR register is interpreted as BAR size 129459c993d1SWarner Losh * (in 64 kB units) plus 64kB, so substract 0x10000 129559c993d1SWarner Losh * form value passed to register to get correct value. 129659c993d1SWarner Losh */ 129759c993d1SWarner Losh size -= 0x10000; 129859c993d1SWarner Losh pcie_bar_cr_write(base, 1, size | 1); 129959c993d1SWarner Losh pcie_bar_br_write(base, 1, ddrbase | 130059c993d1SWarner Losh MV_PCIE_BAR_64BIT | MV_PCIE_BAR_PREFETCH_EN); 130159c993d1SWarner Losh pcie_bar_br_write(base, 0, fdt_immr_pa | 130259c993d1SWarner Losh MV_PCIE_BAR_64BIT | MV_PCIE_BAR_PREFETCH_EN); 130359c993d1SWarner Losh } 130459c993d1SWarner Losh 130559c993d1SWarner Losh static int 130659c993d1SWarner Losh decode_win_pcie_valid(void) 130759c993d1SWarner Losh { 130859c993d1SWarner Losh 130959c993d1SWarner Losh return (decode_win_can_cover_ddr(MV_WIN_PCIE_MAX)); 131059c993d1SWarner Losh } 131159c993d1SWarner Losh 131259c993d1SWarner Losh /************************************************************************** 131359c993d1SWarner Losh * IDMA windows routines 131459c993d1SWarner Losh **************************************************************************/ 131559c993d1SWarner Losh #if defined(SOC_MV_ORION) || defined(SOC_MV_DISCOVERY) 131659c993d1SWarner Losh static int 131759c993d1SWarner Losh idma_bare_read(u_long base, int i) 131859c993d1SWarner Losh { 131959c993d1SWarner Losh uint32_t v; 132059c993d1SWarner Losh 132159c993d1SWarner Losh v = win_idma_bare_read(base); 132259c993d1SWarner Losh v &= (1 << i); 132359c993d1SWarner Losh 132459c993d1SWarner Losh return (v >> i); 132559c993d1SWarner Losh } 132659c993d1SWarner Losh 132759c993d1SWarner Losh static void 132859c993d1SWarner Losh idma_bare_write(u_long base, int i, int val) 132959c993d1SWarner Losh { 133059c993d1SWarner Losh uint32_t v; 133159c993d1SWarner Losh 133259c993d1SWarner Losh v = win_idma_bare_read(base); 133359c993d1SWarner Losh v &= ~(1 << i); 133459c993d1SWarner Losh v |= (val << i); 133559c993d1SWarner Losh win_idma_bare_write(base, v); 133659c993d1SWarner Losh } 133759c993d1SWarner Losh 133859c993d1SWarner Losh /* 133959c993d1SWarner Losh * Sets channel protection 'val' for window 'w' on channel 'c' 134059c993d1SWarner Losh */ 134159c993d1SWarner Losh static void 134259c993d1SWarner Losh idma_cap_write(u_long base, int c, int w, int val) 134359c993d1SWarner Losh { 134459c993d1SWarner Losh uint32_t v; 134559c993d1SWarner Losh 134659c993d1SWarner Losh v = win_idma_cap_read(base, c); 134759c993d1SWarner Losh v &= ~(0x3 << (w * 2)); 134859c993d1SWarner Losh v |= (val << (w * 2)); 134959c993d1SWarner Losh win_idma_cap_write(base, c, v); 135059c993d1SWarner Losh } 135159c993d1SWarner Losh 135259c993d1SWarner Losh /* 135359c993d1SWarner Losh * Set protection 'val' on all channels for window 'w' 135459c993d1SWarner Losh */ 135559c993d1SWarner Losh static void 135659c993d1SWarner Losh idma_set_prot(u_long base, int w, int val) 135759c993d1SWarner Losh { 135859c993d1SWarner Losh int c; 135959c993d1SWarner Losh 136059c993d1SWarner Losh for (c = 0; c < MV_IDMA_CHAN_MAX; c++) 136159c993d1SWarner Losh idma_cap_write(base, c, w, val); 136259c993d1SWarner Losh } 136359c993d1SWarner Losh 136459c993d1SWarner Losh static int 136559c993d1SWarner Losh win_idma_can_remap(int i) 136659c993d1SWarner Losh { 136759c993d1SWarner Losh 136859c993d1SWarner Losh /* IDMA decode windows 0-3 have remap capability */ 136959c993d1SWarner Losh if (i < 4) 137059c993d1SWarner Losh return (1); 137159c993d1SWarner Losh 137259c993d1SWarner Losh return (0); 137359c993d1SWarner Losh } 137459c993d1SWarner Losh 137559c993d1SWarner Losh void 137659c993d1SWarner Losh decode_win_idma_setup(u_long base) 137759c993d1SWarner Losh { 137859c993d1SWarner Losh uint32_t br, sz; 137959c993d1SWarner Losh int i, j; 138059c993d1SWarner Losh 138159c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_IDMA)) 138259c993d1SWarner Losh return; 138359c993d1SWarner Losh /* 138459c993d1SWarner Losh * Disable and clear all IDMA windows, revoke protection for all channels 138559c993d1SWarner Losh */ 138659c993d1SWarner Losh for (i = 0; i < MV_WIN_IDMA_MAX; i++) { 138759c993d1SWarner Losh 138859c993d1SWarner Losh idma_bare_write(base, i, 1); 138959c993d1SWarner Losh win_idma_br_write(base, i, 0); 139059c993d1SWarner Losh win_idma_sz_write(base, i, 0); 139159c993d1SWarner Losh if (win_idma_can_remap(i) == 1) 139259c993d1SWarner Losh win_idma_har_write(base, i, 0); 139359c993d1SWarner Losh } 139459c993d1SWarner Losh for (i = 0; i < MV_IDMA_CHAN_MAX; i++) 139559c993d1SWarner Losh win_idma_cap_write(base, i, 0); 139659c993d1SWarner Losh 139759c993d1SWarner Losh /* 139859c993d1SWarner Losh * Set up access to all active DRAM banks 139959c993d1SWarner Losh */ 140059c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) 140159c993d1SWarner Losh if (ddr_is_active(i)) { 140259c993d1SWarner Losh br = ddr_base(i) | (ddr_attr(i) << 8) | ddr_target(i); 140359c993d1SWarner Losh sz = ((ddr_size(i) - 1) & 0xffff0000); 140459c993d1SWarner Losh 140559c993d1SWarner Losh /* Place DDR entries in non-remapped windows */ 140659c993d1SWarner Losh for (j = 0; j < MV_WIN_IDMA_MAX; j++) 140759c993d1SWarner Losh if (win_idma_can_remap(j) != 1 && 140859c993d1SWarner Losh idma_bare_read(base, j) == 1) { 140959c993d1SWarner Losh 141059c993d1SWarner Losh /* Configure window */ 141159c993d1SWarner Losh win_idma_br_write(base, j, br); 141259c993d1SWarner Losh win_idma_sz_write(base, j, sz); 141359c993d1SWarner Losh 141459c993d1SWarner Losh /* Set protection RW on all channels */ 141559c993d1SWarner Losh idma_set_prot(base, j, 0x3); 141659c993d1SWarner Losh 141759c993d1SWarner Losh /* Enable window */ 141859c993d1SWarner Losh idma_bare_write(base, j, 0); 141959c993d1SWarner Losh break; 142059c993d1SWarner Losh } 142159c993d1SWarner Losh } 142259c993d1SWarner Losh 142359c993d1SWarner Losh /* 142459c993d1SWarner Losh * Remaining targets -- from statically defined table 142559c993d1SWarner Losh */ 142659c993d1SWarner Losh for (i = 0; i < idma_wins_no; i++) 142759c993d1SWarner Losh if (idma_wins[i].target > 0) { 142859c993d1SWarner Losh br = (idma_wins[i].base & 0xffff0000) | 142959c993d1SWarner Losh (idma_wins[i].attr << 8) | idma_wins[i].target; 143059c993d1SWarner Losh sz = ((idma_wins[i].size - 1) & 0xffff0000); 143159c993d1SWarner Losh 143259c993d1SWarner Losh /* Set the first free IDMA window */ 143359c993d1SWarner Losh for (j = 0; j < MV_WIN_IDMA_MAX; j++) { 143459c993d1SWarner Losh if (idma_bare_read(base, j) == 0) 143559c993d1SWarner Losh continue; 143659c993d1SWarner Losh 143759c993d1SWarner Losh /* Configure window */ 143859c993d1SWarner Losh win_idma_br_write(base, j, br); 143959c993d1SWarner Losh win_idma_sz_write(base, j, sz); 144059c993d1SWarner Losh if (win_idma_can_remap(j) && 144159c993d1SWarner Losh idma_wins[j].remap >= 0) 144259c993d1SWarner Losh win_idma_har_write(base, j, 144359c993d1SWarner Losh idma_wins[j].remap); 144459c993d1SWarner Losh 144559c993d1SWarner Losh /* Set protection RW on all channels */ 144659c993d1SWarner Losh idma_set_prot(base, j, 0x3); 144759c993d1SWarner Losh 144859c993d1SWarner Losh /* Enable window */ 144959c993d1SWarner Losh idma_bare_write(base, j, 0); 145059c993d1SWarner Losh break; 145159c993d1SWarner Losh } 145259c993d1SWarner Losh } 145359c993d1SWarner Losh } 145459c993d1SWarner Losh 145559c993d1SWarner Losh int 145659c993d1SWarner Losh decode_win_idma_valid(void) 145759c993d1SWarner Losh { 145859c993d1SWarner Losh const struct decode_win *wintab; 145959c993d1SWarner Losh int c, i, j, rv; 146059c993d1SWarner Losh uint32_t b, e, s; 146159c993d1SWarner Losh 146259c993d1SWarner Losh if (idma_wins_no > MV_WIN_IDMA_MAX) { 146359c993d1SWarner Losh printf("IDMA windows: too many entries: %d\n", idma_wins_no); 146459c993d1SWarner Losh return (0); 146559c993d1SWarner Losh } 146659c993d1SWarner Losh for (i = 0, c = 0; i < MV_WIN_DDR_MAX; i++) 146759c993d1SWarner Losh if (ddr_is_active(i)) 146859c993d1SWarner Losh c++; 146959c993d1SWarner Losh 147059c993d1SWarner Losh if (idma_wins_no > (MV_WIN_IDMA_MAX - c)) { 147159c993d1SWarner Losh printf("IDMA windows: too many entries: %d, available: %d\n", 147259c993d1SWarner Losh idma_wins_no, MV_WIN_IDMA_MAX - c); 147359c993d1SWarner Losh return (0); 147459c993d1SWarner Losh } 147559c993d1SWarner Losh 147659c993d1SWarner Losh wintab = idma_wins; 147759c993d1SWarner Losh rv = 1; 147859c993d1SWarner Losh for (i = 0; i < idma_wins_no; i++, wintab++) { 147959c993d1SWarner Losh 148059c993d1SWarner Losh if (wintab->target == 0) { 148159c993d1SWarner Losh printf("IDMA window#%d: DDR target window is not " 148259c993d1SWarner Losh "supposed to be reprogrammed!\n", i); 148359c993d1SWarner Losh rv = 0; 148459c993d1SWarner Losh } 148559c993d1SWarner Losh 148659c993d1SWarner Losh if (wintab->remap >= 0 && win_cpu_can_remap(i) != 1) { 148759c993d1SWarner Losh printf("IDMA window#%d: not capable of remapping, but " 148859c993d1SWarner Losh "val 0x%08x defined\n", i, wintab->remap); 148959c993d1SWarner Losh rv = 0; 149059c993d1SWarner Losh } 149159c993d1SWarner Losh 149259c993d1SWarner Losh s = wintab->size; 149359c993d1SWarner Losh b = wintab->base; 149459c993d1SWarner Losh e = b + s - 1; 149559c993d1SWarner Losh if (s > (0xFFFFFFFF - b + 1)) { 149659c993d1SWarner Losh /* XXX this boundary check should account for 64bit and 149759c993d1SWarner Losh * remapping.. */ 149859c993d1SWarner Losh printf("IDMA window#%d: no space for size 0x%08x at " 149959c993d1SWarner Losh "0x%08x\n", i, s, b); 150059c993d1SWarner Losh rv = 0; 150159c993d1SWarner Losh continue; 150259c993d1SWarner Losh } 150359c993d1SWarner Losh 150459c993d1SWarner Losh j = decode_win_overlap(i, idma_wins_no, &idma_wins[0]); 150559c993d1SWarner Losh if (j >= 0) { 150659c993d1SWarner Losh printf("IDMA window#%d: (0x%08x - 0x%08x) overlaps " 150759c993d1SWarner Losh "with #%d (0x%08x - 0x%08x)\n", i, b, e, j, 150859c993d1SWarner Losh idma_wins[j].base, 150959c993d1SWarner Losh idma_wins[j].base + idma_wins[j].size - 1); 151059c993d1SWarner Losh rv = 0; 151159c993d1SWarner Losh } 151259c993d1SWarner Losh } 151359c993d1SWarner Losh 151459c993d1SWarner Losh return (rv); 151559c993d1SWarner Losh } 151659c993d1SWarner Losh 151759c993d1SWarner Losh void 151859c993d1SWarner Losh decode_win_idma_dump(u_long base) 151959c993d1SWarner Losh { 152059c993d1SWarner Losh int i; 152159c993d1SWarner Losh 152259c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_IDMA)) 152359c993d1SWarner Losh return; 152459c993d1SWarner Losh 152559c993d1SWarner Losh for (i = 0; i < MV_WIN_IDMA_MAX; i++) { 152659c993d1SWarner Losh printf("IDMA window#%d: b 0x%08x, s 0x%08x", i, 152759c993d1SWarner Losh win_idma_br_read(base, i), win_idma_sz_read(base, i)); 152859c993d1SWarner Losh 152959c993d1SWarner Losh if (win_idma_can_remap(i)) 153059c993d1SWarner Losh printf(", ha 0x%08x", win_idma_har_read(base, i)); 153159c993d1SWarner Losh 153259c993d1SWarner Losh printf("\n"); 153359c993d1SWarner Losh } 153459c993d1SWarner Losh for (i = 0; i < MV_IDMA_CHAN_MAX; i++) 153559c993d1SWarner Losh printf("IDMA channel#%d: ap 0x%08x\n", i, 153659c993d1SWarner Losh win_idma_cap_read(base, i)); 153759c993d1SWarner Losh printf("IDMA windows: bare 0x%08x\n", win_idma_bare_read(base)); 153859c993d1SWarner Losh } 153959c993d1SWarner Losh #else 154059c993d1SWarner Losh 154159c993d1SWarner Losh /* Provide dummy functions to satisfy the build for SoCs not equipped with IDMA */ 154259c993d1SWarner Losh int 154359c993d1SWarner Losh decode_win_idma_valid(void) 154459c993d1SWarner Losh { 154559c993d1SWarner Losh 154659c993d1SWarner Losh return (1); 154759c993d1SWarner Losh } 154859c993d1SWarner Losh 154959c993d1SWarner Losh void 155059c993d1SWarner Losh decode_win_idma_setup(u_long base) 155159c993d1SWarner Losh { 155259c993d1SWarner Losh } 155359c993d1SWarner Losh 155459c993d1SWarner Losh void 155559c993d1SWarner Losh decode_win_idma_dump(u_long base) 155659c993d1SWarner Losh { 155759c993d1SWarner Losh } 155859c993d1SWarner Losh #endif 155959c993d1SWarner Losh 156059c993d1SWarner Losh /************************************************************************** 156159c993d1SWarner Losh * XOR windows routines 156259c993d1SWarner Losh **************************************************************************/ 156359c993d1SWarner Losh #if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY) 156459c993d1SWarner Losh static int 156559c993d1SWarner Losh xor_ctrl_read(u_long base, int i, int c, int e) 156659c993d1SWarner Losh { 156759c993d1SWarner Losh uint32_t v; 156859c993d1SWarner Losh v = win_xor_ctrl_read(base, c, e); 156959c993d1SWarner Losh v &= (1 << i); 157059c993d1SWarner Losh 157159c993d1SWarner Losh return (v >> i); 157259c993d1SWarner Losh } 157359c993d1SWarner Losh 157459c993d1SWarner Losh static void 157559c993d1SWarner Losh xor_ctrl_write(u_long base, int i, int c, int e, int val) 157659c993d1SWarner Losh { 157759c993d1SWarner Losh uint32_t v; 157859c993d1SWarner Losh 157959c993d1SWarner Losh v = win_xor_ctrl_read(base, c, e); 158059c993d1SWarner Losh v &= ~(1 << i); 158159c993d1SWarner Losh v |= (val << i); 158259c993d1SWarner Losh win_xor_ctrl_write(base, c, e, v); 158359c993d1SWarner Losh } 158459c993d1SWarner Losh 158559c993d1SWarner Losh /* 158659c993d1SWarner Losh * Set channel protection 'val' for window 'w' on channel 'c' 158759c993d1SWarner Losh */ 158859c993d1SWarner Losh static void 158959c993d1SWarner Losh xor_chan_write(u_long base, int c, int e, int w, int val) 159059c993d1SWarner Losh { 159159c993d1SWarner Losh uint32_t v; 159259c993d1SWarner Losh 159359c993d1SWarner Losh v = win_xor_ctrl_read(base, c, e); 159459c993d1SWarner Losh v &= ~(0x3 << (w * 2 + 16)); 159559c993d1SWarner Losh v |= (val << (w * 2 + 16)); 159659c993d1SWarner Losh win_xor_ctrl_write(base, c, e, v); 159759c993d1SWarner Losh } 159859c993d1SWarner Losh 159959c993d1SWarner Losh /* 160059c993d1SWarner Losh * Set protection 'val' on all channels for window 'w' on engine 'e' 160159c993d1SWarner Losh */ 160259c993d1SWarner Losh static void 160359c993d1SWarner Losh xor_set_prot(u_long base, int w, int e, int val) 160459c993d1SWarner Losh { 160559c993d1SWarner Losh int c; 160659c993d1SWarner Losh 160759c993d1SWarner Losh for (c = 0; c < MV_XOR_CHAN_MAX; c++) 160859c993d1SWarner Losh xor_chan_write(base, c, e, w, val); 160959c993d1SWarner Losh } 161059c993d1SWarner Losh 161159c993d1SWarner Losh static int 161259c993d1SWarner Losh win_xor_can_remap(int i) 161359c993d1SWarner Losh { 161459c993d1SWarner Losh 161559c993d1SWarner Losh /* XOR decode windows 0-3 have remap capability */ 161659c993d1SWarner Losh if (i < 4) 161759c993d1SWarner Losh return (1); 161859c993d1SWarner Losh 161959c993d1SWarner Losh return (0); 162059c993d1SWarner Losh } 162159c993d1SWarner Losh 162259c993d1SWarner Losh static int 162359c993d1SWarner Losh xor_max_eng(void) 162459c993d1SWarner Losh { 162559c993d1SWarner Losh uint32_t dev, rev; 162659c993d1SWarner Losh 162759c993d1SWarner Losh soc_id(&dev, &rev); 162859c993d1SWarner Losh switch (dev) { 162959c993d1SWarner Losh case MV_DEV_88F6281: 163059c993d1SWarner Losh case MV_DEV_88F6282: 163159c993d1SWarner Losh case MV_DEV_MV78130: 163259c993d1SWarner Losh case MV_DEV_MV78160: 163359c993d1SWarner Losh case MV_DEV_MV78230: 163459c993d1SWarner Losh case MV_DEV_MV78260: 163559c993d1SWarner Losh case MV_DEV_MV78460: 163659c993d1SWarner Losh return (2); 163759c993d1SWarner Losh case MV_DEV_MV78100: 163859c993d1SWarner Losh case MV_DEV_MV78100_Z0: 163959c993d1SWarner Losh return (1); 164059c993d1SWarner Losh default: 164159c993d1SWarner Losh return (0); 164259c993d1SWarner Losh } 164359c993d1SWarner Losh } 164459c993d1SWarner Losh 164559c993d1SWarner Losh static void 164659c993d1SWarner Losh xor_active_dram(u_long base, int c, int e, int *window) 164759c993d1SWarner Losh { 164859c993d1SWarner Losh uint32_t br, sz; 164959c993d1SWarner Losh int i, m, w; 165059c993d1SWarner Losh 165159c993d1SWarner Losh /* 165259c993d1SWarner Losh * Set up access to all active DRAM banks 165359c993d1SWarner Losh */ 165459c993d1SWarner Losh m = xor_max_eng(); 165559c993d1SWarner Losh for (i = 0; i < m; i++) 165659c993d1SWarner Losh if (ddr_is_active(i)) { 165759c993d1SWarner Losh br = ddr_base(i) | (ddr_attr(i) << 8) | 165859c993d1SWarner Losh ddr_target(i); 165959c993d1SWarner Losh sz = ((ddr_size(i) - 1) & 0xffff0000); 166059c993d1SWarner Losh 166159c993d1SWarner Losh /* Place DDR entries in non-remapped windows */ 166259c993d1SWarner Losh for (w = 0; w < MV_WIN_XOR_MAX; w++) 166359c993d1SWarner Losh if (win_xor_can_remap(w) != 1 && 166459c993d1SWarner Losh (xor_ctrl_read(base, w, c, e) == 0) && 166559c993d1SWarner Losh w > *window) { 166659c993d1SWarner Losh /* Configure window */ 166759c993d1SWarner Losh win_xor_br_write(base, w, e, br); 166859c993d1SWarner Losh win_xor_sz_write(base, w, e, sz); 166959c993d1SWarner Losh 167059c993d1SWarner Losh /* Set protection RW on all channels */ 167159c993d1SWarner Losh xor_set_prot(base, w, e, 0x3); 167259c993d1SWarner Losh 167359c993d1SWarner Losh /* Enable window */ 167459c993d1SWarner Losh xor_ctrl_write(base, w, c, e, 1); 167559c993d1SWarner Losh (*window)++; 167659c993d1SWarner Losh break; 167759c993d1SWarner Losh } 167859c993d1SWarner Losh } 167959c993d1SWarner Losh } 168059c993d1SWarner Losh 168159c993d1SWarner Losh void 168259c993d1SWarner Losh decode_win_xor_setup(u_long base) 168359c993d1SWarner Losh { 168459c993d1SWarner Losh uint32_t br, sz; 168559c993d1SWarner Losh int i, j, z, e = 1, m, window; 168659c993d1SWarner Losh 168759c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_XOR)) 168859c993d1SWarner Losh return; 168959c993d1SWarner Losh 169059c993d1SWarner Losh /* 169159c993d1SWarner Losh * Disable and clear all XOR windows, revoke protection for all 169259c993d1SWarner Losh * channels 169359c993d1SWarner Losh */ 169459c993d1SWarner Losh m = xor_max_eng(); 169559c993d1SWarner Losh for (j = 0; j < m; j++, e--) { 169659c993d1SWarner Losh 169759c993d1SWarner Losh /* Number of non-remaped windows */ 169859c993d1SWarner Losh window = MV_XOR_NON_REMAP - 1; 169959c993d1SWarner Losh 170059c993d1SWarner Losh for (i = 0; i < MV_WIN_XOR_MAX; i++) { 170159c993d1SWarner Losh win_xor_br_write(base, i, e, 0); 170259c993d1SWarner Losh win_xor_sz_write(base, i, e, 0); 170359c993d1SWarner Losh } 170459c993d1SWarner Losh 170559c993d1SWarner Losh if (win_xor_can_remap(i) == 1) 170659c993d1SWarner Losh win_xor_har_write(base, i, e, 0); 170759c993d1SWarner Losh 170859c993d1SWarner Losh for (i = 0; i < MV_XOR_CHAN_MAX; i++) { 170959c993d1SWarner Losh win_xor_ctrl_write(base, i, e, 0); 171059c993d1SWarner Losh xor_active_dram(base, i, e, &window); 171159c993d1SWarner Losh } 171259c993d1SWarner Losh 171359c993d1SWarner Losh /* 171459c993d1SWarner Losh * Remaining targets -- from a statically defined table 171559c993d1SWarner Losh */ 171659c993d1SWarner Losh for (i = 0; i < xor_wins_no; i++) 171759c993d1SWarner Losh if (xor_wins[i].target > 0) { 171859c993d1SWarner Losh br = (xor_wins[i].base & 0xffff0000) | 171959c993d1SWarner Losh (xor_wins[i].attr << 8) | 172059c993d1SWarner Losh xor_wins[i].target; 172159c993d1SWarner Losh sz = ((xor_wins[i].size - 1) & 0xffff0000); 172259c993d1SWarner Losh 172359c993d1SWarner Losh /* Set the first free XOR window */ 172459c993d1SWarner Losh for (z = 0; z < MV_WIN_XOR_MAX; z++) { 172559c993d1SWarner Losh if (xor_ctrl_read(base, z, 0, e) && 172659c993d1SWarner Losh xor_ctrl_read(base, z, 1, e)) 172759c993d1SWarner Losh continue; 172859c993d1SWarner Losh 172959c993d1SWarner Losh /* Configure window */ 173059c993d1SWarner Losh win_xor_br_write(base, z, e, br); 173159c993d1SWarner Losh win_xor_sz_write(base, z, e, sz); 173259c993d1SWarner Losh if (win_xor_can_remap(z) && 173359c993d1SWarner Losh xor_wins[z].remap >= 0) 173459c993d1SWarner Losh win_xor_har_write(base, z, e, 173559c993d1SWarner Losh xor_wins[z].remap); 173659c993d1SWarner Losh 173759c993d1SWarner Losh /* Set protection RW on all channels */ 173859c993d1SWarner Losh xor_set_prot(base, z, e, 0x3); 173959c993d1SWarner Losh 174059c993d1SWarner Losh /* Enable window */ 174159c993d1SWarner Losh xor_ctrl_write(base, z, 0, e, 1); 174259c993d1SWarner Losh xor_ctrl_write(base, z, 1, e, 1); 174359c993d1SWarner Losh break; 174459c993d1SWarner Losh } 174559c993d1SWarner Losh } 174659c993d1SWarner Losh } 174759c993d1SWarner Losh } 174859c993d1SWarner Losh 174959c993d1SWarner Losh int 175059c993d1SWarner Losh decode_win_xor_valid(void) 175159c993d1SWarner Losh { 175259c993d1SWarner Losh const struct decode_win *wintab; 175359c993d1SWarner Losh int c, i, j, rv; 175459c993d1SWarner Losh uint32_t b, e, s; 175559c993d1SWarner Losh 175659c993d1SWarner Losh if (xor_wins_no > MV_WIN_XOR_MAX) { 175759c993d1SWarner Losh printf("XOR windows: too many entries: %d\n", xor_wins_no); 175859c993d1SWarner Losh return (0); 175959c993d1SWarner Losh } 176059c993d1SWarner Losh for (i = 0, c = 0; i < MV_WIN_DDR_MAX; i++) 176159c993d1SWarner Losh if (ddr_is_active(i)) 176259c993d1SWarner Losh c++; 176359c993d1SWarner Losh 176459c993d1SWarner Losh if (xor_wins_no > (MV_WIN_XOR_MAX - c)) { 176559c993d1SWarner Losh printf("XOR windows: too many entries: %d, available: %d\n", 176659c993d1SWarner Losh xor_wins_no, MV_WIN_IDMA_MAX - c); 176759c993d1SWarner Losh return (0); 176859c993d1SWarner Losh } 176959c993d1SWarner Losh 177059c993d1SWarner Losh wintab = xor_wins; 177159c993d1SWarner Losh rv = 1; 177259c993d1SWarner Losh for (i = 0; i < xor_wins_no; i++, wintab++) { 177359c993d1SWarner Losh 177459c993d1SWarner Losh if (wintab->target == 0) { 177559c993d1SWarner Losh printf("XOR window#%d: DDR target window is not " 177659c993d1SWarner Losh "supposed to be reprogrammed!\n", i); 177759c993d1SWarner Losh rv = 0; 177859c993d1SWarner Losh } 177959c993d1SWarner Losh 178059c993d1SWarner Losh if (wintab->remap >= 0 && win_cpu_can_remap(i) != 1) { 178159c993d1SWarner Losh printf("XOR window#%d: not capable of remapping, but " 178259c993d1SWarner Losh "val 0x%08x defined\n", i, wintab->remap); 178359c993d1SWarner Losh rv = 0; 178459c993d1SWarner Losh } 178559c993d1SWarner Losh 178659c993d1SWarner Losh s = wintab->size; 178759c993d1SWarner Losh b = wintab->base; 178859c993d1SWarner Losh e = b + s - 1; 178959c993d1SWarner Losh if (s > (0xFFFFFFFF - b + 1)) { 179059c993d1SWarner Losh /* 179159c993d1SWarner Losh * XXX this boundary check should account for 64bit 179259c993d1SWarner Losh * and remapping.. 179359c993d1SWarner Losh */ 179459c993d1SWarner Losh printf("XOR window#%d: no space for size 0x%08x at " 179559c993d1SWarner Losh "0x%08x\n", i, s, b); 179659c993d1SWarner Losh rv = 0; 179759c993d1SWarner Losh continue; 179859c993d1SWarner Losh } 179959c993d1SWarner Losh 180059c993d1SWarner Losh j = decode_win_overlap(i, xor_wins_no, &xor_wins[0]); 180159c993d1SWarner Losh if (j >= 0) { 180259c993d1SWarner Losh printf("XOR window#%d: (0x%08x - 0x%08x) overlaps " 180359c993d1SWarner Losh "with #%d (0x%08x - 0x%08x)\n", i, b, e, j, 180459c993d1SWarner Losh xor_wins[j].base, 180559c993d1SWarner Losh xor_wins[j].base + xor_wins[j].size - 1); 180659c993d1SWarner Losh rv = 0; 180759c993d1SWarner Losh } 180859c993d1SWarner Losh } 180959c993d1SWarner Losh 181059c993d1SWarner Losh return (rv); 181159c993d1SWarner Losh } 181259c993d1SWarner Losh 181359c993d1SWarner Losh void 181459c993d1SWarner Losh decode_win_xor_dump(u_long base) 181559c993d1SWarner Losh { 181659c993d1SWarner Losh int i, j; 181759c993d1SWarner Losh int e = 1; 181859c993d1SWarner Losh 181959c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_XOR)) 182059c993d1SWarner Losh return; 182159c993d1SWarner Losh 182259c993d1SWarner Losh for (j = 0; j < xor_max_eng(); j++, e--) { 182359c993d1SWarner Losh for (i = 0; i < MV_WIN_XOR_MAX; i++) { 182459c993d1SWarner Losh printf("XOR window#%d: b 0x%08x, s 0x%08x", i, 182559c993d1SWarner Losh win_xor_br_read(base, i, e), win_xor_sz_read(base, i, e)); 182659c993d1SWarner Losh 182759c993d1SWarner Losh if (win_xor_can_remap(i)) 182859c993d1SWarner Losh printf(", ha 0x%08x", win_xor_har_read(base, i, e)); 182959c993d1SWarner Losh 183059c993d1SWarner Losh printf("\n"); 183159c993d1SWarner Losh } 183259c993d1SWarner Losh for (i = 0; i < MV_XOR_CHAN_MAX; i++) 183359c993d1SWarner Losh printf("XOR control#%d: 0x%08x\n", i, 183459c993d1SWarner Losh win_xor_ctrl_read(base, i, e)); 183559c993d1SWarner Losh } 183659c993d1SWarner Losh } 183759c993d1SWarner Losh 183859c993d1SWarner Losh #else 183959c993d1SWarner Losh /* Provide dummy functions to satisfy the build for SoCs not equipped with XOR */ 184059c993d1SWarner Losh static int 184159c993d1SWarner Losh decode_win_xor_valid(void) 184259c993d1SWarner Losh { 184359c993d1SWarner Losh 184459c993d1SWarner Losh return (1); 184559c993d1SWarner Losh } 184659c993d1SWarner Losh 184759c993d1SWarner Losh static void 184859c993d1SWarner Losh decode_win_xor_setup(u_long base) 184959c993d1SWarner Losh { 185059c993d1SWarner Losh } 185159c993d1SWarner Losh 185259c993d1SWarner Losh static void 185359c993d1SWarner Losh decode_win_xor_dump(u_long base) 185459c993d1SWarner Losh { 185559c993d1SWarner Losh } 185659c993d1SWarner Losh #endif 185759c993d1SWarner Losh 185859c993d1SWarner Losh /************************************************************************** 185959c993d1SWarner Losh * SATA windows routines 186059c993d1SWarner Losh **************************************************************************/ 186159c993d1SWarner Losh static void 186259c993d1SWarner Losh decode_win_sata_setup(u_long base) 186359c993d1SWarner Losh { 186459c993d1SWarner Losh uint32_t cr, br; 186559c993d1SWarner Losh int i, j; 186659c993d1SWarner Losh 186759c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_SATA)) 186859c993d1SWarner Losh return; 186959c993d1SWarner Losh 187059c993d1SWarner Losh for (i = 0; i < MV_WIN_SATA_MAX; i++) { 187159c993d1SWarner Losh win_sata_cr_write(base, i, 0); 187259c993d1SWarner Losh win_sata_br_write(base, i, 0); 187359c993d1SWarner Losh } 187459c993d1SWarner Losh 187559c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) 187659c993d1SWarner Losh if (ddr_is_active(i)) { 187759c993d1SWarner Losh cr = ((ddr_size(i) - 1) & 0xffff0000) | 187859c993d1SWarner Losh (ddr_attr(i) << 8) | (ddr_target(i) << 4) | 1; 187959c993d1SWarner Losh br = ddr_base(i); 188059c993d1SWarner Losh 188159c993d1SWarner Losh /* Use the first available SATA window */ 188259c993d1SWarner Losh for (j = 0; j < MV_WIN_SATA_MAX; j++) { 188359c993d1SWarner Losh if ((win_sata_cr_read(base, j) & 1) != 0) 188459c993d1SWarner Losh continue; 188559c993d1SWarner Losh 188659c993d1SWarner Losh win_sata_br_write(base, j, br); 188759c993d1SWarner Losh win_sata_cr_write(base, j, cr); 188859c993d1SWarner Losh break; 188959c993d1SWarner Losh } 189059c993d1SWarner Losh } 189159c993d1SWarner Losh } 189259c993d1SWarner Losh 189359c993d1SWarner Losh static int 189459c993d1SWarner Losh decode_win_sata_valid(void) 189559c993d1SWarner Losh { 189659c993d1SWarner Losh uint32_t dev, rev; 189759c993d1SWarner Losh 189859c993d1SWarner Losh soc_id(&dev, &rev); 189959c993d1SWarner Losh if (dev == MV_DEV_88F5281) 190059c993d1SWarner Losh return (1); 190159c993d1SWarner Losh 190259c993d1SWarner Losh return (decode_win_can_cover_ddr(MV_WIN_SATA_MAX)); 190359c993d1SWarner Losh } 190459c993d1SWarner Losh 190559c993d1SWarner Losh /************************************************************************** 190659c993d1SWarner Losh * FDT parsing routines. 190759c993d1SWarner Losh **************************************************************************/ 190859c993d1SWarner Losh 190959c993d1SWarner Losh static int 191059c993d1SWarner Losh fdt_get_ranges(const char *nodename, void *buf, int size, int *tuples, 191159c993d1SWarner Losh int *tuplesize) 191259c993d1SWarner Losh { 191359c993d1SWarner Losh phandle_t node; 191459c993d1SWarner Losh pcell_t addr_cells, par_addr_cells, size_cells; 191559c993d1SWarner Losh int len, tuple_size, tuples_count; 191659c993d1SWarner Losh 191759c993d1SWarner Losh node = OF_finddevice(nodename); 191859c993d1SWarner Losh if (node == -1) 191959c993d1SWarner Losh return (EINVAL); 192059c993d1SWarner Losh 192159c993d1SWarner Losh if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0) 192259c993d1SWarner Losh return (ENXIO); 192359c993d1SWarner Losh 192459c993d1SWarner Losh par_addr_cells = fdt_parent_addr_cells(node); 192559c993d1SWarner Losh if (par_addr_cells > 2) 192659c993d1SWarner Losh return (ERANGE); 192759c993d1SWarner Losh 192859c993d1SWarner Losh tuple_size = sizeof(pcell_t) * (addr_cells + par_addr_cells + 192959c993d1SWarner Losh size_cells); 193059c993d1SWarner Losh 193159c993d1SWarner Losh /* Note the OF_getprop_alloc() cannot be used at this early stage. */ 193259c993d1SWarner Losh len = OF_getprop(node, "ranges", buf, size); 193359c993d1SWarner Losh 193459c993d1SWarner Losh /* 193559c993d1SWarner Losh * XXX this does not handle the empty 'ranges;' case, which is 193659c993d1SWarner Losh * legitimate and should be allowed. 193759c993d1SWarner Losh */ 193859c993d1SWarner Losh tuples_count = len / tuple_size; 193959c993d1SWarner Losh if (tuples_count <= 0) 194059c993d1SWarner Losh return (ERANGE); 194159c993d1SWarner Losh 19421f7f3314SRuslan Bukin if (par_addr_cells > 2 || addr_cells > 2 || size_cells > 2) 194359c993d1SWarner Losh return (ERANGE); 194459c993d1SWarner Losh 194559c993d1SWarner Losh *tuples = tuples_count; 194659c993d1SWarner Losh *tuplesize = tuple_size; 194759c993d1SWarner Losh return (0); 194859c993d1SWarner Losh } 194959c993d1SWarner Losh 195059c993d1SWarner Losh static int 195159c993d1SWarner Losh win_cpu_from_dt(void) 195259c993d1SWarner Losh { 195359c993d1SWarner Losh pcell_t ranges[48]; 195459c993d1SWarner Losh phandle_t node; 195559c993d1SWarner Losh int i, entry_size, err, t, tuple_size, tuples; 195659c993d1SWarner Losh u_long sram_base, sram_size; 195759c993d1SWarner Losh 195859c993d1SWarner Losh t = 0; 195959c993d1SWarner Losh /* Retrieve 'ranges' property of '/localbus' node. */ 196059c993d1SWarner Losh if ((err = fdt_get_ranges("/localbus", ranges, sizeof(ranges), 196159c993d1SWarner Losh &tuples, &tuple_size)) == 0) { 196259c993d1SWarner Losh /* 196359c993d1SWarner Losh * Fill CPU decode windows table. 196459c993d1SWarner Losh */ 196559c993d1SWarner Losh bzero((void *)&cpu_win_tbl, sizeof(cpu_win_tbl)); 196659c993d1SWarner Losh 196759c993d1SWarner Losh entry_size = tuple_size / sizeof(pcell_t); 196859c993d1SWarner Losh cpu_wins_no = tuples; 196959c993d1SWarner Losh 197059c993d1SWarner Losh for (i = 0, t = 0; t < tuples; i += entry_size, t++) { 197159c993d1SWarner Losh cpu_win_tbl[t].target = 1; 197259c993d1SWarner Losh cpu_win_tbl[t].attr = fdt32_to_cpu(ranges[i + 1]); 197359c993d1SWarner Losh cpu_win_tbl[t].base = fdt32_to_cpu(ranges[i + 2]); 197459c993d1SWarner Losh cpu_win_tbl[t].size = fdt32_to_cpu(ranges[i + 3]); 197559c993d1SWarner Losh cpu_win_tbl[t].remap = ~0; 197659c993d1SWarner Losh debugf("target = 0x%0x attr = 0x%0x base = 0x%0x " 197759c993d1SWarner Losh "size = 0x%0x remap = 0x%0x\n", 197859c993d1SWarner Losh cpu_win_tbl[t].target, 197959c993d1SWarner Losh cpu_win_tbl[t].attr, cpu_win_tbl[t].base, 198059c993d1SWarner Losh cpu_win_tbl[t].size, cpu_win_tbl[t].remap); 198159c993d1SWarner Losh } 198259c993d1SWarner Losh } 198359c993d1SWarner Losh 198459c993d1SWarner Losh /* 198559c993d1SWarner Losh * Retrieve CESA SRAM data. 198659c993d1SWarner Losh */ 198759c993d1SWarner Losh if ((node = OF_finddevice("sram")) != -1) 198859c993d1SWarner Losh if (fdt_is_compatible(node, "mrvl,cesa-sram")) 198959c993d1SWarner Losh goto moveon; 199059c993d1SWarner Losh 199159c993d1SWarner Losh if ((node = OF_finddevice("/")) == 0) 199259c993d1SWarner Losh return (ENXIO); 199359c993d1SWarner Losh 199459c993d1SWarner Losh if ((node = fdt_find_compatible(node, "mrvl,cesa-sram", 0)) == 0) 199559c993d1SWarner Losh /* SRAM block is not always present. */ 199659c993d1SWarner Losh return (0); 199759c993d1SWarner Losh moveon: 199859c993d1SWarner Losh sram_base = sram_size = 0; 199959c993d1SWarner Losh if (fdt_regsize(node, &sram_base, &sram_size) != 0) 200059c993d1SWarner Losh return (EINVAL); 200159c993d1SWarner Losh 200259c993d1SWarner Losh cpu_win_tbl[t].target = MV_WIN_CESA_TARGET; 200359c993d1SWarner Losh cpu_win_tbl[t].attr = MV_WIN_CESA_ATTR(1); 200459c993d1SWarner Losh cpu_win_tbl[t].base = sram_base; 200559c993d1SWarner Losh cpu_win_tbl[t].size = sram_size; 200659c993d1SWarner Losh cpu_win_tbl[t].remap = ~0; 200759c993d1SWarner Losh cpu_wins_no++; 200859c993d1SWarner Losh debugf("sram: base = 0x%0lx size = 0x%0lx\n", sram_base, sram_size); 200959c993d1SWarner Losh 201059c993d1SWarner Losh return (0); 201159c993d1SWarner Losh } 201259c993d1SWarner Losh 201359c993d1SWarner Losh static int 201459c993d1SWarner Losh fdt_win_setup(void) 201559c993d1SWarner Losh { 201659c993d1SWarner Losh phandle_t node, child; 201759c993d1SWarner Losh struct soc_node_spec *soc_node; 201859c993d1SWarner Losh u_long size, base; 201959c993d1SWarner Losh int err, i; 202059c993d1SWarner Losh 202159c993d1SWarner Losh node = OF_finddevice("/"); 202259c993d1SWarner Losh if (node == -1) 202359c993d1SWarner Losh panic("fdt_win_setup: no root node"); 202459c993d1SWarner Losh 202559c993d1SWarner Losh /* 202659c993d1SWarner Losh * Traverse through all children of root and simple-bus nodes. 202759c993d1SWarner Losh * For each found device retrieve decode windows data (if applicable). 202859c993d1SWarner Losh */ 202959c993d1SWarner Losh child = OF_child(node); 203059c993d1SWarner Losh while (child != 0) { 203159c993d1SWarner Losh for (i = 0; soc_nodes[i].compat != NULL; i++) { 203259c993d1SWarner Losh 203359c993d1SWarner Losh soc_node = &soc_nodes[i]; 203459c993d1SWarner Losh 203559c993d1SWarner Losh if (!fdt_is_compatible(child, soc_node->compat)) 203659c993d1SWarner Losh continue; 203759c993d1SWarner Losh 203859c993d1SWarner Losh err = fdt_regsize(child, &base, &size); 203959c993d1SWarner Losh if (err != 0) 204059c993d1SWarner Losh return (err); 204159c993d1SWarner Losh 204259c993d1SWarner Losh base = (base & 0x000fffff) | fdt_immr_va; 204359c993d1SWarner Losh if (soc_node->decode_handler != NULL) 204459c993d1SWarner Losh soc_node->decode_handler(base); 204559c993d1SWarner Losh else 204659c993d1SWarner Losh return (ENXIO); 204759c993d1SWarner Losh 204859c993d1SWarner Losh if (MV_DUMP_WIN && (soc_node->dump_handler != NULL)) 204959c993d1SWarner Losh soc_node->dump_handler(base); 205059c993d1SWarner Losh } 205159c993d1SWarner Losh 205259c993d1SWarner Losh /* 205359c993d1SWarner Losh * Once done with root-level children let's move down to 205459c993d1SWarner Losh * simple-bus and its children. 205559c993d1SWarner Losh */ 205659c993d1SWarner Losh child = OF_peer(child); 205759c993d1SWarner Losh if ((child == 0) && (node == OF_finddevice("/"))) { 205859c993d1SWarner Losh node = fdt_find_compatible(node, "simple-bus", 1); 205959c993d1SWarner Losh if (node == 0) 206059c993d1SWarner Losh return (ENXIO); 206159c993d1SWarner Losh child = OF_child(node); 206259c993d1SWarner Losh } 206359c993d1SWarner Losh } 206459c993d1SWarner Losh 206559c993d1SWarner Losh return (0); 206659c993d1SWarner Losh } 206759c993d1SWarner Losh 206859c993d1SWarner Losh static void 206959c993d1SWarner Losh fdt_fixup_busfreq(phandle_t root) 207059c993d1SWarner Losh { 207159c993d1SWarner Losh phandle_t sb; 207259c993d1SWarner Losh pcell_t freq; 207359c993d1SWarner Losh 207459c993d1SWarner Losh freq = cpu_to_fdt32(get_tclk()); 207559c993d1SWarner Losh 207659c993d1SWarner Losh /* 207759c993d1SWarner Losh * Fix bus speed in cpu node 207859c993d1SWarner Losh */ 207959c993d1SWarner Losh if ((sb = OF_finddevice("cpu")) != 0) 208059c993d1SWarner Losh if (fdt_is_compatible_strict(sb, "ARM,88VS584")) 208159c993d1SWarner Losh OF_setprop(sb, "bus-frequency", (void *)&freq, 208259c993d1SWarner Losh sizeof(freq)); 208359c993d1SWarner Losh 208459c993d1SWarner Losh /* 208559c993d1SWarner Losh * This fixup sets the simple-bus bus-frequency property. 208659c993d1SWarner Losh */ 208759c993d1SWarner Losh if ((sb = fdt_find_compatible(root, "simple-bus", 1)) != 0) 208859c993d1SWarner Losh OF_setprop(sb, "bus-frequency", (void *)&freq, sizeof(freq)); 208959c993d1SWarner Losh } 209059c993d1SWarner Losh 209159c993d1SWarner Losh static void 209259c993d1SWarner Losh fdt_fixup_ranges(phandle_t root) 209359c993d1SWarner Losh { 209459c993d1SWarner Losh phandle_t node; 209559c993d1SWarner Losh pcell_t par_addr_cells, addr_cells, size_cells; 209659c993d1SWarner Losh pcell_t ranges[3], reg[2], *rangesptr; 209759c993d1SWarner Losh int len, tuple_size, tuples_count; 209859c993d1SWarner Losh uint32_t base; 209959c993d1SWarner Losh 210059c993d1SWarner Losh /* Fix-up SoC ranges according to real fdt_immr_pa */ 210159c993d1SWarner Losh if ((node = fdt_find_compatible(root, "simple-bus", 1)) != 0) { 210259c993d1SWarner Losh if (fdt_addrsize_cells(node, &addr_cells, &size_cells) == 0 && 210359c993d1SWarner Losh (par_addr_cells = fdt_parent_addr_cells(node) <= 2)) { 210459c993d1SWarner Losh tuple_size = sizeof(pcell_t) * (par_addr_cells + 210559c993d1SWarner Losh addr_cells + size_cells); 210659c993d1SWarner Losh len = OF_getprop(node, "ranges", ranges, 210759c993d1SWarner Losh sizeof(ranges)); 210859c993d1SWarner Losh tuples_count = len / tuple_size; 210959c993d1SWarner Losh /* Unexpected settings are not supported */ 211059c993d1SWarner Losh if (tuples_count != 1) 211159c993d1SWarner Losh goto fixup_failed; 211259c993d1SWarner Losh 211359c993d1SWarner Losh rangesptr = &ranges[0]; 211459c993d1SWarner Losh rangesptr += par_addr_cells; 211559c993d1SWarner Losh base = fdt_data_get((void *)rangesptr, addr_cells); 211659c993d1SWarner Losh *rangesptr = cpu_to_fdt32(fdt_immr_pa); 211759c993d1SWarner Losh if (OF_setprop(node, "ranges", (void *)&ranges[0], 211859c993d1SWarner Losh sizeof(ranges)) < 0) 211959c993d1SWarner Losh goto fixup_failed; 212059c993d1SWarner Losh } 212159c993d1SWarner Losh } 212259c993d1SWarner Losh 212359c993d1SWarner Losh /* Fix-up PCIe reg according to real PCIe registers' PA */ 212459c993d1SWarner Losh if ((node = fdt_find_compatible(root, "mrvl,pcie", 1)) != 0) { 212559c993d1SWarner Losh if (fdt_addrsize_cells(OF_parent(node), &par_addr_cells, 212659c993d1SWarner Losh &size_cells) == 0) { 212759c993d1SWarner Losh tuple_size = sizeof(pcell_t) * (par_addr_cells + 212859c993d1SWarner Losh size_cells); 212959c993d1SWarner Losh len = OF_getprop(node, "reg", reg, sizeof(reg)); 213059c993d1SWarner Losh tuples_count = len / tuple_size; 213159c993d1SWarner Losh /* Unexpected settings are not supported */ 213259c993d1SWarner Losh if (tuples_count != 1) 213359c993d1SWarner Losh goto fixup_failed; 213459c993d1SWarner Losh 213559c993d1SWarner Losh base = fdt_data_get((void *)®[0], par_addr_cells); 213659c993d1SWarner Losh base &= ~0xFF000000; 213759c993d1SWarner Losh base |= fdt_immr_pa; 213859c993d1SWarner Losh reg[0] = cpu_to_fdt32(base); 213959c993d1SWarner Losh if (OF_setprop(node, "reg", (void *)®[0], 214059c993d1SWarner Losh sizeof(reg)) < 0) 214159c993d1SWarner Losh goto fixup_failed; 214259c993d1SWarner Losh } 214359c993d1SWarner Losh } 214459c993d1SWarner Losh /* Fix-up succeeded. May return and continue */ 214559c993d1SWarner Losh return; 214659c993d1SWarner Losh 214759c993d1SWarner Losh fixup_failed: 214859c993d1SWarner Losh while (1) { 214959c993d1SWarner Losh /* 215059c993d1SWarner Losh * In case of any error while fixing ranges just hang. 215159c993d1SWarner Losh * 1. No message can be displayed yet since console 215259c993d1SWarner Losh * is not initialized. 215359c993d1SWarner Losh * 2. Going further will cause failure on bus_space_map() 215459c993d1SWarner Losh * relying on the wrong ranges or data abort when 215559c993d1SWarner Losh * accessing PCIe registers. 215659c993d1SWarner Losh */ 215759c993d1SWarner Losh } 215859c993d1SWarner Losh } 215959c993d1SWarner Losh 216059c993d1SWarner Losh struct fdt_fixup_entry fdt_fixup_table[] = { 216159c993d1SWarner Losh { "mrvl,DB-88F6281", &fdt_fixup_busfreq }, 216259c993d1SWarner Losh { "mrvl,DB-78460", &fdt_fixup_busfreq }, 216359c993d1SWarner Losh { "mrvl,DB-78460", &fdt_fixup_ranges }, 216459c993d1SWarner Losh { NULL, NULL } 216559c993d1SWarner Losh }; 216659c993d1SWarner Losh 216759c993d1SWarner Losh static int 216859c993d1SWarner Losh fdt_pic_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig, 216959c993d1SWarner Losh int *pol) 217059c993d1SWarner Losh { 217159c993d1SWarner Losh 217259c993d1SWarner Losh if (!fdt_is_compatible(node, "mrvl,pic") && 217359c993d1SWarner Losh !fdt_is_compatible(node, "mrvl,mpic")) 217459c993d1SWarner Losh return (ENXIO); 217559c993d1SWarner Losh 217659c993d1SWarner Losh *interrupt = fdt32_to_cpu(intr[0]); 217759c993d1SWarner Losh *trig = INTR_TRIGGER_CONFORM; 217859c993d1SWarner Losh *pol = INTR_POLARITY_CONFORM; 217959c993d1SWarner Losh 218059c993d1SWarner Losh return (0); 218159c993d1SWarner Losh } 218259c993d1SWarner Losh 218359c993d1SWarner Losh fdt_pic_decode_t fdt_pic_table[] = { 218459c993d1SWarner Losh &fdt_pic_decode_ic, 218559c993d1SWarner Losh NULL 218659c993d1SWarner Losh }; 218759c993d1SWarner Losh 218859c993d1SWarner Losh uint64_t 218959c993d1SWarner Losh get_sar_value(void) 219059c993d1SWarner Losh { 219159c993d1SWarner Losh uint32_t sar_low, sar_high; 219259c993d1SWarner Losh 219359c993d1SWarner Losh #if defined(SOC_MV_ARMADAXP) 219459c993d1SWarner Losh sar_high = bus_space_read_4(fdtbus_bs_tag, MV_MISC_BASE, 219559c993d1SWarner Losh SAMPLE_AT_RESET_HI); 219659c993d1SWarner Losh sar_low = bus_space_read_4(fdtbus_bs_tag, MV_MISC_BASE, 219759c993d1SWarner Losh SAMPLE_AT_RESET_LO); 219859c993d1SWarner Losh #else 219959c993d1SWarner Losh /* 220059c993d1SWarner Losh * TODO: Add getting proper values for other SoC configurations 220159c993d1SWarner Losh */ 220259c993d1SWarner Losh sar_high = 0; 220359c993d1SWarner Losh sar_low = 0; 220459c993d1SWarner Losh #endif 220559c993d1SWarner Losh 220659c993d1SWarner Losh return (((uint64_t)sar_high << 32) | sar_low); 220759c993d1SWarner Losh } 2208