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> 4981c8a263SZbigniew Bodek #include <machine/intr.h> 5059c993d1SWarner Losh 5159c993d1SWarner Losh #include <arm/mv/mvreg.h> 5259c993d1SWarner Losh #include <arm/mv/mvvar.h> 5359c993d1SWarner Losh #include <arm/mv/mvwin.h> 5459c993d1SWarner Losh 5559c993d1SWarner Losh 5659c993d1SWarner Losh MALLOC_DEFINE(M_IDMA, "idma", "idma dma test memory"); 5759c993d1SWarner Losh 5859c993d1SWarner Losh #define IDMA_DEBUG 5959c993d1SWarner Losh #undef IDMA_DEBUG 6059c993d1SWarner Losh 6159c993d1SWarner Losh #define MAX_CPU_WIN 5 6259c993d1SWarner Losh 6359c993d1SWarner Losh #ifdef DEBUG 6459c993d1SWarner Losh #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 6559c993d1SWarner Losh printf(fmt,##args); } while (0) 6659c993d1SWarner Losh #else 6759c993d1SWarner Losh #define debugf(fmt, args...) 6859c993d1SWarner Losh #endif 6959c993d1SWarner Losh 7059c993d1SWarner Losh #ifdef DEBUG 7159c993d1SWarner Losh #define MV_DUMP_WIN 1 7259c993d1SWarner Losh #else 7359c993d1SWarner Losh #define MV_DUMP_WIN 0 7459c993d1SWarner Losh #endif 7559c993d1SWarner Losh 7659c993d1SWarner Losh static int win_eth_can_remap(int i); 7759c993d1SWarner Losh 7859c993d1SWarner Losh #ifndef SOC_MV_FREY 7959c993d1SWarner Losh static int decode_win_cpu_valid(void); 8059c993d1SWarner Losh #endif 8159c993d1SWarner Losh static int decode_win_usb_valid(void); 8234a3d2c6SWojciech Macek static int decode_win_usb3_valid(void); 8359c993d1SWarner Losh static int decode_win_eth_valid(void); 8459c993d1SWarner Losh static int decode_win_pcie_valid(void); 8559c993d1SWarner Losh static int decode_win_sata_valid(void); 8659c993d1SWarner Losh 8759c993d1SWarner Losh static int decode_win_idma_valid(void); 8859c993d1SWarner Losh static int decode_win_xor_valid(void); 8959c993d1SWarner Losh 9059c993d1SWarner Losh #ifndef SOC_MV_FREY 9159c993d1SWarner Losh static void decode_win_cpu_setup(void); 9259c993d1SWarner Losh #endif 9359c993d1SWarner Losh #ifdef SOC_MV_ARMADAXP 9459c993d1SWarner Losh static int decode_win_sdram_fixup(void); 9559c993d1SWarner Losh #endif 9659c993d1SWarner Losh static void decode_win_usb_setup(u_long); 9734a3d2c6SWojciech Macek static void decode_win_usb3_setup(u_long); 9859c993d1SWarner Losh static void decode_win_eth_setup(u_long); 9959c993d1SWarner Losh static void decode_win_sata_setup(u_long); 10059c993d1SWarner Losh 10159c993d1SWarner Losh static void decode_win_idma_setup(u_long); 10259c993d1SWarner Losh static void decode_win_xor_setup(u_long); 10359c993d1SWarner Losh 10459c993d1SWarner Losh static void decode_win_usb_dump(u_long); 10534a3d2c6SWojciech Macek static void decode_win_usb3_dump(u_long); 10659c993d1SWarner Losh static void decode_win_eth_dump(u_long base); 10759c993d1SWarner Losh static void decode_win_idma_dump(u_long base); 10859c993d1SWarner Losh static void decode_win_xor_dump(u_long base); 10959c993d1SWarner Losh 11059c993d1SWarner Losh static int fdt_get_ranges(const char *, void *, int, int *, int *); 11181c8a263SZbigniew Bodek #ifdef SOC_MV_ARMADA38X 11281c8a263SZbigniew Bodek int gic_decode_fdt(phandle_t iparent, pcell_t *intr, int *interrupt, 11381c8a263SZbigniew Bodek int *trig, int *pol); 11481c8a263SZbigniew Bodek #endif 11559c993d1SWarner Losh 11659c993d1SWarner Losh static int win_cpu_from_dt(void); 11759c993d1SWarner Losh static int fdt_win_setup(void); 11859c993d1SWarner Losh 11959c993d1SWarner Losh static uint32_t dev_mask = 0; 12059c993d1SWarner Losh static int cpu_wins_no = 0; 12159c993d1SWarner Losh static int eth_port = 0; 12259c993d1SWarner Losh static int usb_port = 0; 12359c993d1SWarner Losh 12459c993d1SWarner Losh static struct decode_win cpu_win_tbl[MAX_CPU_WIN]; 12559c993d1SWarner Losh 12659c993d1SWarner Losh const struct decode_win *cpu_wins = cpu_win_tbl; 12759c993d1SWarner Losh 12859c993d1SWarner Losh typedef void (*decode_win_setup_t)(u_long); 12959c993d1SWarner Losh typedef void (*dump_win_t)(u_long); 13059c993d1SWarner Losh 13159c993d1SWarner Losh struct soc_node_spec { 13259c993d1SWarner Losh const char *compat; 13359c993d1SWarner Losh decode_win_setup_t decode_handler; 13459c993d1SWarner Losh dump_win_t dump_handler; 13559c993d1SWarner Losh }; 13659c993d1SWarner Losh 13759c993d1SWarner Losh static struct soc_node_spec soc_nodes[] = { 13859c993d1SWarner Losh { "mrvl,ge", &decode_win_eth_setup, &decode_win_eth_dump }, 13959c993d1SWarner Losh { "mrvl,usb-ehci", &decode_win_usb_setup, &decode_win_usb_dump }, 14034a3d2c6SWojciech Macek { "marvell,armada-380-xhci", &decode_win_usb3_setup, &decode_win_usb3_dump }, 14159c993d1SWarner Losh { "mrvl,sata", &decode_win_sata_setup, NULL }, 14259c993d1SWarner Losh { "mrvl,xor", &decode_win_xor_setup, &decode_win_xor_dump }, 14359c993d1SWarner Losh { "mrvl,idma", &decode_win_idma_setup, &decode_win_idma_dump }, 14459c993d1SWarner Losh { "mrvl,pcie", &decode_win_pcie_setup, NULL }, 14559c993d1SWarner Losh { NULL, NULL, NULL }, 14659c993d1SWarner Losh }; 14759c993d1SWarner Losh 14859c993d1SWarner Losh struct fdt_pm_mask_entry fdt_pm_mask_table[] = { 14959c993d1SWarner Losh { "mrvl,ge", CPU_PM_CTRL_GE(0) }, 15059c993d1SWarner Losh { "mrvl,ge", CPU_PM_CTRL_GE(1) }, 15159c993d1SWarner Losh { "mrvl,usb-ehci", CPU_PM_CTRL_USB(0) }, 15259c993d1SWarner Losh { "mrvl,usb-ehci", CPU_PM_CTRL_USB(1) }, 15359c993d1SWarner Losh { "mrvl,usb-ehci", CPU_PM_CTRL_USB(2) }, 15459c993d1SWarner Losh { "mrvl,xor", CPU_PM_CTRL_XOR }, 15559c993d1SWarner Losh { "mrvl,sata", CPU_PM_CTRL_SATA }, 15659c993d1SWarner Losh 15759c993d1SWarner Losh { NULL, 0 } 15859c993d1SWarner Losh }; 15959c993d1SWarner Losh 16059c993d1SWarner Losh static __inline int 16159c993d1SWarner Losh pm_is_disabled(uint32_t mask) 16259c993d1SWarner Losh { 16359c993d1SWarner Losh #if defined(SOC_MV_KIRKWOOD) 16459c993d1SWarner Losh return (soc_power_ctrl_get(mask) == mask); 16559c993d1SWarner Losh #else 16659c993d1SWarner Losh return (soc_power_ctrl_get(mask) == mask ? 0 : 1); 16759c993d1SWarner Losh #endif 16859c993d1SWarner Losh } 16959c993d1SWarner Losh 17059c993d1SWarner Losh /* 17159c993d1SWarner Losh * Disable device using power management register. 17259c993d1SWarner Losh * 1 - Device Power On 17359c993d1SWarner Losh * 0 - Device Power Off 17459c993d1SWarner Losh * Mask can be set in loader. 17559c993d1SWarner Losh * EXAMPLE: 17659c993d1SWarner Losh * loader> set hw.pm-disable-mask=0x2 17759c993d1SWarner Losh * 17859c993d1SWarner Losh * Common mask: 17959c993d1SWarner Losh * |-------------------------------| 18059c993d1SWarner Losh * | Device | Kirkwood | Discovery | 18159c993d1SWarner Losh * |-------------------------------| 18259c993d1SWarner Losh * | USB0 | 0x00008 | 0x020000 | 18359c993d1SWarner Losh * |-------------------------------| 18459c993d1SWarner Losh * | USB1 | - | 0x040000 | 18559c993d1SWarner Losh * |-------------------------------| 18659c993d1SWarner Losh * | USB2 | - | 0x080000 | 18759c993d1SWarner Losh * |-------------------------------| 18859c993d1SWarner Losh * | GE0 | 0x00001 | 0x000002 | 18959c993d1SWarner Losh * |-------------------------------| 19059c993d1SWarner Losh * | GE1 | - | 0x000004 | 19159c993d1SWarner Losh * |-------------------------------| 19259c993d1SWarner Losh * | IDMA | - | 0x100000 | 19359c993d1SWarner Losh * |-------------------------------| 19459c993d1SWarner Losh * | XOR | 0x10000 | 0x200000 | 19559c993d1SWarner Losh * |-------------------------------| 19659c993d1SWarner Losh * | CESA | 0x20000 | 0x400000 | 19759c993d1SWarner Losh * |-------------------------------| 19859c993d1SWarner Losh * | SATA | 0x04000 | 0x004000 | 19959c993d1SWarner Losh * --------------------------------| 20059c993d1SWarner Losh * This feature can be used only on Kirkwood and Discovery 20159c993d1SWarner Losh * machines. 20259c993d1SWarner Losh */ 20359c993d1SWarner Losh static __inline void 20459c993d1SWarner Losh pm_disable_device(int mask) 20559c993d1SWarner Losh { 20659c993d1SWarner Losh #ifdef DIAGNOSTIC 20759c993d1SWarner Losh uint32_t reg; 20859c993d1SWarner Losh 20959c993d1SWarner Losh reg = soc_power_ctrl_get(CPU_PM_CTRL_ALL); 21059c993d1SWarner Losh printf("Power Management Register: 0%x\n", reg); 21159c993d1SWarner Losh 21259c993d1SWarner Losh reg &= ~mask; 21359c993d1SWarner Losh soc_power_ctrl_set(reg); 21459c993d1SWarner Losh printf("Device %x is disabled\n", mask); 21559c993d1SWarner Losh 21659c993d1SWarner Losh reg = soc_power_ctrl_get(CPU_PM_CTRL_ALL); 21759c993d1SWarner Losh printf("Power Management Register: 0%x\n", reg); 21859c993d1SWarner Losh #endif 21959c993d1SWarner Losh } 22059c993d1SWarner Losh 22159c993d1SWarner Losh int 22259c993d1SWarner Losh fdt_pm(phandle_t node) 22359c993d1SWarner Losh { 22459c993d1SWarner Losh uint32_t cpu_pm_ctrl; 22559c993d1SWarner Losh int i, ena, compat; 22659c993d1SWarner Losh 22759c993d1SWarner Losh ena = 1; 22859c993d1SWarner Losh cpu_pm_ctrl = read_cpu_ctrl(CPU_PM_CTRL); 22959c993d1SWarner Losh for (i = 0; fdt_pm_mask_table[i].compat != NULL; i++) { 23059c993d1SWarner Losh if (dev_mask & (1 << i)) 23159c993d1SWarner Losh continue; 23259c993d1SWarner Losh 23359c993d1SWarner Losh compat = fdt_is_compatible(node, fdt_pm_mask_table[i].compat); 23459c993d1SWarner Losh #if defined(SOC_MV_KIRKWOOD) 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 #else 24459c993d1SWarner Losh if (compat && (~cpu_pm_ctrl & fdt_pm_mask_table[i].mask)) { 24559c993d1SWarner Losh dev_mask |= (1 << i); 24659c993d1SWarner Losh ena = 0; 24759c993d1SWarner Losh break; 24859c993d1SWarner Losh } else if (compat) { 24959c993d1SWarner Losh dev_mask |= (1 << i); 25059c993d1SWarner Losh break; 25159c993d1SWarner Losh } 25259c993d1SWarner Losh #endif 25359c993d1SWarner Losh } 25459c993d1SWarner Losh 25559c993d1SWarner Losh return (ena); 25659c993d1SWarner Losh } 25759c993d1SWarner Losh 25859c993d1SWarner Losh uint32_t 25959c993d1SWarner Losh read_cpu_ctrl(uint32_t reg) 26059c993d1SWarner Losh { 26159c993d1SWarner Losh 26259c993d1SWarner Losh return (bus_space_read_4(fdtbus_bs_tag, MV_CPU_CONTROL_BASE, reg)); 26359c993d1SWarner Losh } 26459c993d1SWarner Losh 26559c993d1SWarner Losh void 26659c993d1SWarner Losh write_cpu_ctrl(uint32_t reg, uint32_t val) 26759c993d1SWarner Losh { 26859c993d1SWarner Losh 26959c993d1SWarner Losh bus_space_write_4(fdtbus_bs_tag, MV_CPU_CONTROL_BASE, reg, val); 27059c993d1SWarner Losh } 27159c993d1SWarner Losh 272f8742b0dSZbigniew Bodek #if defined(SOC_MV_ARMADAXP) || defined(SOC_MV_ARMADA38X) 27359c993d1SWarner Losh uint32_t 27459c993d1SWarner Losh read_cpu_mp_clocks(uint32_t reg) 27559c993d1SWarner Losh { 27659c993d1SWarner Losh 27759c993d1SWarner Losh return (bus_space_read_4(fdtbus_bs_tag, MV_MP_CLOCKS_BASE, reg)); 27859c993d1SWarner Losh } 27959c993d1SWarner Losh 28059c993d1SWarner Losh void 28159c993d1SWarner Losh write_cpu_mp_clocks(uint32_t reg, uint32_t val) 28259c993d1SWarner Losh { 28359c993d1SWarner Losh 28459c993d1SWarner Losh bus_space_write_4(fdtbus_bs_tag, MV_MP_CLOCKS_BASE, reg, val); 28559c993d1SWarner Losh } 28659c993d1SWarner Losh 28759c993d1SWarner Losh uint32_t 28859c993d1SWarner Losh read_cpu_misc(uint32_t reg) 28959c993d1SWarner Losh { 29059c993d1SWarner Losh 29159c993d1SWarner Losh return (bus_space_read_4(fdtbus_bs_tag, MV_MISC_BASE, reg)); 29259c993d1SWarner Losh } 29359c993d1SWarner Losh 29459c993d1SWarner Losh void 29559c993d1SWarner Losh write_cpu_misc(uint32_t reg, uint32_t val) 29659c993d1SWarner Losh { 29759c993d1SWarner Losh 29859c993d1SWarner Losh bus_space_write_4(fdtbus_bs_tag, MV_MISC_BASE, reg, val); 29959c993d1SWarner Losh } 30059c993d1SWarner Losh #endif 30159c993d1SWarner Losh 30259c993d1SWarner Losh void 30359c993d1SWarner Losh cpu_reset(void) 30459c993d1SWarner Losh { 30559c993d1SWarner Losh 306f8742b0dSZbigniew Bodek #if defined(SOC_MV_ARMADAXP) || defined (SOC_MV_ARMADA38X) 30759c993d1SWarner Losh write_cpu_misc(RSTOUTn_MASK, SOFT_RST_OUT_EN); 30859c993d1SWarner Losh write_cpu_misc(SYSTEM_SOFT_RESET, SYS_SOFT_RST); 30959c993d1SWarner Losh #else 31059c993d1SWarner Losh write_cpu_ctrl(RSTOUTn_MASK, SOFT_RST_OUT_EN); 31159c993d1SWarner Losh write_cpu_ctrl(SYSTEM_SOFT_RESET, SYS_SOFT_RST); 31259c993d1SWarner Losh #endif 31359c993d1SWarner Losh while (1); 31459c993d1SWarner Losh } 31559c993d1SWarner Losh 31659c993d1SWarner Losh uint32_t 31759c993d1SWarner Losh cpu_extra_feat(void) 31859c993d1SWarner Losh { 31959c993d1SWarner Losh uint32_t dev, rev; 32059c993d1SWarner Losh uint32_t ef = 0; 32159c993d1SWarner Losh 32259c993d1SWarner Losh soc_id(&dev, &rev); 32359c993d1SWarner Losh 32459c993d1SWarner Losh switch (dev) { 32559c993d1SWarner Losh case MV_DEV_88F6281: 32659c993d1SWarner Losh case MV_DEV_88F6282: 32759c993d1SWarner Losh case MV_DEV_88RC8180: 32859c993d1SWarner Losh case MV_DEV_MV78100_Z0: 32959c993d1SWarner Losh case MV_DEV_MV78100: 33059c993d1SWarner Losh __asm __volatile("mrc p15, 1, %0, c15, c1, 0" : "=r" (ef)); 33159c993d1SWarner Losh break; 33259c993d1SWarner Losh case MV_DEV_88F5182: 33359c993d1SWarner Losh case MV_DEV_88F5281: 33459c993d1SWarner Losh __asm __volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (ef)); 33559c993d1SWarner Losh break; 33659c993d1SWarner Losh default: 33759c993d1SWarner Losh if (bootverbose) 33859c993d1SWarner Losh printf("This ARM Core does not support any extra features\n"); 33959c993d1SWarner Losh } 34059c993d1SWarner Losh 34159c993d1SWarner Losh return (ef); 34259c993d1SWarner Losh } 34359c993d1SWarner Losh 34459c993d1SWarner Losh /* 34559c993d1SWarner Losh * Get the power status of device. This feature is only supported on 34659c993d1SWarner Losh * Kirkwood and Discovery SoCs. 34759c993d1SWarner Losh */ 34859c993d1SWarner Losh uint32_t 34959c993d1SWarner Losh soc_power_ctrl_get(uint32_t mask) 35059c993d1SWarner Losh { 35159c993d1SWarner Losh 35259c993d1SWarner Losh #if !defined(SOC_MV_ORION) && !defined(SOC_MV_LOKIPLUS) && !defined(SOC_MV_FREY) 35359c993d1SWarner Losh if (mask != CPU_PM_CTRL_NONE) 35459c993d1SWarner Losh mask &= read_cpu_ctrl(CPU_PM_CTRL); 35559c993d1SWarner Losh 35659c993d1SWarner Losh return (mask); 35759c993d1SWarner Losh #else 35859c993d1SWarner Losh return (mask); 35959c993d1SWarner Losh #endif 36059c993d1SWarner Losh } 36159c993d1SWarner Losh 36259c993d1SWarner Losh /* 36359c993d1SWarner Losh * Set the power status of device. This feature is only supported on 36459c993d1SWarner Losh * Kirkwood and Discovery SoCs. 36559c993d1SWarner Losh */ 36659c993d1SWarner Losh void 36759c993d1SWarner Losh soc_power_ctrl_set(uint32_t mask) 36859c993d1SWarner Losh { 36959c993d1SWarner Losh 37059c993d1SWarner Losh #if !defined(SOC_MV_ORION) && !defined(SOC_MV_LOKIPLUS) 37159c993d1SWarner Losh if (mask != CPU_PM_CTRL_NONE) 37259c993d1SWarner Losh write_cpu_ctrl(CPU_PM_CTRL, mask); 37359c993d1SWarner Losh #endif 37459c993d1SWarner Losh } 37559c993d1SWarner Losh 37659c993d1SWarner Losh void 37759c993d1SWarner Losh soc_id(uint32_t *dev, uint32_t *rev) 37859c993d1SWarner Losh { 37959c993d1SWarner Losh 38059c993d1SWarner Losh /* 38159c993d1SWarner Losh * Notice: system identifiers are available in the registers range of 38259c993d1SWarner Losh * PCIE controller, so using this function is only allowed (and 38359c993d1SWarner Losh * possible) after the internal registers range has been mapped in via 38430b72b68SRuslan Bukin * devmap_bootstrap(). 38559c993d1SWarner Losh */ 38659c993d1SWarner Losh *dev = bus_space_read_4(fdtbus_bs_tag, MV_PCIE_BASE, 0) >> 16; 38759c993d1SWarner Losh *rev = bus_space_read_4(fdtbus_bs_tag, MV_PCIE_BASE, 8) & 0xff; 38859c993d1SWarner Losh } 38959c993d1SWarner Losh 39059c993d1SWarner Losh static void 39159c993d1SWarner Losh soc_identify(void) 39259c993d1SWarner Losh { 39359c993d1SWarner Losh uint32_t d, r, size, mode; 39459c993d1SWarner Losh const char *dev; 39559c993d1SWarner Losh const char *rev; 39659c993d1SWarner Losh 39759c993d1SWarner Losh soc_id(&d, &r); 39859c993d1SWarner Losh 39959c993d1SWarner Losh printf("SOC: "); 40059c993d1SWarner Losh if (bootverbose) 40159c993d1SWarner Losh printf("(0x%4x:0x%02x) ", d, r); 40259c993d1SWarner Losh 40359c993d1SWarner Losh rev = ""; 40459c993d1SWarner Losh switch (d) { 40559c993d1SWarner Losh case MV_DEV_88F5181: 40659c993d1SWarner Losh dev = "Marvell 88F5181"; 40759c993d1SWarner Losh if (r == 3) 40859c993d1SWarner Losh rev = "B1"; 40959c993d1SWarner Losh break; 41059c993d1SWarner Losh case MV_DEV_88F5182: 41159c993d1SWarner Losh dev = "Marvell 88F5182"; 41259c993d1SWarner Losh if (r == 2) 41359c993d1SWarner Losh rev = "A2"; 41459c993d1SWarner Losh break; 41559c993d1SWarner Losh case MV_DEV_88F5281: 41659c993d1SWarner Losh dev = "Marvell 88F5281"; 41759c993d1SWarner Losh if (r == 4) 41859c993d1SWarner Losh rev = "D0"; 41959c993d1SWarner Losh else if (r == 5) 42059c993d1SWarner Losh rev = "D1"; 42159c993d1SWarner Losh else if (r == 6) 42259c993d1SWarner Losh rev = "D2"; 42359c993d1SWarner Losh break; 42459c993d1SWarner Losh case MV_DEV_88F6281: 42559c993d1SWarner Losh dev = "Marvell 88F6281"; 42659c993d1SWarner Losh if (r == 0) 42759c993d1SWarner Losh rev = "Z0"; 42859c993d1SWarner Losh else if (r == 2) 42959c993d1SWarner Losh rev = "A0"; 43059c993d1SWarner Losh else if (r == 3) 43159c993d1SWarner Losh rev = "A1"; 43259c993d1SWarner Losh break; 43359c993d1SWarner Losh case MV_DEV_88RC8180: 43459c993d1SWarner Losh dev = "Marvell 88RC8180"; 43559c993d1SWarner Losh break; 43659c993d1SWarner Losh case MV_DEV_88RC9480: 43759c993d1SWarner Losh dev = "Marvell 88RC9480"; 43859c993d1SWarner Losh break; 43959c993d1SWarner Losh case MV_DEV_88RC9580: 44059c993d1SWarner Losh dev = "Marvell 88RC9580"; 44159c993d1SWarner Losh break; 44259c993d1SWarner Losh case MV_DEV_88F6781: 44359c993d1SWarner Losh dev = "Marvell 88F6781"; 44459c993d1SWarner Losh if (r == 2) 44559c993d1SWarner Losh rev = "Y0"; 44659c993d1SWarner Losh break; 44759c993d1SWarner Losh case MV_DEV_88F6282: 44859c993d1SWarner Losh dev = "Marvell 88F6282"; 44959c993d1SWarner Losh if (r == 0) 45059c993d1SWarner Losh rev = "A0"; 45159c993d1SWarner Losh else if (r == 1) 45259c993d1SWarner Losh rev = "A1"; 45359c993d1SWarner Losh break; 454f8742b0dSZbigniew Bodek case MV_DEV_88F6828: 455f8742b0dSZbigniew Bodek dev = "Marvell 88F6828"; 456f8742b0dSZbigniew Bodek break; 457f8742b0dSZbigniew Bodek case MV_DEV_88F6820: 458f8742b0dSZbigniew Bodek dev = "Marvell 88F6820"; 459f8742b0dSZbigniew Bodek break; 460f8742b0dSZbigniew Bodek case MV_DEV_88F6810: 461f8742b0dSZbigniew Bodek dev = "Marvell 88F6810"; 462f8742b0dSZbigniew Bodek break; 46359c993d1SWarner Losh case MV_DEV_MV78100_Z0: 46459c993d1SWarner Losh dev = "Marvell MV78100 Z0"; 46559c993d1SWarner Losh break; 46659c993d1SWarner Losh case MV_DEV_MV78100: 46759c993d1SWarner Losh dev = "Marvell MV78100"; 46859c993d1SWarner Losh break; 46959c993d1SWarner Losh case MV_DEV_MV78160: 47059c993d1SWarner Losh dev = "Marvell MV78160"; 47159c993d1SWarner Losh break; 47259c993d1SWarner Losh case MV_DEV_MV78260: 47359c993d1SWarner Losh dev = "Marvell MV78260"; 47459c993d1SWarner Losh break; 47559c993d1SWarner Losh case MV_DEV_MV78460: 47659c993d1SWarner Losh dev = "Marvell MV78460"; 47759c993d1SWarner Losh break; 47859c993d1SWarner Losh default: 47959c993d1SWarner Losh dev = "UNKNOWN"; 48059c993d1SWarner Losh break; 48159c993d1SWarner Losh } 48259c993d1SWarner Losh 48359c993d1SWarner Losh printf("%s", dev); 48459c993d1SWarner Losh if (*rev != '\0') 48559c993d1SWarner Losh printf(" rev %s", rev); 48659c993d1SWarner Losh printf(", TClock %dMHz\n", get_tclk() / 1000 / 1000); 48759c993d1SWarner Losh 48859c993d1SWarner Losh mode = read_cpu_ctrl(CPU_CONFIG); 48959c993d1SWarner Losh printf(" Instruction cache prefetch %s, data cache prefetch %s\n", 49059c993d1SWarner Losh (mode & CPU_CONFIG_IC_PREF) ? "enabled" : "disabled", 49159c993d1SWarner Losh (mode & CPU_CONFIG_DC_PREF) ? "enabled" : "disabled"); 49259c993d1SWarner Losh 49359c993d1SWarner Losh switch (d) { 49459c993d1SWarner Losh case MV_DEV_88F6281: 49559c993d1SWarner Losh case MV_DEV_88F6282: 49659c993d1SWarner Losh mode = read_cpu_ctrl(CPU_L2_CONFIG) & CPU_L2_CONFIG_MODE; 49759c993d1SWarner Losh printf(" 256KB 4-way set-associative %s unified L2 cache\n", 49859c993d1SWarner Losh mode ? "write-through" : "write-back"); 49959c993d1SWarner Losh break; 50059c993d1SWarner Losh case MV_DEV_MV78100: 50159c993d1SWarner Losh mode = read_cpu_ctrl(CPU_CONTROL); 50259c993d1SWarner Losh size = mode & CPU_CONTROL_L2_SIZE; 50359c993d1SWarner Losh mode = mode & CPU_CONTROL_L2_MODE; 50459c993d1SWarner Losh printf(" %s set-associative %s unified L2 cache\n", 50559c993d1SWarner Losh size ? "256KB 4-way" : "512KB 8-way", 50659c993d1SWarner Losh mode ? "write-through" : "write-back"); 50759c993d1SWarner Losh break; 50859c993d1SWarner Losh default: 50959c993d1SWarner Losh break; 51059c993d1SWarner Losh } 51159c993d1SWarner Losh } 51259c993d1SWarner Losh 51359c993d1SWarner Losh static void 51459c993d1SWarner Losh platform_identify(void *dummy) 51559c993d1SWarner Losh { 51659c993d1SWarner Losh 51759c993d1SWarner Losh soc_identify(); 51859c993d1SWarner Losh 51959c993d1SWarner Losh /* 52059c993d1SWarner Losh * XXX Board identification e.g. read out from FPGA or similar should 52159c993d1SWarner Losh * go here 52259c993d1SWarner Losh */ 52359c993d1SWarner Losh } 52459c993d1SWarner Losh SYSINIT(platform_identify, SI_SUB_CPU, SI_ORDER_SECOND, platform_identify, 52559c993d1SWarner Losh NULL); 52659c993d1SWarner Losh 52759c993d1SWarner Losh #ifdef KDB 52859c993d1SWarner Losh static void 52959c993d1SWarner Losh mv_enter_debugger(void *dummy) 53059c993d1SWarner Losh { 53159c993d1SWarner Losh 53259c993d1SWarner Losh if (boothowto & RB_KDB) 53359c993d1SWarner Losh kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); 53459c993d1SWarner Losh } 53559c993d1SWarner Losh SYSINIT(mv_enter_debugger, SI_SUB_CPU, SI_ORDER_ANY, mv_enter_debugger, NULL); 53659c993d1SWarner Losh #endif 53759c993d1SWarner Losh 53859c993d1SWarner Losh int 53959c993d1SWarner Losh soc_decode_win(void) 54059c993d1SWarner Losh { 54159c993d1SWarner Losh uint32_t dev, rev; 54259c993d1SWarner Losh int mask, err; 54359c993d1SWarner Losh 54459c993d1SWarner Losh mask = 0; 54559c993d1SWarner Losh TUNABLE_INT_FETCH("hw.pm-disable-mask", &mask); 54659c993d1SWarner Losh 54759c993d1SWarner Losh if (mask != 0) 54859c993d1SWarner Losh pm_disable_device(mask); 54959c993d1SWarner Losh 55059c993d1SWarner Losh /* Retrieve data about physical addresses from device tree. */ 55159c993d1SWarner Losh if ((err = win_cpu_from_dt()) != 0) 55259c993d1SWarner Losh return (err); 55359c993d1SWarner Losh 55459c993d1SWarner Losh /* Retrieve our ID: some windows facilities vary between SoC models */ 55559c993d1SWarner Losh soc_id(&dev, &rev); 55659c993d1SWarner Losh 55759c993d1SWarner Losh #ifdef SOC_MV_ARMADAXP 55859c993d1SWarner Losh if ((err = decode_win_sdram_fixup()) != 0) 55959c993d1SWarner Losh return(err); 56059c993d1SWarner Losh #endif 56159c993d1SWarner Losh 56259c993d1SWarner Losh #ifndef SOC_MV_FREY 56359c993d1SWarner Losh if (!decode_win_cpu_valid() || !decode_win_usb_valid() || 56459c993d1SWarner Losh !decode_win_eth_valid() || !decode_win_idma_valid() || 56559c993d1SWarner Losh !decode_win_pcie_valid() || !decode_win_sata_valid() || 56634a3d2c6SWojciech Macek !decode_win_xor_valid() || !decode_win_usb3_valid()) 56759c993d1SWarner Losh return (EINVAL); 56859c993d1SWarner Losh 56959c993d1SWarner Losh decode_win_cpu_setup(); 57059c993d1SWarner Losh #else 57159c993d1SWarner Losh if (!decode_win_usb_valid() || 57259c993d1SWarner Losh !decode_win_eth_valid() || !decode_win_idma_valid() || 57359c993d1SWarner Losh !decode_win_pcie_valid() || !decode_win_sata_valid() || 57434a3d2c6SWojciech Macek !decode_win_xor_valid() || !decode_win_usb3_valid()) 57559c993d1SWarner Losh return (EINVAL); 57659c993d1SWarner Losh #endif 57759c993d1SWarner Losh if (MV_DUMP_WIN) 57859c993d1SWarner Losh soc_dump_decode_win(); 57959c993d1SWarner Losh 58059c993d1SWarner Losh eth_port = 0; 58159c993d1SWarner Losh usb_port = 0; 58259c993d1SWarner Losh if ((err = fdt_win_setup()) != 0) 58359c993d1SWarner Losh return (err); 58459c993d1SWarner Losh 58559c993d1SWarner Losh return (0); 58659c993d1SWarner Losh } 58759c993d1SWarner Losh 58859c993d1SWarner Losh /************************************************************************** 58959c993d1SWarner Losh * Decode windows registers accessors 59059c993d1SWarner Losh **************************************************************************/ 59159c993d1SWarner Losh #if !defined(SOC_MV_FREY) 59259c993d1SWarner Losh WIN_REG_IDX_RD(win_cpu, cr, MV_WIN_CPU_CTRL, MV_MBUS_BRIDGE_BASE) 59359c993d1SWarner Losh WIN_REG_IDX_RD(win_cpu, br, MV_WIN_CPU_BASE, MV_MBUS_BRIDGE_BASE) 59459c993d1SWarner Losh WIN_REG_IDX_RD(win_cpu, remap_l, MV_WIN_CPU_REMAP_LO, MV_MBUS_BRIDGE_BASE) 59559c993d1SWarner Losh WIN_REG_IDX_RD(win_cpu, remap_h, MV_WIN_CPU_REMAP_HI, MV_MBUS_BRIDGE_BASE) 59659c993d1SWarner Losh WIN_REG_IDX_WR(win_cpu, cr, MV_WIN_CPU_CTRL, MV_MBUS_BRIDGE_BASE) 59759c993d1SWarner Losh WIN_REG_IDX_WR(win_cpu, br, MV_WIN_CPU_BASE, MV_MBUS_BRIDGE_BASE) 59859c993d1SWarner Losh WIN_REG_IDX_WR(win_cpu, remap_l, MV_WIN_CPU_REMAP_LO, MV_MBUS_BRIDGE_BASE) 59959c993d1SWarner Losh WIN_REG_IDX_WR(win_cpu, remap_h, MV_WIN_CPU_REMAP_HI, MV_MBUS_BRIDGE_BASE) 60059c993d1SWarner Losh #endif 60159c993d1SWarner Losh 60259c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_usb, cr, MV_WIN_USB_CTRL) 60359c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_usb, br, MV_WIN_USB_BASE) 60459c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_usb, cr, MV_WIN_USB_CTRL) 60559c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_usb, br, MV_WIN_USB_BASE) 60659c993d1SWarner Losh 60734a3d2c6SWojciech Macek #ifdef SOC_MV_ARMADA38X 60834a3d2c6SWojciech Macek WIN_REG_BASE_IDX_RD(win_usb3, cr, MV_WIN_USB3_CTRL) 60934a3d2c6SWojciech Macek WIN_REG_BASE_IDX_RD(win_usb3, br, MV_WIN_USB3_BASE) 61034a3d2c6SWojciech Macek WIN_REG_BASE_IDX_WR(win_usb3, cr, MV_WIN_USB3_CTRL) 61134a3d2c6SWojciech Macek WIN_REG_BASE_IDX_WR(win_usb3, br, MV_WIN_USB3_BASE) 61234a3d2c6SWojciech Macek #endif 61334a3d2c6SWojciech Macek 61459c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_eth, br, MV_WIN_ETH_BASE) 61559c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_eth, sz, MV_WIN_ETH_SIZE) 61659c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_eth, har, MV_WIN_ETH_REMAP) 61759c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_eth, br, MV_WIN_ETH_BASE) 61859c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_eth, sz, MV_WIN_ETH_SIZE) 61959c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_eth, har, MV_WIN_ETH_REMAP) 62059c993d1SWarner Losh 62159c993d1SWarner Losh WIN_REG_BASE_IDX_RD2(win_xor, br, MV_WIN_XOR_BASE) 62259c993d1SWarner Losh WIN_REG_BASE_IDX_RD2(win_xor, sz, MV_WIN_XOR_SIZE) 62359c993d1SWarner Losh WIN_REG_BASE_IDX_RD2(win_xor, har, MV_WIN_XOR_REMAP) 62459c993d1SWarner Losh WIN_REG_BASE_IDX_RD2(win_xor, ctrl, MV_WIN_XOR_CTRL) 62559c993d1SWarner Losh WIN_REG_BASE_IDX_WR2(win_xor, br, MV_WIN_XOR_BASE) 62659c993d1SWarner Losh WIN_REG_BASE_IDX_WR2(win_xor, sz, MV_WIN_XOR_SIZE) 62759c993d1SWarner Losh WIN_REG_BASE_IDX_WR2(win_xor, har, MV_WIN_XOR_REMAP) 62859c993d1SWarner Losh WIN_REG_BASE_IDX_WR2(win_xor, ctrl, MV_WIN_XOR_CTRL) 62959c993d1SWarner Losh 63059c993d1SWarner Losh WIN_REG_BASE_RD(win_eth, bare, 0x290) 63159c993d1SWarner Losh WIN_REG_BASE_RD(win_eth, epap, 0x294) 63259c993d1SWarner Losh WIN_REG_BASE_WR(win_eth, bare, 0x290) 63359c993d1SWarner Losh WIN_REG_BASE_WR(win_eth, epap, 0x294) 63459c993d1SWarner Losh 63559c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_pcie, cr, MV_WIN_PCIE_CTRL); 63659c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_pcie, br, MV_WIN_PCIE_BASE); 63759c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_pcie, remap, MV_WIN_PCIE_REMAP); 63859c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_pcie, cr, MV_WIN_PCIE_CTRL); 63959c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_pcie, br, MV_WIN_PCIE_BASE); 64059c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_pcie, remap, MV_WIN_PCIE_REMAP); 64159c993d1SWarner Losh WIN_REG_BASE_IDX_RD(pcie_bar, br, MV_PCIE_BAR_BASE); 64259c993d1SWarner Losh WIN_REG_BASE_IDX_WR(pcie_bar, br, MV_PCIE_BAR_BASE); 64359c993d1SWarner Losh WIN_REG_BASE_IDX_WR(pcie_bar, brh, MV_PCIE_BAR_BASE_H); 64459c993d1SWarner Losh WIN_REG_BASE_IDX_WR(pcie_bar, cr, MV_PCIE_BAR_CTRL); 64559c993d1SWarner Losh 64659c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_idma, br, MV_WIN_IDMA_BASE) 64759c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_idma, sz, MV_WIN_IDMA_SIZE) 64859c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_idma, har, MV_WIN_IDMA_REMAP) 64959c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_idma, cap, MV_WIN_IDMA_CAP) 65059c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_idma, br, MV_WIN_IDMA_BASE) 65159c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_idma, sz, MV_WIN_IDMA_SIZE) 65259c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_idma, har, MV_WIN_IDMA_REMAP) 65359c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_idma, cap, MV_WIN_IDMA_CAP) 65459c993d1SWarner Losh WIN_REG_BASE_RD(win_idma, bare, 0xa80) 65559c993d1SWarner Losh WIN_REG_BASE_WR(win_idma, bare, 0xa80) 65659c993d1SWarner Losh 65759c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_sata, cr, MV_WIN_SATA_CTRL); 65859c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_sata, br, MV_WIN_SATA_BASE); 65959c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_sata, cr, MV_WIN_SATA_CTRL); 66059c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_sata, br, MV_WIN_SATA_BASE); 66159c993d1SWarner Losh #ifndef SOC_MV_DOVE 66259c993d1SWarner Losh WIN_REG_IDX_RD(ddr, br, MV_WIN_DDR_BASE, MV_DDR_CADR_BASE) 66359c993d1SWarner Losh WIN_REG_IDX_RD(ddr, sz, MV_WIN_DDR_SIZE, MV_DDR_CADR_BASE) 66459c993d1SWarner Losh WIN_REG_IDX_WR(ddr, br, MV_WIN_DDR_BASE, MV_DDR_CADR_BASE) 66559c993d1SWarner Losh WIN_REG_IDX_WR(ddr, sz, MV_WIN_DDR_SIZE, MV_DDR_CADR_BASE) 66659c993d1SWarner Losh #else 66759c993d1SWarner Losh /* 66859c993d1SWarner Losh * On 88F6781 (Dove) SoC DDR Controller is accessed through 66959c993d1SWarner Losh * single MBUS <-> AXI bridge. In this case we provide emulated 67059c993d1SWarner Losh * ddr_br_read() and ddr_sz_read() functions to keep compatibility 67159c993d1SWarner Losh * with common decoding windows setup code. 67259c993d1SWarner Losh */ 67359c993d1SWarner Losh 67459c993d1SWarner Losh static inline uint32_t ddr_br_read(int i) 67559c993d1SWarner Losh { 67659c993d1SWarner Losh uint32_t mmap; 67759c993d1SWarner Losh 67859c993d1SWarner Losh /* Read Memory Address Map Register for CS i */ 67959c993d1SWarner Losh mmap = bus_space_read_4(fdtbus_bs_tag, MV_DDR_CADR_BASE + (i * 0x10), 0); 68059c993d1SWarner Losh 68159c993d1SWarner Losh /* Return CS i base address */ 68259c993d1SWarner Losh return (mmap & 0xFF000000); 68359c993d1SWarner Losh } 68459c993d1SWarner Losh 68559c993d1SWarner Losh static inline uint32_t ddr_sz_read(int i) 68659c993d1SWarner Losh { 68759c993d1SWarner Losh uint32_t mmap, size; 68859c993d1SWarner Losh 68959c993d1SWarner Losh /* Read Memory Address Map Register for CS i */ 69059c993d1SWarner Losh mmap = bus_space_read_4(fdtbus_bs_tag, MV_DDR_CADR_BASE + (i * 0x10), 0); 69159c993d1SWarner Losh 69259c993d1SWarner Losh /* Extract size of CS space in 64kB units */ 69359c993d1SWarner Losh size = (1 << ((mmap >> 16) & 0x0F)); 69459c993d1SWarner Losh 69559c993d1SWarner Losh /* Return CS size and enable/disable status */ 69659c993d1SWarner Losh return (((size - 1) << 16) | (mmap & 0x01)); 69759c993d1SWarner Losh } 69859c993d1SWarner Losh #endif 69959c993d1SWarner Losh 70059c993d1SWarner Losh #if !defined(SOC_MV_FREY) 70159c993d1SWarner Losh /************************************************************************** 70259c993d1SWarner Losh * Decode windows helper routines 70359c993d1SWarner Losh **************************************************************************/ 70459c993d1SWarner Losh void 70559c993d1SWarner Losh soc_dump_decode_win(void) 70659c993d1SWarner Losh { 70759c993d1SWarner Losh uint32_t dev, rev; 70859c993d1SWarner Losh int i; 70959c993d1SWarner Losh 71059c993d1SWarner Losh soc_id(&dev, &rev); 71159c993d1SWarner Losh 71259c993d1SWarner Losh for (i = 0; i < MV_WIN_CPU_MAX; i++) { 71359c993d1SWarner Losh printf("CPU window#%d: c 0x%08x, b 0x%08x", i, 71459c993d1SWarner Losh win_cpu_cr_read(i), 71559c993d1SWarner Losh win_cpu_br_read(i)); 71659c993d1SWarner Losh 71759c993d1SWarner Losh if (win_cpu_can_remap(i)) 71859c993d1SWarner Losh printf(", rl 0x%08x, rh 0x%08x", 71959c993d1SWarner Losh win_cpu_remap_l_read(i), 72059c993d1SWarner Losh win_cpu_remap_h_read(i)); 72159c993d1SWarner Losh 72259c993d1SWarner Losh printf("\n"); 72359c993d1SWarner Losh } 72459c993d1SWarner Losh printf("Internal regs base: 0x%08x\n", 72559c993d1SWarner Losh bus_space_read_4(fdtbus_bs_tag, MV_INTREGS_BASE, 0)); 72659c993d1SWarner Losh 72759c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) 72859c993d1SWarner Losh printf("DDR CS#%d: b 0x%08x, s 0x%08x\n", i, 72959c993d1SWarner Losh ddr_br_read(i), ddr_sz_read(i)); 73059c993d1SWarner Losh } 73159c993d1SWarner Losh 73259c993d1SWarner Losh /************************************************************************** 73359c993d1SWarner Losh * CPU windows routines 73459c993d1SWarner Losh **************************************************************************/ 73559c993d1SWarner Losh int 73659c993d1SWarner Losh win_cpu_can_remap(int i) 73759c993d1SWarner Losh { 73859c993d1SWarner Losh uint32_t dev, rev; 73959c993d1SWarner Losh 74059c993d1SWarner Losh soc_id(&dev, &rev); 74159c993d1SWarner Losh 74259c993d1SWarner Losh /* Depending on the SoC certain windows have remap capability */ 74359c993d1SWarner Losh if ((dev == MV_DEV_88F5182 && i < 2) || 74459c993d1SWarner Losh (dev == MV_DEV_88F5281 && i < 4) || 74559c993d1SWarner Losh (dev == MV_DEV_88F6281 && i < 4) || 74659c993d1SWarner Losh (dev == MV_DEV_88F6282 && i < 4) || 747515af5ceSZbigniew Bodek (dev == MV_DEV_88F6828 && i < 20) || 748515af5ceSZbigniew Bodek (dev == MV_DEV_88F6820 && i < 20) || 749515af5ceSZbigniew Bodek (dev == MV_DEV_88F6810 && i < 20) || 75059c993d1SWarner Losh (dev == MV_DEV_88RC8180 && i < 2) || 75159c993d1SWarner Losh (dev == MV_DEV_88F6781 && i < 4) || 75259c993d1SWarner Losh (dev == MV_DEV_MV78100_Z0 && i < 8) || 75359c993d1SWarner Losh ((dev & MV_DEV_FAMILY_MASK) == MV_DEV_DISCOVERY && i < 8)) 75459c993d1SWarner Losh return (1); 75559c993d1SWarner Losh 75659c993d1SWarner Losh return (0); 75759c993d1SWarner Losh } 75859c993d1SWarner Losh 75959c993d1SWarner Losh /* XXX This should check for overlapping remap fields too.. */ 76059c993d1SWarner Losh int 76159c993d1SWarner Losh decode_win_overlap(int win, int win_no, const struct decode_win *wintab) 76259c993d1SWarner Losh { 76359c993d1SWarner Losh const struct decode_win *tab; 76459c993d1SWarner Losh int i; 76559c993d1SWarner Losh 76659c993d1SWarner Losh tab = wintab; 76759c993d1SWarner Losh 76859c993d1SWarner Losh for (i = 0; i < win_no; i++, tab++) { 76959c993d1SWarner Losh if (i == win) 77059c993d1SWarner Losh /* Skip self */ 77159c993d1SWarner Losh continue; 77259c993d1SWarner Losh 77359c993d1SWarner Losh if ((tab->base + tab->size - 1) < (wintab + win)->base) 77459c993d1SWarner Losh continue; 77559c993d1SWarner Losh 77659c993d1SWarner Losh else if (((wintab + win)->base + (wintab + win)->size - 1) < 77759c993d1SWarner Losh tab->base) 77859c993d1SWarner Losh continue; 77959c993d1SWarner Losh else 78059c993d1SWarner Losh return (i); 78159c993d1SWarner Losh } 78259c993d1SWarner Losh 78359c993d1SWarner Losh return (-1); 78459c993d1SWarner Losh } 78559c993d1SWarner Losh 78659c993d1SWarner Losh static int 78759c993d1SWarner Losh decode_win_cpu_valid(void) 78859c993d1SWarner Losh { 78959c993d1SWarner Losh int i, j, rv; 79059c993d1SWarner Losh uint32_t b, e, s; 79159c993d1SWarner Losh 79259c993d1SWarner Losh if (cpu_wins_no > MV_WIN_CPU_MAX) { 79359c993d1SWarner Losh printf("CPU windows: too many entries: %d\n", cpu_wins_no); 79459c993d1SWarner Losh return (0); 79559c993d1SWarner Losh } 79659c993d1SWarner Losh 79759c993d1SWarner Losh rv = 1; 79859c993d1SWarner Losh for (i = 0; i < cpu_wins_no; i++) { 79959c993d1SWarner Losh 80059c993d1SWarner Losh if (cpu_wins[i].target == 0) { 80159c993d1SWarner Losh printf("CPU window#%d: DDR target window is not " 80259c993d1SWarner Losh "supposed to be reprogrammed!\n", i); 80359c993d1SWarner Losh rv = 0; 80459c993d1SWarner Losh } 80559c993d1SWarner Losh 80659c993d1SWarner Losh if (cpu_wins[i].remap != ~0 && win_cpu_can_remap(i) != 1) { 80759c993d1SWarner Losh printf("CPU window#%d: not capable of remapping, but " 80859c993d1SWarner Losh "val 0x%08x defined\n", i, cpu_wins[i].remap); 80959c993d1SWarner Losh rv = 0; 81059c993d1SWarner Losh } 81159c993d1SWarner Losh 81259c993d1SWarner Losh s = cpu_wins[i].size; 81359c993d1SWarner Losh b = cpu_wins[i].base; 81459c993d1SWarner Losh e = b + s - 1; 81559c993d1SWarner Losh if (s > (0xFFFFFFFF - b + 1)) { 81659c993d1SWarner Losh /* 81759c993d1SWarner Losh * XXX this boundary check should account for 64bit 81859c993d1SWarner Losh * and remapping.. 81959c993d1SWarner Losh */ 82059c993d1SWarner Losh printf("CPU window#%d: no space for size 0x%08x at " 82159c993d1SWarner Losh "0x%08x\n", i, s, b); 82259c993d1SWarner Losh rv = 0; 82359c993d1SWarner Losh continue; 82459c993d1SWarner Losh } 82559c993d1SWarner Losh 826d9c9c81cSPedro F. Giffuni if (b != rounddown2(b, s)) { 82759c993d1SWarner Losh printf("CPU window#%d: address 0x%08x is not aligned " 82859c993d1SWarner Losh "to 0x%08x\n", i, b, s); 82959c993d1SWarner Losh rv = 0; 83059c993d1SWarner Losh continue; 83159c993d1SWarner Losh } 83259c993d1SWarner Losh 83359c993d1SWarner Losh j = decode_win_overlap(i, cpu_wins_no, &cpu_wins[0]); 83459c993d1SWarner Losh if (j >= 0) { 83559c993d1SWarner Losh printf("CPU window#%d: (0x%08x - 0x%08x) overlaps " 83659c993d1SWarner Losh "with #%d (0x%08x - 0x%08x)\n", i, b, e, j, 83759c993d1SWarner Losh cpu_wins[j].base, 83859c993d1SWarner Losh cpu_wins[j].base + cpu_wins[j].size - 1); 83959c993d1SWarner Losh rv = 0; 84059c993d1SWarner Losh } 84159c993d1SWarner Losh } 84259c993d1SWarner Losh 84359c993d1SWarner Losh return (rv); 84459c993d1SWarner Losh } 84559c993d1SWarner Losh 84659c993d1SWarner Losh int 84759c993d1SWarner Losh decode_win_cpu_set(int target, int attr, vm_paddr_t base, uint32_t size, 84859c993d1SWarner Losh vm_paddr_t remap) 84959c993d1SWarner Losh { 85059c993d1SWarner Losh uint32_t br, cr; 85159c993d1SWarner Losh int win, i; 85259c993d1SWarner Losh 85359c993d1SWarner Losh if (remap == ~0) { 85459c993d1SWarner Losh win = MV_WIN_CPU_MAX - 1; 85559c993d1SWarner Losh i = -1; 85659c993d1SWarner Losh } else { 85759c993d1SWarner Losh win = 0; 85859c993d1SWarner Losh i = 1; 85959c993d1SWarner Losh } 86059c993d1SWarner Losh 86159c993d1SWarner Losh while ((win >= 0) && (win < MV_WIN_CPU_MAX)) { 86259c993d1SWarner Losh cr = win_cpu_cr_read(win); 86359c993d1SWarner Losh if ((cr & MV_WIN_CPU_ENABLE_BIT) == 0) 86459c993d1SWarner Losh break; 86559c993d1SWarner Losh if ((cr & ((0xff << MV_WIN_CPU_ATTR_SHIFT) | 86659c993d1SWarner Losh (0x1f << MV_WIN_CPU_TARGET_SHIFT))) == 86759c993d1SWarner Losh ((attr << MV_WIN_CPU_ATTR_SHIFT) | 86859c993d1SWarner Losh (target << MV_WIN_CPU_TARGET_SHIFT))) 86959c993d1SWarner Losh break; 87059c993d1SWarner Losh win += i; 87159c993d1SWarner Losh } 87259c993d1SWarner Losh if ((win < 0) || (win >= MV_WIN_CPU_MAX) || 87359c993d1SWarner Losh ((remap != ~0) && (win_cpu_can_remap(win) == 0))) 87459c993d1SWarner Losh return (-1); 87559c993d1SWarner Losh 87659c993d1SWarner Losh br = base & 0xffff0000; 87759c993d1SWarner Losh win_cpu_br_write(win, br); 87859c993d1SWarner Losh 87959c993d1SWarner Losh if (win_cpu_can_remap(win)) { 88059c993d1SWarner Losh if (remap != ~0) { 88159c993d1SWarner Losh win_cpu_remap_l_write(win, remap & 0xffff0000); 88259c993d1SWarner Losh win_cpu_remap_h_write(win, 0); 88359c993d1SWarner Losh } else { 88459c993d1SWarner Losh /* 88559c993d1SWarner Losh * Remap function is not used for a given window 88659c993d1SWarner Losh * (capable of remapping) - set remap field with the 88759c993d1SWarner Losh * same value as base. 88859c993d1SWarner Losh */ 88959c993d1SWarner Losh win_cpu_remap_l_write(win, base & 0xffff0000); 89059c993d1SWarner Losh win_cpu_remap_h_write(win, 0); 89159c993d1SWarner Losh } 89259c993d1SWarner Losh } 89359c993d1SWarner Losh 89459c993d1SWarner Losh cr = ((size - 1) & 0xffff0000) | (attr << MV_WIN_CPU_ATTR_SHIFT) | 89559c993d1SWarner Losh (target << MV_WIN_CPU_TARGET_SHIFT) | MV_WIN_CPU_ENABLE_BIT; 89659c993d1SWarner Losh win_cpu_cr_write(win, cr); 89759c993d1SWarner Losh 89859c993d1SWarner Losh return (0); 89959c993d1SWarner Losh } 90059c993d1SWarner Losh 90159c993d1SWarner Losh static void 90259c993d1SWarner Losh decode_win_cpu_setup(void) 90359c993d1SWarner Losh { 90459c993d1SWarner Losh int i; 90559c993d1SWarner Losh 90659c993d1SWarner Losh /* Disable all CPU windows */ 90759c993d1SWarner Losh for (i = 0; i < MV_WIN_CPU_MAX; i++) { 90859c993d1SWarner Losh win_cpu_cr_write(i, 0); 90959c993d1SWarner Losh win_cpu_br_write(i, 0); 91059c993d1SWarner Losh if (win_cpu_can_remap(i)) { 91159c993d1SWarner Losh win_cpu_remap_l_write(i, 0); 91259c993d1SWarner Losh win_cpu_remap_h_write(i, 0); 91359c993d1SWarner Losh } 91459c993d1SWarner Losh } 91559c993d1SWarner Losh 91659c993d1SWarner Losh for (i = 0; i < cpu_wins_no; i++) 91759c993d1SWarner Losh if (cpu_wins[i].target > 0) 91859c993d1SWarner Losh decode_win_cpu_set(cpu_wins[i].target, 91959c993d1SWarner Losh cpu_wins[i].attr, cpu_wins[i].base, 92059c993d1SWarner Losh cpu_wins[i].size, cpu_wins[i].remap); 92159c993d1SWarner Losh 92259c993d1SWarner Losh } 92359c993d1SWarner Losh #endif 92459c993d1SWarner Losh 92559c993d1SWarner Losh #ifdef SOC_MV_ARMADAXP 92659c993d1SWarner Losh static int 92759c993d1SWarner Losh decode_win_sdram_fixup(void) 92859c993d1SWarner Losh { 92959c993d1SWarner Losh struct mem_region mr[FDT_MEM_REGIONS]; 93059c993d1SWarner Losh uint8_t window_valid[MV_WIN_DDR_MAX]; 931e571e15cSWojciech Macek int mr_cnt, err, i, j; 93259c993d1SWarner Losh uint32_t valid_win_num = 0; 93359c993d1SWarner Losh 93459c993d1SWarner Losh /* Grab physical memory regions information from device tree. */ 935a4376069SAndrew Turner err = fdt_get_mem_regions(mr, &mr_cnt, NULL); 93659c993d1SWarner Losh if (err != 0) 93759c993d1SWarner Losh return (err); 93859c993d1SWarner Losh 93959c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) 94059c993d1SWarner Losh window_valid[i] = 0; 94159c993d1SWarner Losh 94259c993d1SWarner Losh /* Try to match entries from device tree with settings from u-boot */ 94359c993d1SWarner Losh for (i = 0; i < mr_cnt; i++) { 94459c993d1SWarner Losh for (j = 0; j < MV_WIN_DDR_MAX; j++) { 94559c993d1SWarner Losh if (ddr_is_active(j) && 94659c993d1SWarner Losh (ddr_base(j) == mr[i].mr_start) && 94759c993d1SWarner Losh (ddr_size(j) == mr[i].mr_size)) { 94859c993d1SWarner Losh window_valid[j] = 1; 94959c993d1SWarner Losh valid_win_num++; 95059c993d1SWarner Losh } 95159c993d1SWarner Losh } 95259c993d1SWarner Losh } 95359c993d1SWarner Losh 95459c993d1SWarner Losh if (mr_cnt != valid_win_num) 95559c993d1SWarner Losh return (EINVAL); 95659c993d1SWarner Losh 95759c993d1SWarner Losh /* Destroy windows without corresponding device tree entry */ 95859c993d1SWarner Losh for (j = 0; j < MV_WIN_DDR_MAX; j++) { 95959c993d1SWarner Losh if (ddr_is_active(j) && (window_valid[j] != 1)) { 96059c993d1SWarner Losh printf("Disabling SDRAM decoding window: %d\n", j); 96159c993d1SWarner Losh ddr_disable(j); 96259c993d1SWarner Losh } 96359c993d1SWarner Losh } 96459c993d1SWarner Losh 96559c993d1SWarner Losh return (0); 96659c993d1SWarner Losh } 96759c993d1SWarner Losh #endif 96859c993d1SWarner Losh /* 96959c993d1SWarner Losh * Check if we're able to cover all active DDR banks. 97059c993d1SWarner Losh */ 97159c993d1SWarner Losh static int 97259c993d1SWarner Losh decode_win_can_cover_ddr(int max) 97359c993d1SWarner Losh { 97459c993d1SWarner Losh int i, c; 97559c993d1SWarner Losh 97659c993d1SWarner Losh c = 0; 97759c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) 97859c993d1SWarner Losh if (ddr_is_active(i)) 97959c993d1SWarner Losh c++; 98059c993d1SWarner Losh 98159c993d1SWarner Losh if (c > max) { 98259c993d1SWarner Losh printf("Unable to cover all active DDR banks: " 98359c993d1SWarner Losh "%d, available windows: %d\n", c, max); 98459c993d1SWarner Losh return (0); 98559c993d1SWarner Losh } 98659c993d1SWarner Losh 98759c993d1SWarner Losh return (1); 98859c993d1SWarner Losh } 98959c993d1SWarner Losh 99059c993d1SWarner Losh /************************************************************************** 99159c993d1SWarner Losh * DDR windows routines 99259c993d1SWarner Losh **************************************************************************/ 99359c993d1SWarner Losh int 99459c993d1SWarner Losh ddr_is_active(int i) 99559c993d1SWarner Losh { 99659c993d1SWarner Losh 99759c993d1SWarner Losh if (ddr_sz_read(i) & 0x1) 99859c993d1SWarner Losh return (1); 99959c993d1SWarner Losh 100059c993d1SWarner Losh return (0); 100159c993d1SWarner Losh } 100259c993d1SWarner Losh 100359c993d1SWarner Losh void 100459c993d1SWarner Losh ddr_disable(int i) 100559c993d1SWarner Losh { 100659c993d1SWarner Losh 100759c993d1SWarner Losh ddr_sz_write(i, 0); 100859c993d1SWarner Losh ddr_br_write(i, 0); 100959c993d1SWarner Losh } 101059c993d1SWarner Losh 101159c993d1SWarner Losh uint32_t 101259c993d1SWarner Losh ddr_base(int i) 101359c993d1SWarner Losh { 101459c993d1SWarner Losh 101559c993d1SWarner Losh return (ddr_br_read(i) & 0xff000000); 101659c993d1SWarner Losh } 101759c993d1SWarner Losh 101859c993d1SWarner Losh uint32_t 101959c993d1SWarner Losh ddr_size(int i) 102059c993d1SWarner Losh { 102159c993d1SWarner Losh 102259c993d1SWarner Losh return ((ddr_sz_read(i) | 0x00ffffff) + 1); 102359c993d1SWarner Losh } 102459c993d1SWarner Losh 102559c993d1SWarner Losh uint32_t 102659c993d1SWarner Losh ddr_attr(int i) 102759c993d1SWarner Losh { 102859c993d1SWarner Losh uint32_t dev, rev; 102959c993d1SWarner Losh 103059c993d1SWarner Losh soc_id(&dev, &rev); 103159c993d1SWarner Losh if (dev == MV_DEV_88RC8180) 103259c993d1SWarner Losh return ((ddr_sz_read(i) & 0xf0) >> 4); 103359c993d1SWarner Losh if (dev == MV_DEV_88F6781) 103459c993d1SWarner Losh return (0); 103559c993d1SWarner Losh 103659c993d1SWarner Losh return (i == 0 ? 0xe : 103759c993d1SWarner Losh (i == 1 ? 0xd : 103859c993d1SWarner Losh (i == 2 ? 0xb : 103959c993d1SWarner Losh (i == 3 ? 0x7 : 0xff)))); 104059c993d1SWarner Losh } 104159c993d1SWarner Losh 104259c993d1SWarner Losh uint32_t 104359c993d1SWarner Losh ddr_target(int i) 104459c993d1SWarner Losh { 104559c993d1SWarner Losh uint32_t dev, rev; 104659c993d1SWarner Losh 104759c993d1SWarner Losh soc_id(&dev, &rev); 104859c993d1SWarner Losh if (dev == MV_DEV_88RC8180) { 104959c993d1SWarner Losh i = (ddr_sz_read(i) & 0xf0) >> 4; 105059c993d1SWarner Losh return (i == 0xe ? 0xc : 105159c993d1SWarner Losh (i == 0xd ? 0xd : 105259c993d1SWarner Losh (i == 0xb ? 0xe : 105359c993d1SWarner Losh (i == 0x7 ? 0xf : 0xc)))); 105459c993d1SWarner Losh } 105559c993d1SWarner Losh 105659c993d1SWarner Losh /* 105759c993d1SWarner Losh * On SOCs other than 88RC8180 Mbus unit ID for 105859c993d1SWarner Losh * DDR SDRAM controller is always 0x0. 105959c993d1SWarner Losh */ 106059c993d1SWarner Losh return (0); 106159c993d1SWarner Losh } 106259c993d1SWarner Losh 106359c993d1SWarner Losh /************************************************************************** 106459c993d1SWarner Losh * USB windows routines 106559c993d1SWarner Losh **************************************************************************/ 106659c993d1SWarner Losh static int 106759c993d1SWarner Losh decode_win_usb_valid(void) 106859c993d1SWarner Losh { 106959c993d1SWarner Losh 107059c993d1SWarner Losh return (decode_win_can_cover_ddr(MV_WIN_USB_MAX)); 107159c993d1SWarner Losh } 107259c993d1SWarner Losh 107359c993d1SWarner Losh static void 107459c993d1SWarner Losh decode_win_usb_dump(u_long base) 107559c993d1SWarner Losh { 107659c993d1SWarner Losh int i; 107759c993d1SWarner Losh 107859c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_USB(usb_port - 1))) 107959c993d1SWarner Losh return; 108059c993d1SWarner Losh 108159c993d1SWarner Losh for (i = 0; i < MV_WIN_USB_MAX; i++) 108259c993d1SWarner Losh printf("USB window#%d: c 0x%08x, b 0x%08x\n", i, 108359c993d1SWarner Losh win_usb_cr_read(base, i), win_usb_br_read(base, i)); 108459c993d1SWarner Losh } 108559c993d1SWarner Losh 108659c993d1SWarner Losh /* 108759c993d1SWarner Losh * Set USB decode windows. 108859c993d1SWarner Losh */ 108959c993d1SWarner Losh static void 109059c993d1SWarner Losh decode_win_usb_setup(u_long base) 109159c993d1SWarner Losh { 109259c993d1SWarner Losh uint32_t br, cr; 109359c993d1SWarner Losh int i, j; 109459c993d1SWarner Losh 109559c993d1SWarner Losh 109659c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_USB(usb_port))) 109759c993d1SWarner Losh return; 109859c993d1SWarner Losh 109959c993d1SWarner Losh usb_port++; 110059c993d1SWarner Losh 110159c993d1SWarner Losh for (i = 0; i < MV_WIN_USB_MAX; i++) { 110259c993d1SWarner Losh win_usb_cr_write(base, i, 0); 110359c993d1SWarner Losh win_usb_br_write(base, i, 0); 110459c993d1SWarner Losh } 110559c993d1SWarner Losh 110659c993d1SWarner Losh /* Only access to active DRAM banks is required */ 110759c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) { 110859c993d1SWarner Losh if (ddr_is_active(i)) { 110959c993d1SWarner Losh br = ddr_base(i); 111059c993d1SWarner Losh /* 111159c993d1SWarner Losh * XXX for 6281 we should handle Mbus write 111259c993d1SWarner Losh * burst limit field in the ctrl reg 111359c993d1SWarner Losh */ 111459c993d1SWarner Losh cr = (((ddr_size(i) - 1) & 0xffff0000) | 111559c993d1SWarner Losh (ddr_attr(i) << 8) | 111659c993d1SWarner Losh (ddr_target(i) << 4) | 1); 111759c993d1SWarner Losh 111859c993d1SWarner Losh /* Set the first free USB window */ 111959c993d1SWarner Losh for (j = 0; j < MV_WIN_USB_MAX; j++) { 112059c993d1SWarner Losh if (win_usb_cr_read(base, j) & 0x1) 112159c993d1SWarner Losh continue; 112259c993d1SWarner Losh 112359c993d1SWarner Losh win_usb_br_write(base, j, br); 112459c993d1SWarner Losh win_usb_cr_write(base, j, cr); 112559c993d1SWarner Losh break; 112659c993d1SWarner Losh } 112759c993d1SWarner Losh } 112859c993d1SWarner Losh } 112959c993d1SWarner Losh } 113059c993d1SWarner Losh 113159c993d1SWarner Losh /************************************************************************** 113234a3d2c6SWojciech Macek * USB3 windows routines 113334a3d2c6SWojciech Macek **************************************************************************/ 113434a3d2c6SWojciech Macek #ifdef SOC_MV_ARMADA38X 113534a3d2c6SWojciech Macek static int 113634a3d2c6SWojciech Macek decode_win_usb3_valid(void) 113734a3d2c6SWojciech Macek { 113834a3d2c6SWojciech Macek 113934a3d2c6SWojciech Macek return (decode_win_can_cover_ddr(MV_WIN_USB3_MAX)); 114034a3d2c6SWojciech Macek } 114134a3d2c6SWojciech Macek 114234a3d2c6SWojciech Macek static void 114334a3d2c6SWojciech Macek decode_win_usb3_dump(u_long base) 114434a3d2c6SWojciech Macek { 114534a3d2c6SWojciech Macek int i; 114634a3d2c6SWojciech Macek 114734a3d2c6SWojciech Macek for (i = 0; i < MV_WIN_USB3_MAX; i++) 114834a3d2c6SWojciech Macek printf("USB3.0 window#%d: c 0x%08x, b 0x%08x\n", i, 114934a3d2c6SWojciech Macek win_usb3_cr_read(base, i), win_usb3_br_read(base, i)); 115034a3d2c6SWojciech Macek } 115134a3d2c6SWojciech Macek 115234a3d2c6SWojciech Macek /* 115334a3d2c6SWojciech Macek * Set USB3 decode windows 115434a3d2c6SWojciech Macek */ 115534a3d2c6SWojciech Macek static void 115634a3d2c6SWojciech Macek decode_win_usb3_setup(u_long base) 115734a3d2c6SWojciech Macek { 115834a3d2c6SWojciech Macek uint32_t br, cr; 115934a3d2c6SWojciech Macek int i, j; 116034a3d2c6SWojciech Macek 116134a3d2c6SWojciech Macek for (i = 0; i < MV_WIN_USB3_MAX; i++) { 116234a3d2c6SWojciech Macek win_usb3_cr_write(base, i, 0); 116334a3d2c6SWojciech Macek win_usb3_br_write(base, i, 0); 116434a3d2c6SWojciech Macek } 116534a3d2c6SWojciech Macek 116634a3d2c6SWojciech Macek /* Only access to active DRAM banks is required */ 116734a3d2c6SWojciech Macek for (i = 0; i < MV_WIN_DDR_MAX; i++) { 116834a3d2c6SWojciech Macek if (ddr_is_active(i)) { 116934a3d2c6SWojciech Macek br = ddr_base(i); 117034a3d2c6SWojciech Macek cr = (((ddr_size(i) - 1) & 117134a3d2c6SWojciech Macek (IO_WIN_SIZE_MASK << IO_WIN_SIZE_SHIFT)) | 117234a3d2c6SWojciech Macek (ddr_attr(i) << IO_WIN_ATTR_SHIFT) | 117334a3d2c6SWojciech Macek (ddr_target(i) << IO_WIN_TGT_SHIFT) | 117434a3d2c6SWojciech Macek IO_WIN_ENA_MASK); 117534a3d2c6SWojciech Macek 117634a3d2c6SWojciech Macek /* Set the first free USB3.0 window */ 117734a3d2c6SWojciech Macek for (j = 0; j < MV_WIN_USB3_MAX; j++) { 117834a3d2c6SWojciech Macek if (win_usb3_cr_read(base, j) & IO_WIN_ENA_MASK) 117934a3d2c6SWojciech Macek continue; 118034a3d2c6SWojciech Macek 118134a3d2c6SWojciech Macek win_usb3_br_write(base, j, br); 118234a3d2c6SWojciech Macek win_usb3_cr_write(base, j, cr); 118334a3d2c6SWojciech Macek break; 118434a3d2c6SWojciech Macek } 118534a3d2c6SWojciech Macek } 118634a3d2c6SWojciech Macek } 118734a3d2c6SWojciech Macek } 118834a3d2c6SWojciech Macek #else 118934a3d2c6SWojciech Macek /* 119034a3d2c6SWojciech Macek * Provide dummy functions to satisfy the build 119134a3d2c6SWojciech Macek * for SoCs not equipped with USB3 119234a3d2c6SWojciech Macek */ 119334a3d2c6SWojciech Macek static int 119434a3d2c6SWojciech Macek decode_win_usb3_valid(void) 119534a3d2c6SWojciech Macek { 119634a3d2c6SWojciech Macek 119734a3d2c6SWojciech Macek return (1); 119834a3d2c6SWojciech Macek } 119934a3d2c6SWojciech Macek 120034a3d2c6SWojciech Macek static void 120134a3d2c6SWojciech Macek decode_win_usb3_setup(u_long base) 120234a3d2c6SWojciech Macek { 120334a3d2c6SWojciech Macek } 120434a3d2c6SWojciech Macek 120534a3d2c6SWojciech Macek static void 120634a3d2c6SWojciech Macek decode_win_usb3_dump(u_long base) 120734a3d2c6SWojciech Macek { 120834a3d2c6SWojciech Macek } 120934a3d2c6SWojciech Macek #endif 121034a3d2c6SWojciech Macek /************************************************************************** 121159c993d1SWarner Losh * ETH windows routines 121259c993d1SWarner Losh **************************************************************************/ 121359c993d1SWarner Losh 121459c993d1SWarner Losh static int 121559c993d1SWarner Losh win_eth_can_remap(int i) 121659c993d1SWarner Losh { 121759c993d1SWarner Losh 121859c993d1SWarner Losh /* ETH encode windows 0-3 have remap capability */ 121959c993d1SWarner Losh if (i < 4) 122059c993d1SWarner Losh return (1); 122159c993d1SWarner Losh 122259c993d1SWarner Losh return (0); 122359c993d1SWarner Losh } 122459c993d1SWarner Losh 122559c993d1SWarner Losh static int 122659c993d1SWarner Losh eth_bare_read(uint32_t base, int i) 122759c993d1SWarner Losh { 122859c993d1SWarner Losh uint32_t v; 122959c993d1SWarner Losh 123059c993d1SWarner Losh v = win_eth_bare_read(base); 123159c993d1SWarner Losh v &= (1 << i); 123259c993d1SWarner Losh 123359c993d1SWarner Losh return (v >> i); 123459c993d1SWarner Losh } 123559c993d1SWarner Losh 123659c993d1SWarner Losh static void 123759c993d1SWarner Losh eth_bare_write(uint32_t base, int i, int val) 123859c993d1SWarner Losh { 123959c993d1SWarner Losh uint32_t v; 124059c993d1SWarner Losh 124159c993d1SWarner Losh v = win_eth_bare_read(base); 124259c993d1SWarner Losh v &= ~(1 << i); 124359c993d1SWarner Losh v |= (val << i); 124459c993d1SWarner Losh win_eth_bare_write(base, v); 124559c993d1SWarner Losh } 124659c993d1SWarner Losh 124759c993d1SWarner Losh static void 124859c993d1SWarner Losh eth_epap_write(uint32_t base, int i, int val) 124959c993d1SWarner Losh { 125059c993d1SWarner Losh uint32_t v; 125159c993d1SWarner Losh 125259c993d1SWarner Losh v = win_eth_epap_read(base); 125359c993d1SWarner Losh v &= ~(0x3 << (i * 2)); 125459c993d1SWarner Losh v |= (val << (i * 2)); 125559c993d1SWarner Losh win_eth_epap_write(base, v); 125659c993d1SWarner Losh } 125759c993d1SWarner Losh 125859c993d1SWarner Losh static void 125959c993d1SWarner Losh decode_win_eth_dump(u_long base) 126059c993d1SWarner Losh { 126159c993d1SWarner Losh int i; 126259c993d1SWarner Losh 126359c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_GE(eth_port - 1))) 126459c993d1SWarner Losh return; 126559c993d1SWarner Losh 126659c993d1SWarner Losh for (i = 0; i < MV_WIN_ETH_MAX; i++) { 126759c993d1SWarner Losh printf("ETH window#%d: b 0x%08x, s 0x%08x", i, 126859c993d1SWarner Losh win_eth_br_read(base, i), 126959c993d1SWarner Losh win_eth_sz_read(base, i)); 127059c993d1SWarner Losh 127159c993d1SWarner Losh if (win_eth_can_remap(i)) 127259c993d1SWarner Losh printf(", ha 0x%08x", 127359c993d1SWarner Losh win_eth_har_read(base, i)); 127459c993d1SWarner Losh 127559c993d1SWarner Losh printf("\n"); 127659c993d1SWarner Losh } 127759c993d1SWarner Losh printf("ETH windows: bare 0x%08x, epap 0x%08x\n", 127859c993d1SWarner Losh win_eth_bare_read(base), 127959c993d1SWarner Losh win_eth_epap_read(base)); 128059c993d1SWarner Losh } 128159c993d1SWarner Losh 128259c993d1SWarner Losh #if defined(SOC_MV_LOKIPLUS) 128359c993d1SWarner Losh #define MV_WIN_ETH_DDR_TRGT(n) 0 128459c993d1SWarner Losh #else 128559c993d1SWarner Losh #define MV_WIN_ETH_DDR_TRGT(n) ddr_target(n) 128659c993d1SWarner Losh #endif 128759c993d1SWarner Losh 128859c993d1SWarner Losh static void 128959c993d1SWarner Losh decode_win_eth_setup(u_long base) 129059c993d1SWarner Losh { 129159c993d1SWarner Losh uint32_t br, sz; 129259c993d1SWarner Losh int i, j; 129359c993d1SWarner Losh 129459c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_GE(eth_port))) 129559c993d1SWarner Losh return; 129659c993d1SWarner Losh 129759c993d1SWarner Losh eth_port++; 129859c993d1SWarner Losh 129959c993d1SWarner Losh /* Disable, clear and revoke protection for all ETH windows */ 130059c993d1SWarner Losh for (i = 0; i < MV_WIN_ETH_MAX; i++) { 130159c993d1SWarner Losh 130259c993d1SWarner Losh eth_bare_write(base, i, 1); 130359c993d1SWarner Losh eth_epap_write(base, i, 0); 130459c993d1SWarner Losh win_eth_br_write(base, i, 0); 130559c993d1SWarner Losh win_eth_sz_write(base, i, 0); 130659c993d1SWarner Losh if (win_eth_can_remap(i)) 130759c993d1SWarner Losh win_eth_har_write(base, i, 0); 130859c993d1SWarner Losh } 130959c993d1SWarner Losh 131059c993d1SWarner Losh /* Only access to active DRAM banks is required */ 131159c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) 131259c993d1SWarner Losh if (ddr_is_active(i)) { 131359c993d1SWarner Losh 131459c993d1SWarner Losh br = ddr_base(i) | (ddr_attr(i) << 8) | MV_WIN_ETH_DDR_TRGT(i); 131559c993d1SWarner Losh sz = ((ddr_size(i) - 1) & 0xffff0000); 131659c993d1SWarner Losh 131759c993d1SWarner Losh /* Set the first free ETH window */ 131859c993d1SWarner Losh for (j = 0; j < MV_WIN_ETH_MAX; j++) { 131959c993d1SWarner Losh if (eth_bare_read(base, j) == 0) 132059c993d1SWarner Losh continue; 132159c993d1SWarner Losh 132259c993d1SWarner Losh win_eth_br_write(base, j, br); 132359c993d1SWarner Losh win_eth_sz_write(base, j, sz); 132459c993d1SWarner Losh 132559c993d1SWarner Losh /* XXX remapping ETH windows not supported */ 132659c993d1SWarner Losh 132759c993d1SWarner Losh /* Set protection RW */ 132859c993d1SWarner Losh eth_epap_write(base, j, 0x3); 132959c993d1SWarner Losh 133059c993d1SWarner Losh /* Enable window */ 133159c993d1SWarner Losh eth_bare_write(base, j, 0); 133259c993d1SWarner Losh break; 133359c993d1SWarner Losh } 133459c993d1SWarner Losh } 133559c993d1SWarner Losh } 133659c993d1SWarner Losh 133759c993d1SWarner Losh static int 133859c993d1SWarner Losh decode_win_eth_valid(void) 133959c993d1SWarner Losh { 134059c993d1SWarner Losh 134159c993d1SWarner Losh return (decode_win_can_cover_ddr(MV_WIN_ETH_MAX)); 134259c993d1SWarner Losh } 134359c993d1SWarner Losh 134459c993d1SWarner Losh /************************************************************************** 134559c993d1SWarner Losh * PCIE windows routines 134659c993d1SWarner Losh **************************************************************************/ 134759c993d1SWarner Losh 134859c993d1SWarner Losh void 134959c993d1SWarner Losh decode_win_pcie_setup(u_long base) 135059c993d1SWarner Losh { 135159c993d1SWarner Losh uint32_t size = 0, ddrbase = ~0; 135259c993d1SWarner Losh uint32_t cr, br; 135359c993d1SWarner Losh int i, j; 135459c993d1SWarner Losh 135559c993d1SWarner Losh for (i = 0; i < MV_PCIE_BAR_MAX; i++) { 135659c993d1SWarner Losh pcie_bar_br_write(base, i, 135759c993d1SWarner Losh MV_PCIE_BAR_64BIT | MV_PCIE_BAR_PREFETCH_EN); 135859c993d1SWarner Losh if (i < 3) 135959c993d1SWarner Losh pcie_bar_brh_write(base, i, 0); 136059c993d1SWarner Losh if (i > 0) 136159c993d1SWarner Losh pcie_bar_cr_write(base, i, 0); 136259c993d1SWarner Losh } 136359c993d1SWarner Losh 136459c993d1SWarner Losh for (i = 0; i < MV_WIN_PCIE_MAX; i++) { 136559c993d1SWarner Losh win_pcie_cr_write(base, i, 0); 136659c993d1SWarner Losh win_pcie_br_write(base, i, 0); 136759c993d1SWarner Losh win_pcie_remap_write(base, i, 0); 136859c993d1SWarner Losh } 136959c993d1SWarner Losh 137059c993d1SWarner Losh /* On End-Point only set BAR size to 1MB regardless of DDR size */ 137159c993d1SWarner Losh if ((bus_space_read_4(fdtbus_bs_tag, base, MV_PCIE_CONTROL) 137259c993d1SWarner Losh & MV_PCIE_ROOT_CMPLX) == 0) { 137359c993d1SWarner Losh pcie_bar_cr_write(base, 1, 0xf0000 | 1); 137459c993d1SWarner Losh return; 137559c993d1SWarner Losh } 137659c993d1SWarner Losh 137759c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) { 137859c993d1SWarner Losh if (ddr_is_active(i)) { 137959c993d1SWarner Losh /* Map DDR to BAR 1 */ 138059c993d1SWarner Losh cr = (ddr_size(i) - 1) & 0xffff0000; 138159c993d1SWarner Losh size += ddr_size(i) & 0xffff0000; 138259c993d1SWarner Losh cr |= (ddr_attr(i) << 8) | (ddr_target(i) << 4) | 1; 138359c993d1SWarner Losh br = ddr_base(i); 138459c993d1SWarner Losh if (br < ddrbase) 138559c993d1SWarner Losh ddrbase = br; 138659c993d1SWarner Losh 138759c993d1SWarner Losh /* Use the first available PCIE window */ 138859c993d1SWarner Losh for (j = 0; j < MV_WIN_PCIE_MAX; j++) { 138959c993d1SWarner Losh if (win_pcie_cr_read(base, j) != 0) 139059c993d1SWarner Losh continue; 139159c993d1SWarner Losh 139259c993d1SWarner Losh win_pcie_br_write(base, j, br); 139359c993d1SWarner Losh win_pcie_cr_write(base, j, cr); 139459c993d1SWarner Losh break; 139559c993d1SWarner Losh } 139659c993d1SWarner Losh } 139759c993d1SWarner Losh } 139859c993d1SWarner Losh 139959c993d1SWarner Losh /* 140059c993d1SWarner Losh * Upper 16 bits in BAR register is interpreted as BAR size 1401255eff3bSPedro F. Giffuni * (in 64 kB units) plus 64kB, so subtract 0x10000 140259c993d1SWarner Losh * form value passed to register to get correct value. 140359c993d1SWarner Losh */ 140459c993d1SWarner Losh size -= 0x10000; 140559c993d1SWarner Losh pcie_bar_cr_write(base, 1, size | 1); 140659c993d1SWarner Losh pcie_bar_br_write(base, 1, ddrbase | 140759c993d1SWarner Losh MV_PCIE_BAR_64BIT | MV_PCIE_BAR_PREFETCH_EN); 140859c993d1SWarner Losh pcie_bar_br_write(base, 0, fdt_immr_pa | 140959c993d1SWarner Losh MV_PCIE_BAR_64BIT | MV_PCIE_BAR_PREFETCH_EN); 141059c993d1SWarner Losh } 141159c993d1SWarner Losh 141259c993d1SWarner Losh static int 141359c993d1SWarner Losh decode_win_pcie_valid(void) 141459c993d1SWarner Losh { 141559c993d1SWarner Losh 141659c993d1SWarner Losh return (decode_win_can_cover_ddr(MV_WIN_PCIE_MAX)); 141759c993d1SWarner Losh } 141859c993d1SWarner Losh 141959c993d1SWarner Losh /************************************************************************** 142059c993d1SWarner Losh * IDMA windows routines 142159c993d1SWarner Losh **************************************************************************/ 142259c993d1SWarner Losh #if defined(SOC_MV_ORION) || defined(SOC_MV_DISCOVERY) 142359c993d1SWarner Losh static int 142459c993d1SWarner Losh idma_bare_read(u_long base, int i) 142559c993d1SWarner Losh { 142659c993d1SWarner Losh uint32_t v; 142759c993d1SWarner Losh 142859c993d1SWarner Losh v = win_idma_bare_read(base); 142959c993d1SWarner Losh v &= (1 << i); 143059c993d1SWarner Losh 143159c993d1SWarner Losh return (v >> i); 143259c993d1SWarner Losh } 143359c993d1SWarner Losh 143459c993d1SWarner Losh static void 143559c993d1SWarner Losh idma_bare_write(u_long base, int i, int val) 143659c993d1SWarner Losh { 143759c993d1SWarner Losh uint32_t v; 143859c993d1SWarner Losh 143959c993d1SWarner Losh v = win_idma_bare_read(base); 144059c993d1SWarner Losh v &= ~(1 << i); 144159c993d1SWarner Losh v |= (val << i); 144259c993d1SWarner Losh win_idma_bare_write(base, v); 144359c993d1SWarner Losh } 144459c993d1SWarner Losh 144559c993d1SWarner Losh /* 144659c993d1SWarner Losh * Sets channel protection 'val' for window 'w' on channel 'c' 144759c993d1SWarner Losh */ 144859c993d1SWarner Losh static void 144959c993d1SWarner Losh idma_cap_write(u_long base, int c, int w, int val) 145059c993d1SWarner Losh { 145159c993d1SWarner Losh uint32_t v; 145259c993d1SWarner Losh 145359c993d1SWarner Losh v = win_idma_cap_read(base, c); 145459c993d1SWarner Losh v &= ~(0x3 << (w * 2)); 145559c993d1SWarner Losh v |= (val << (w * 2)); 145659c993d1SWarner Losh win_idma_cap_write(base, c, v); 145759c993d1SWarner Losh } 145859c993d1SWarner Losh 145959c993d1SWarner Losh /* 146059c993d1SWarner Losh * Set protection 'val' on all channels for window 'w' 146159c993d1SWarner Losh */ 146259c993d1SWarner Losh static void 146359c993d1SWarner Losh idma_set_prot(u_long base, int w, int val) 146459c993d1SWarner Losh { 146559c993d1SWarner Losh int c; 146659c993d1SWarner Losh 146759c993d1SWarner Losh for (c = 0; c < MV_IDMA_CHAN_MAX; c++) 146859c993d1SWarner Losh idma_cap_write(base, c, w, val); 146959c993d1SWarner Losh } 147059c993d1SWarner Losh 147159c993d1SWarner Losh static int 147259c993d1SWarner Losh win_idma_can_remap(int i) 147359c993d1SWarner Losh { 147459c993d1SWarner Losh 147559c993d1SWarner Losh /* IDMA decode windows 0-3 have remap capability */ 147659c993d1SWarner Losh if (i < 4) 147759c993d1SWarner Losh return (1); 147859c993d1SWarner Losh 147959c993d1SWarner Losh return (0); 148059c993d1SWarner Losh } 148159c993d1SWarner Losh 148259c993d1SWarner Losh void 148359c993d1SWarner Losh decode_win_idma_setup(u_long base) 148459c993d1SWarner Losh { 148559c993d1SWarner Losh uint32_t br, sz; 148659c993d1SWarner Losh int i, j; 148759c993d1SWarner Losh 148859c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_IDMA)) 148959c993d1SWarner Losh return; 149059c993d1SWarner Losh /* 149159c993d1SWarner Losh * Disable and clear all IDMA windows, revoke protection for all channels 149259c993d1SWarner Losh */ 149359c993d1SWarner Losh for (i = 0; i < MV_WIN_IDMA_MAX; i++) { 149459c993d1SWarner Losh 149559c993d1SWarner Losh idma_bare_write(base, i, 1); 149659c993d1SWarner Losh win_idma_br_write(base, i, 0); 149759c993d1SWarner Losh win_idma_sz_write(base, i, 0); 149859c993d1SWarner Losh if (win_idma_can_remap(i) == 1) 149959c993d1SWarner Losh win_idma_har_write(base, i, 0); 150059c993d1SWarner Losh } 150159c993d1SWarner Losh for (i = 0; i < MV_IDMA_CHAN_MAX; i++) 150259c993d1SWarner Losh win_idma_cap_write(base, i, 0); 150359c993d1SWarner Losh 150459c993d1SWarner Losh /* 150559c993d1SWarner Losh * Set up access to all active DRAM banks 150659c993d1SWarner Losh */ 150759c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) 150859c993d1SWarner Losh if (ddr_is_active(i)) { 150959c993d1SWarner Losh br = ddr_base(i) | (ddr_attr(i) << 8) | ddr_target(i); 151059c993d1SWarner Losh sz = ((ddr_size(i) - 1) & 0xffff0000); 151159c993d1SWarner Losh 151259c993d1SWarner Losh /* Place DDR entries in non-remapped windows */ 151359c993d1SWarner Losh for (j = 0; j < MV_WIN_IDMA_MAX; j++) 151459c993d1SWarner Losh if (win_idma_can_remap(j) != 1 && 151559c993d1SWarner Losh idma_bare_read(base, j) == 1) { 151659c993d1SWarner Losh 151759c993d1SWarner Losh /* Configure window */ 151859c993d1SWarner Losh win_idma_br_write(base, j, br); 151959c993d1SWarner Losh win_idma_sz_write(base, j, sz); 152059c993d1SWarner Losh 152159c993d1SWarner Losh /* Set protection RW on all channels */ 152259c993d1SWarner Losh idma_set_prot(base, j, 0x3); 152359c993d1SWarner Losh 152459c993d1SWarner Losh /* Enable window */ 152559c993d1SWarner Losh idma_bare_write(base, j, 0); 152659c993d1SWarner Losh break; 152759c993d1SWarner Losh } 152859c993d1SWarner Losh } 152959c993d1SWarner Losh 153059c993d1SWarner Losh /* 153159c993d1SWarner Losh * Remaining targets -- from statically defined table 153259c993d1SWarner Losh */ 153359c993d1SWarner Losh for (i = 0; i < idma_wins_no; i++) 153459c993d1SWarner Losh if (idma_wins[i].target > 0) { 153559c993d1SWarner Losh br = (idma_wins[i].base & 0xffff0000) | 153659c993d1SWarner Losh (idma_wins[i].attr << 8) | idma_wins[i].target; 153759c993d1SWarner Losh sz = ((idma_wins[i].size - 1) & 0xffff0000); 153859c993d1SWarner Losh 153959c993d1SWarner Losh /* Set the first free IDMA window */ 154059c993d1SWarner Losh for (j = 0; j < MV_WIN_IDMA_MAX; j++) { 154159c993d1SWarner Losh if (idma_bare_read(base, j) == 0) 154259c993d1SWarner Losh continue; 154359c993d1SWarner Losh 154459c993d1SWarner Losh /* Configure window */ 154559c993d1SWarner Losh win_idma_br_write(base, j, br); 154659c993d1SWarner Losh win_idma_sz_write(base, j, sz); 154759c993d1SWarner Losh if (win_idma_can_remap(j) && 154859c993d1SWarner Losh idma_wins[j].remap >= 0) 154959c993d1SWarner Losh win_idma_har_write(base, j, 155059c993d1SWarner Losh idma_wins[j].remap); 155159c993d1SWarner Losh 155259c993d1SWarner Losh /* Set protection RW on all channels */ 155359c993d1SWarner Losh idma_set_prot(base, j, 0x3); 155459c993d1SWarner Losh 155559c993d1SWarner Losh /* Enable window */ 155659c993d1SWarner Losh idma_bare_write(base, j, 0); 155759c993d1SWarner Losh break; 155859c993d1SWarner Losh } 155959c993d1SWarner Losh } 156059c993d1SWarner Losh } 156159c993d1SWarner Losh 156259c993d1SWarner Losh int 156359c993d1SWarner Losh decode_win_idma_valid(void) 156459c993d1SWarner Losh { 156559c993d1SWarner Losh const struct decode_win *wintab; 156659c993d1SWarner Losh int c, i, j, rv; 156759c993d1SWarner Losh uint32_t b, e, s; 156859c993d1SWarner Losh 156959c993d1SWarner Losh if (idma_wins_no > MV_WIN_IDMA_MAX) { 157059c993d1SWarner Losh printf("IDMA windows: too many entries: %d\n", idma_wins_no); 157159c993d1SWarner Losh return (0); 157259c993d1SWarner Losh } 157359c993d1SWarner Losh for (i = 0, c = 0; i < MV_WIN_DDR_MAX; i++) 157459c993d1SWarner Losh if (ddr_is_active(i)) 157559c993d1SWarner Losh c++; 157659c993d1SWarner Losh 157759c993d1SWarner Losh if (idma_wins_no > (MV_WIN_IDMA_MAX - c)) { 157859c993d1SWarner Losh printf("IDMA windows: too many entries: %d, available: %d\n", 157959c993d1SWarner Losh idma_wins_no, MV_WIN_IDMA_MAX - c); 158059c993d1SWarner Losh return (0); 158159c993d1SWarner Losh } 158259c993d1SWarner Losh 158359c993d1SWarner Losh wintab = idma_wins; 158459c993d1SWarner Losh rv = 1; 158559c993d1SWarner Losh for (i = 0; i < idma_wins_no; i++, wintab++) { 158659c993d1SWarner Losh 158759c993d1SWarner Losh if (wintab->target == 0) { 158859c993d1SWarner Losh printf("IDMA window#%d: DDR target window is not " 158959c993d1SWarner Losh "supposed to be reprogrammed!\n", i); 159059c993d1SWarner Losh rv = 0; 159159c993d1SWarner Losh } 159259c993d1SWarner Losh 159359c993d1SWarner Losh if (wintab->remap >= 0 && win_cpu_can_remap(i) != 1) { 159459c993d1SWarner Losh printf("IDMA window#%d: not capable of remapping, but " 159559c993d1SWarner Losh "val 0x%08x defined\n", i, wintab->remap); 159659c993d1SWarner Losh rv = 0; 159759c993d1SWarner Losh } 159859c993d1SWarner Losh 159959c993d1SWarner Losh s = wintab->size; 160059c993d1SWarner Losh b = wintab->base; 160159c993d1SWarner Losh e = b + s - 1; 160259c993d1SWarner Losh if (s > (0xFFFFFFFF - b + 1)) { 160359c993d1SWarner Losh /* XXX this boundary check should account for 64bit and 160459c993d1SWarner Losh * remapping.. */ 160559c993d1SWarner Losh printf("IDMA window#%d: no space for size 0x%08x at " 160659c993d1SWarner Losh "0x%08x\n", i, s, b); 160759c993d1SWarner Losh rv = 0; 160859c993d1SWarner Losh continue; 160959c993d1SWarner Losh } 161059c993d1SWarner Losh 161159c993d1SWarner Losh j = decode_win_overlap(i, idma_wins_no, &idma_wins[0]); 161259c993d1SWarner Losh if (j >= 0) { 161359c993d1SWarner Losh printf("IDMA window#%d: (0x%08x - 0x%08x) overlaps " 161459c993d1SWarner Losh "with #%d (0x%08x - 0x%08x)\n", i, b, e, j, 161559c993d1SWarner Losh idma_wins[j].base, 161659c993d1SWarner Losh idma_wins[j].base + idma_wins[j].size - 1); 161759c993d1SWarner Losh rv = 0; 161859c993d1SWarner Losh } 161959c993d1SWarner Losh } 162059c993d1SWarner Losh 162159c993d1SWarner Losh return (rv); 162259c993d1SWarner Losh } 162359c993d1SWarner Losh 162459c993d1SWarner Losh void 162559c993d1SWarner Losh decode_win_idma_dump(u_long base) 162659c993d1SWarner Losh { 162759c993d1SWarner Losh int i; 162859c993d1SWarner Losh 162959c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_IDMA)) 163059c993d1SWarner Losh return; 163159c993d1SWarner Losh 163259c993d1SWarner Losh for (i = 0; i < MV_WIN_IDMA_MAX; i++) { 163359c993d1SWarner Losh printf("IDMA window#%d: b 0x%08x, s 0x%08x", i, 163459c993d1SWarner Losh win_idma_br_read(base, i), win_idma_sz_read(base, i)); 163559c993d1SWarner Losh 163659c993d1SWarner Losh if (win_idma_can_remap(i)) 163759c993d1SWarner Losh printf(", ha 0x%08x", win_idma_har_read(base, i)); 163859c993d1SWarner Losh 163959c993d1SWarner Losh printf("\n"); 164059c993d1SWarner Losh } 164159c993d1SWarner Losh for (i = 0; i < MV_IDMA_CHAN_MAX; i++) 164259c993d1SWarner Losh printf("IDMA channel#%d: ap 0x%08x\n", i, 164359c993d1SWarner Losh win_idma_cap_read(base, i)); 164459c993d1SWarner Losh printf("IDMA windows: bare 0x%08x\n", win_idma_bare_read(base)); 164559c993d1SWarner Losh } 164659c993d1SWarner Losh #else 164759c993d1SWarner Losh 164859c993d1SWarner Losh /* Provide dummy functions to satisfy the build for SoCs not equipped with IDMA */ 164959c993d1SWarner Losh int 165059c993d1SWarner Losh decode_win_idma_valid(void) 165159c993d1SWarner Losh { 165259c993d1SWarner Losh 165359c993d1SWarner Losh return (1); 165459c993d1SWarner Losh } 165559c993d1SWarner Losh 165659c993d1SWarner Losh void 165759c993d1SWarner Losh decode_win_idma_setup(u_long base) 165859c993d1SWarner Losh { 165959c993d1SWarner Losh } 166059c993d1SWarner Losh 166159c993d1SWarner Losh void 166259c993d1SWarner Losh decode_win_idma_dump(u_long base) 166359c993d1SWarner Losh { 166459c993d1SWarner Losh } 166559c993d1SWarner Losh #endif 166659c993d1SWarner Losh 166759c993d1SWarner Losh /************************************************************************** 166859c993d1SWarner Losh * XOR windows routines 166959c993d1SWarner Losh **************************************************************************/ 167059c993d1SWarner Losh #if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY) 167159c993d1SWarner Losh static int 167259c993d1SWarner Losh xor_ctrl_read(u_long base, int i, int c, int e) 167359c993d1SWarner Losh { 167459c993d1SWarner Losh uint32_t v; 167559c993d1SWarner Losh v = win_xor_ctrl_read(base, c, e); 167659c993d1SWarner Losh v &= (1 << i); 167759c993d1SWarner Losh 167859c993d1SWarner Losh return (v >> i); 167959c993d1SWarner Losh } 168059c993d1SWarner Losh 168159c993d1SWarner Losh static void 168259c993d1SWarner Losh xor_ctrl_write(u_long base, int i, int c, int e, int val) 168359c993d1SWarner Losh { 168459c993d1SWarner Losh uint32_t v; 168559c993d1SWarner Losh 168659c993d1SWarner Losh v = win_xor_ctrl_read(base, c, e); 168759c993d1SWarner Losh v &= ~(1 << i); 168859c993d1SWarner Losh v |= (val << i); 168959c993d1SWarner Losh win_xor_ctrl_write(base, c, e, v); 169059c993d1SWarner Losh } 169159c993d1SWarner Losh 169259c993d1SWarner Losh /* 169359c993d1SWarner Losh * Set channel protection 'val' for window 'w' on channel 'c' 169459c993d1SWarner Losh */ 169559c993d1SWarner Losh static void 169659c993d1SWarner Losh xor_chan_write(u_long base, int c, int e, int w, int val) 169759c993d1SWarner Losh { 169859c993d1SWarner Losh uint32_t v; 169959c993d1SWarner Losh 170059c993d1SWarner Losh v = win_xor_ctrl_read(base, c, e); 170159c993d1SWarner Losh v &= ~(0x3 << (w * 2 + 16)); 170259c993d1SWarner Losh v |= (val << (w * 2 + 16)); 170359c993d1SWarner Losh win_xor_ctrl_write(base, c, e, v); 170459c993d1SWarner Losh } 170559c993d1SWarner Losh 170659c993d1SWarner Losh /* 170759c993d1SWarner Losh * Set protection 'val' on all channels for window 'w' on engine 'e' 170859c993d1SWarner Losh */ 170959c993d1SWarner Losh static void 171059c993d1SWarner Losh xor_set_prot(u_long base, int w, int e, int val) 171159c993d1SWarner Losh { 171259c993d1SWarner Losh int c; 171359c993d1SWarner Losh 171459c993d1SWarner Losh for (c = 0; c < MV_XOR_CHAN_MAX; c++) 171559c993d1SWarner Losh xor_chan_write(base, c, e, w, val); 171659c993d1SWarner Losh } 171759c993d1SWarner Losh 171859c993d1SWarner Losh static int 171959c993d1SWarner Losh win_xor_can_remap(int i) 172059c993d1SWarner Losh { 172159c993d1SWarner Losh 172259c993d1SWarner Losh /* XOR decode windows 0-3 have remap capability */ 172359c993d1SWarner Losh if (i < 4) 172459c993d1SWarner Losh return (1); 172559c993d1SWarner Losh 172659c993d1SWarner Losh return (0); 172759c993d1SWarner Losh } 172859c993d1SWarner Losh 172959c993d1SWarner Losh static int 173059c993d1SWarner Losh xor_max_eng(void) 173159c993d1SWarner Losh { 173259c993d1SWarner Losh uint32_t dev, rev; 173359c993d1SWarner Losh 173459c993d1SWarner Losh soc_id(&dev, &rev); 173559c993d1SWarner Losh switch (dev) { 173659c993d1SWarner Losh case MV_DEV_88F6281: 173759c993d1SWarner Losh case MV_DEV_88F6282: 173859c993d1SWarner Losh case MV_DEV_MV78130: 173959c993d1SWarner Losh case MV_DEV_MV78160: 174059c993d1SWarner Losh case MV_DEV_MV78230: 174159c993d1SWarner Losh case MV_DEV_MV78260: 174259c993d1SWarner Losh case MV_DEV_MV78460: 174359c993d1SWarner Losh return (2); 174459c993d1SWarner Losh case MV_DEV_MV78100: 174559c993d1SWarner Losh case MV_DEV_MV78100_Z0: 174659c993d1SWarner Losh return (1); 174759c993d1SWarner Losh default: 174859c993d1SWarner Losh return (0); 174959c993d1SWarner Losh } 175059c993d1SWarner Losh } 175159c993d1SWarner Losh 175259c993d1SWarner Losh static void 175359c993d1SWarner Losh xor_active_dram(u_long base, int c, int e, int *window) 175459c993d1SWarner Losh { 175559c993d1SWarner Losh uint32_t br, sz; 175659c993d1SWarner Losh int i, m, w; 175759c993d1SWarner Losh 175859c993d1SWarner Losh /* 175959c993d1SWarner Losh * Set up access to all active DRAM banks 176059c993d1SWarner Losh */ 176159c993d1SWarner Losh m = xor_max_eng(); 176259c993d1SWarner Losh for (i = 0; i < m; i++) 176359c993d1SWarner Losh if (ddr_is_active(i)) { 176459c993d1SWarner Losh br = ddr_base(i) | (ddr_attr(i) << 8) | 176559c993d1SWarner Losh ddr_target(i); 176659c993d1SWarner Losh sz = ((ddr_size(i) - 1) & 0xffff0000); 176759c993d1SWarner Losh 176859c993d1SWarner Losh /* Place DDR entries in non-remapped windows */ 176959c993d1SWarner Losh for (w = 0; w < MV_WIN_XOR_MAX; w++) 177059c993d1SWarner Losh if (win_xor_can_remap(w) != 1 && 177159c993d1SWarner Losh (xor_ctrl_read(base, w, c, e) == 0) && 177259c993d1SWarner Losh w > *window) { 177359c993d1SWarner Losh /* Configure window */ 177459c993d1SWarner Losh win_xor_br_write(base, w, e, br); 177559c993d1SWarner Losh win_xor_sz_write(base, w, e, sz); 177659c993d1SWarner Losh 177759c993d1SWarner Losh /* Set protection RW on all channels */ 177859c993d1SWarner Losh xor_set_prot(base, w, e, 0x3); 177959c993d1SWarner Losh 178059c993d1SWarner Losh /* Enable window */ 178159c993d1SWarner Losh xor_ctrl_write(base, w, c, e, 1); 178259c993d1SWarner Losh (*window)++; 178359c993d1SWarner Losh break; 178459c993d1SWarner Losh } 178559c993d1SWarner Losh } 178659c993d1SWarner Losh } 178759c993d1SWarner Losh 178859c993d1SWarner Losh void 178959c993d1SWarner Losh decode_win_xor_setup(u_long base) 179059c993d1SWarner Losh { 179159c993d1SWarner Losh uint32_t br, sz; 179259c993d1SWarner Losh int i, j, z, e = 1, m, window; 179359c993d1SWarner Losh 179459c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_XOR)) 179559c993d1SWarner Losh return; 179659c993d1SWarner Losh 179759c993d1SWarner Losh /* 179859c993d1SWarner Losh * Disable and clear all XOR windows, revoke protection for all 179959c993d1SWarner Losh * channels 180059c993d1SWarner Losh */ 180159c993d1SWarner Losh m = xor_max_eng(); 180259c993d1SWarner Losh for (j = 0; j < m; j++, e--) { 180359c993d1SWarner Losh 180459c993d1SWarner Losh /* Number of non-remaped windows */ 180559c993d1SWarner Losh window = MV_XOR_NON_REMAP - 1; 180659c993d1SWarner Losh 180759c993d1SWarner Losh for (i = 0; i < MV_WIN_XOR_MAX; i++) { 180859c993d1SWarner Losh win_xor_br_write(base, i, e, 0); 180959c993d1SWarner Losh win_xor_sz_write(base, i, e, 0); 181059c993d1SWarner Losh } 181159c993d1SWarner Losh 181259c993d1SWarner Losh if (win_xor_can_remap(i) == 1) 181359c993d1SWarner Losh win_xor_har_write(base, i, e, 0); 181459c993d1SWarner Losh 181559c993d1SWarner Losh for (i = 0; i < MV_XOR_CHAN_MAX; i++) { 181659c993d1SWarner Losh win_xor_ctrl_write(base, i, e, 0); 181759c993d1SWarner Losh xor_active_dram(base, i, e, &window); 181859c993d1SWarner Losh } 181959c993d1SWarner Losh 182059c993d1SWarner Losh /* 182159c993d1SWarner Losh * Remaining targets -- from a statically defined table 182259c993d1SWarner Losh */ 182359c993d1SWarner Losh for (i = 0; i < xor_wins_no; i++) 182459c993d1SWarner Losh if (xor_wins[i].target > 0) { 182559c993d1SWarner Losh br = (xor_wins[i].base & 0xffff0000) | 182659c993d1SWarner Losh (xor_wins[i].attr << 8) | 182759c993d1SWarner Losh xor_wins[i].target; 182859c993d1SWarner Losh sz = ((xor_wins[i].size - 1) & 0xffff0000); 182959c993d1SWarner Losh 183059c993d1SWarner Losh /* Set the first free XOR window */ 183159c993d1SWarner Losh for (z = 0; z < MV_WIN_XOR_MAX; z++) { 183259c993d1SWarner Losh if (xor_ctrl_read(base, z, 0, e) && 183359c993d1SWarner Losh xor_ctrl_read(base, z, 1, e)) 183459c993d1SWarner Losh continue; 183559c993d1SWarner Losh 183659c993d1SWarner Losh /* Configure window */ 183759c993d1SWarner Losh win_xor_br_write(base, z, e, br); 183859c993d1SWarner Losh win_xor_sz_write(base, z, e, sz); 183959c993d1SWarner Losh if (win_xor_can_remap(z) && 184059c993d1SWarner Losh xor_wins[z].remap >= 0) 184159c993d1SWarner Losh win_xor_har_write(base, z, e, 184259c993d1SWarner Losh xor_wins[z].remap); 184359c993d1SWarner Losh 184459c993d1SWarner Losh /* Set protection RW on all channels */ 184559c993d1SWarner Losh xor_set_prot(base, z, e, 0x3); 184659c993d1SWarner Losh 184759c993d1SWarner Losh /* Enable window */ 184859c993d1SWarner Losh xor_ctrl_write(base, z, 0, e, 1); 184959c993d1SWarner Losh xor_ctrl_write(base, z, 1, e, 1); 185059c993d1SWarner Losh break; 185159c993d1SWarner Losh } 185259c993d1SWarner Losh } 185359c993d1SWarner Losh } 185459c993d1SWarner Losh } 185559c993d1SWarner Losh 185659c993d1SWarner Losh int 185759c993d1SWarner Losh decode_win_xor_valid(void) 185859c993d1SWarner Losh { 185959c993d1SWarner Losh const struct decode_win *wintab; 186059c993d1SWarner Losh int c, i, j, rv; 186159c993d1SWarner Losh uint32_t b, e, s; 186259c993d1SWarner Losh 186359c993d1SWarner Losh if (xor_wins_no > MV_WIN_XOR_MAX) { 186459c993d1SWarner Losh printf("XOR windows: too many entries: %d\n", xor_wins_no); 186559c993d1SWarner Losh return (0); 186659c993d1SWarner Losh } 186759c993d1SWarner Losh for (i = 0, c = 0; i < MV_WIN_DDR_MAX; i++) 186859c993d1SWarner Losh if (ddr_is_active(i)) 186959c993d1SWarner Losh c++; 187059c993d1SWarner Losh 187159c993d1SWarner Losh if (xor_wins_no > (MV_WIN_XOR_MAX - c)) { 187259c993d1SWarner Losh printf("XOR windows: too many entries: %d, available: %d\n", 187359c993d1SWarner Losh xor_wins_no, MV_WIN_IDMA_MAX - c); 187459c993d1SWarner Losh return (0); 187559c993d1SWarner Losh } 187659c993d1SWarner Losh 187759c993d1SWarner Losh wintab = xor_wins; 187859c993d1SWarner Losh rv = 1; 187959c993d1SWarner Losh for (i = 0; i < xor_wins_no; i++, wintab++) { 188059c993d1SWarner Losh 188159c993d1SWarner Losh if (wintab->target == 0) { 188259c993d1SWarner Losh printf("XOR window#%d: DDR target window is not " 188359c993d1SWarner Losh "supposed to be reprogrammed!\n", i); 188459c993d1SWarner Losh rv = 0; 188559c993d1SWarner Losh } 188659c993d1SWarner Losh 188759c993d1SWarner Losh if (wintab->remap >= 0 && win_cpu_can_remap(i) != 1) { 188859c993d1SWarner Losh printf("XOR window#%d: not capable of remapping, but " 188959c993d1SWarner Losh "val 0x%08x defined\n", i, wintab->remap); 189059c993d1SWarner Losh rv = 0; 189159c993d1SWarner Losh } 189259c993d1SWarner Losh 189359c993d1SWarner Losh s = wintab->size; 189459c993d1SWarner Losh b = wintab->base; 189559c993d1SWarner Losh e = b + s - 1; 189659c993d1SWarner Losh if (s > (0xFFFFFFFF - b + 1)) { 189759c993d1SWarner Losh /* 189859c993d1SWarner Losh * XXX this boundary check should account for 64bit 189959c993d1SWarner Losh * and remapping.. 190059c993d1SWarner Losh */ 190159c993d1SWarner Losh printf("XOR window#%d: no space for size 0x%08x at " 190259c993d1SWarner Losh "0x%08x\n", i, s, b); 190359c993d1SWarner Losh rv = 0; 190459c993d1SWarner Losh continue; 190559c993d1SWarner Losh } 190659c993d1SWarner Losh 190759c993d1SWarner Losh j = decode_win_overlap(i, xor_wins_no, &xor_wins[0]); 190859c993d1SWarner Losh if (j >= 0) { 190959c993d1SWarner Losh printf("XOR window#%d: (0x%08x - 0x%08x) overlaps " 191059c993d1SWarner Losh "with #%d (0x%08x - 0x%08x)\n", i, b, e, j, 191159c993d1SWarner Losh xor_wins[j].base, 191259c993d1SWarner Losh xor_wins[j].base + xor_wins[j].size - 1); 191359c993d1SWarner Losh rv = 0; 191459c993d1SWarner Losh } 191559c993d1SWarner Losh } 191659c993d1SWarner Losh 191759c993d1SWarner Losh return (rv); 191859c993d1SWarner Losh } 191959c993d1SWarner Losh 192059c993d1SWarner Losh void 192159c993d1SWarner Losh decode_win_xor_dump(u_long base) 192259c993d1SWarner Losh { 192359c993d1SWarner Losh int i, j; 192459c993d1SWarner Losh int e = 1; 192559c993d1SWarner Losh 192659c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_XOR)) 192759c993d1SWarner Losh return; 192859c993d1SWarner Losh 192959c993d1SWarner Losh for (j = 0; j < xor_max_eng(); j++, e--) { 193059c993d1SWarner Losh for (i = 0; i < MV_WIN_XOR_MAX; i++) { 193159c993d1SWarner Losh printf("XOR window#%d: b 0x%08x, s 0x%08x", i, 193259c993d1SWarner Losh win_xor_br_read(base, i, e), win_xor_sz_read(base, i, e)); 193359c993d1SWarner Losh 193459c993d1SWarner Losh if (win_xor_can_remap(i)) 193559c993d1SWarner Losh printf(", ha 0x%08x", win_xor_har_read(base, i, e)); 193659c993d1SWarner Losh 193759c993d1SWarner Losh printf("\n"); 193859c993d1SWarner Losh } 193959c993d1SWarner Losh for (i = 0; i < MV_XOR_CHAN_MAX; i++) 194059c993d1SWarner Losh printf("XOR control#%d: 0x%08x\n", i, 194159c993d1SWarner Losh win_xor_ctrl_read(base, i, e)); 194259c993d1SWarner Losh } 194359c993d1SWarner Losh } 194459c993d1SWarner Losh 194559c993d1SWarner Losh #else 194659c993d1SWarner Losh /* Provide dummy functions to satisfy the build for SoCs not equipped with XOR */ 194759c993d1SWarner Losh static int 194859c993d1SWarner Losh decode_win_xor_valid(void) 194959c993d1SWarner Losh { 195059c993d1SWarner Losh 195159c993d1SWarner Losh return (1); 195259c993d1SWarner Losh } 195359c993d1SWarner Losh 195459c993d1SWarner Losh static void 195559c993d1SWarner Losh decode_win_xor_setup(u_long base) 195659c993d1SWarner Losh { 195759c993d1SWarner Losh } 195859c993d1SWarner Losh 195959c993d1SWarner Losh static void 196059c993d1SWarner Losh decode_win_xor_dump(u_long base) 196159c993d1SWarner Losh { 196259c993d1SWarner Losh } 196359c993d1SWarner Losh #endif 196459c993d1SWarner Losh 196559c993d1SWarner Losh /************************************************************************** 196659c993d1SWarner Losh * SATA windows routines 196759c993d1SWarner Losh **************************************************************************/ 196859c993d1SWarner Losh static void 196959c993d1SWarner Losh decode_win_sata_setup(u_long base) 197059c993d1SWarner Losh { 197159c993d1SWarner Losh uint32_t cr, br; 197259c993d1SWarner Losh int i, j; 197359c993d1SWarner Losh 197459c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_SATA)) 197559c993d1SWarner Losh return; 197659c993d1SWarner Losh 197759c993d1SWarner Losh for (i = 0; i < MV_WIN_SATA_MAX; i++) { 197859c993d1SWarner Losh win_sata_cr_write(base, i, 0); 197959c993d1SWarner Losh win_sata_br_write(base, i, 0); 198059c993d1SWarner Losh } 198159c993d1SWarner Losh 198259c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) 198359c993d1SWarner Losh if (ddr_is_active(i)) { 198459c993d1SWarner Losh cr = ((ddr_size(i) - 1) & 0xffff0000) | 198559c993d1SWarner Losh (ddr_attr(i) << 8) | (ddr_target(i) << 4) | 1; 198659c993d1SWarner Losh br = ddr_base(i); 198759c993d1SWarner Losh 198859c993d1SWarner Losh /* Use the first available SATA window */ 198959c993d1SWarner Losh for (j = 0; j < MV_WIN_SATA_MAX; j++) { 199059c993d1SWarner Losh if ((win_sata_cr_read(base, j) & 1) != 0) 199159c993d1SWarner Losh continue; 199259c993d1SWarner Losh 199359c993d1SWarner Losh win_sata_br_write(base, j, br); 199459c993d1SWarner Losh win_sata_cr_write(base, j, cr); 199559c993d1SWarner Losh break; 199659c993d1SWarner Losh } 199759c993d1SWarner Losh } 199859c993d1SWarner Losh } 199959c993d1SWarner Losh 200059c993d1SWarner Losh static int 200159c993d1SWarner Losh decode_win_sata_valid(void) 200259c993d1SWarner Losh { 200359c993d1SWarner Losh uint32_t dev, rev; 200459c993d1SWarner Losh 200559c993d1SWarner Losh soc_id(&dev, &rev); 200659c993d1SWarner Losh if (dev == MV_DEV_88F5281) 200759c993d1SWarner Losh return (1); 200859c993d1SWarner Losh 200959c993d1SWarner Losh return (decode_win_can_cover_ddr(MV_WIN_SATA_MAX)); 201059c993d1SWarner Losh } 201159c993d1SWarner Losh 201259c993d1SWarner Losh /************************************************************************** 201359c993d1SWarner Losh * FDT parsing routines. 201459c993d1SWarner Losh **************************************************************************/ 201559c993d1SWarner Losh 201659c993d1SWarner Losh static int 201759c993d1SWarner Losh fdt_get_ranges(const char *nodename, void *buf, int size, int *tuples, 201859c993d1SWarner Losh int *tuplesize) 201959c993d1SWarner Losh { 202059c993d1SWarner Losh phandle_t node; 202159c993d1SWarner Losh pcell_t addr_cells, par_addr_cells, size_cells; 202259c993d1SWarner Losh int len, tuple_size, tuples_count; 202359c993d1SWarner Losh 202459c993d1SWarner Losh node = OF_finddevice(nodename); 202559c993d1SWarner Losh if (node == -1) 202659c993d1SWarner Losh return (EINVAL); 202759c993d1SWarner Losh 202859c993d1SWarner Losh if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0) 202959c993d1SWarner Losh return (ENXIO); 203059c993d1SWarner Losh 203159c993d1SWarner Losh par_addr_cells = fdt_parent_addr_cells(node); 203259c993d1SWarner Losh if (par_addr_cells > 2) 203359c993d1SWarner Losh return (ERANGE); 203459c993d1SWarner Losh 203559c993d1SWarner Losh tuple_size = sizeof(pcell_t) * (addr_cells + par_addr_cells + 203659c993d1SWarner Losh size_cells); 203759c993d1SWarner Losh 203859c993d1SWarner Losh /* Note the OF_getprop_alloc() cannot be used at this early stage. */ 203959c993d1SWarner Losh len = OF_getprop(node, "ranges", buf, size); 204059c993d1SWarner Losh 204159c993d1SWarner Losh /* 204259c993d1SWarner Losh * XXX this does not handle the empty 'ranges;' case, which is 204359c993d1SWarner Losh * legitimate and should be allowed. 204459c993d1SWarner Losh */ 204559c993d1SWarner Losh tuples_count = len / tuple_size; 204659c993d1SWarner Losh if (tuples_count <= 0) 204759c993d1SWarner Losh return (ERANGE); 204859c993d1SWarner Losh 20491f7f3314SRuslan Bukin if (par_addr_cells > 2 || addr_cells > 2 || size_cells > 2) 205059c993d1SWarner Losh return (ERANGE); 205159c993d1SWarner Losh 205259c993d1SWarner Losh *tuples = tuples_count; 205359c993d1SWarner Losh *tuplesize = tuple_size; 205459c993d1SWarner Losh return (0); 205559c993d1SWarner Losh } 205659c993d1SWarner Losh 205759c993d1SWarner Losh static int 205859c993d1SWarner Losh win_cpu_from_dt(void) 205959c993d1SWarner Losh { 206059c993d1SWarner Losh pcell_t ranges[48]; 206159c993d1SWarner Losh phandle_t node; 206259c993d1SWarner Losh int i, entry_size, err, t, tuple_size, tuples; 206359c993d1SWarner Losh u_long sram_base, sram_size; 206459c993d1SWarner Losh 206559c993d1SWarner Losh t = 0; 206659c993d1SWarner Losh /* Retrieve 'ranges' property of '/localbus' node. */ 206759c993d1SWarner Losh if ((err = fdt_get_ranges("/localbus", ranges, sizeof(ranges), 206859c993d1SWarner Losh &tuples, &tuple_size)) == 0) { 206959c993d1SWarner Losh /* 207059c993d1SWarner Losh * Fill CPU decode windows table. 207159c993d1SWarner Losh */ 207259c993d1SWarner Losh bzero((void *)&cpu_win_tbl, sizeof(cpu_win_tbl)); 207359c993d1SWarner Losh 207459c993d1SWarner Losh entry_size = tuple_size / sizeof(pcell_t); 207559c993d1SWarner Losh cpu_wins_no = tuples; 207659c993d1SWarner Losh 207759c993d1SWarner Losh for (i = 0, t = 0; t < tuples; i += entry_size, t++) { 207859c993d1SWarner Losh cpu_win_tbl[t].target = 1; 207959c993d1SWarner Losh cpu_win_tbl[t].attr = fdt32_to_cpu(ranges[i + 1]); 208059c993d1SWarner Losh cpu_win_tbl[t].base = fdt32_to_cpu(ranges[i + 2]); 208159c993d1SWarner Losh cpu_win_tbl[t].size = fdt32_to_cpu(ranges[i + 3]); 208259c993d1SWarner Losh cpu_win_tbl[t].remap = ~0; 208359c993d1SWarner Losh debugf("target = 0x%0x attr = 0x%0x base = 0x%0x " 208459c993d1SWarner Losh "size = 0x%0x remap = 0x%0x\n", 208559c993d1SWarner Losh cpu_win_tbl[t].target, 208659c993d1SWarner Losh cpu_win_tbl[t].attr, cpu_win_tbl[t].base, 208759c993d1SWarner Losh cpu_win_tbl[t].size, cpu_win_tbl[t].remap); 208859c993d1SWarner Losh } 208959c993d1SWarner Losh } 209059c993d1SWarner Losh 209159c993d1SWarner Losh /* 209259c993d1SWarner Losh * Retrieve CESA SRAM data. 209359c993d1SWarner Losh */ 209459c993d1SWarner Losh if ((node = OF_finddevice("sram")) != -1) 209559c993d1SWarner Losh if (fdt_is_compatible(node, "mrvl,cesa-sram")) 209659c993d1SWarner Losh goto moveon; 209759c993d1SWarner Losh 209859c993d1SWarner Losh if ((node = OF_finddevice("/")) == 0) 209959c993d1SWarner Losh return (ENXIO); 210059c993d1SWarner Losh 210159c993d1SWarner Losh if ((node = fdt_find_compatible(node, "mrvl,cesa-sram", 0)) == 0) 210259c993d1SWarner Losh /* SRAM block is not always present. */ 210359c993d1SWarner Losh return (0); 210459c993d1SWarner Losh moveon: 210559c993d1SWarner Losh sram_base = sram_size = 0; 210659c993d1SWarner Losh if (fdt_regsize(node, &sram_base, &sram_size) != 0) 210759c993d1SWarner Losh return (EINVAL); 210859c993d1SWarner Losh 210959c993d1SWarner Losh cpu_win_tbl[t].target = MV_WIN_CESA_TARGET; 21105d7cb9a8SZbigniew Bodek #ifdef SOC_MV_ARMADA38X 21115d7cb9a8SZbigniew Bodek cpu_win_tbl[t].attr = MV_WIN_CESA_ATTR(0); 21125d7cb9a8SZbigniew Bodek #else 21135d7cb9a8SZbigniew Bodek cpu_win_tbl[t].attr = MV_WIN_CESA_ATTR(1); 21145d7cb9a8SZbigniew Bodek #endif 21155d7cb9a8SZbigniew Bodek cpu_win_tbl[t].base = sram_base; 21165d7cb9a8SZbigniew Bodek cpu_win_tbl[t].size = sram_size; 21175d7cb9a8SZbigniew Bodek cpu_win_tbl[t].remap = ~0; 21185d7cb9a8SZbigniew Bodek cpu_wins_no++; 21195d7cb9a8SZbigniew Bodek debugf("sram: base = 0x%0lx size = 0x%0lx\n", sram_base, sram_size); 21205d7cb9a8SZbigniew Bodek 21215d7cb9a8SZbigniew Bodek /* Check if there is a second CESA node */ 21225d7cb9a8SZbigniew Bodek while ((node = OF_peer(node)) != 0) { 21235d7cb9a8SZbigniew Bodek if (fdt_is_compatible(node, "mrvl,cesa-sram")) { 21245d7cb9a8SZbigniew Bodek if (fdt_regsize(node, &sram_base, &sram_size) != 0) 21255d7cb9a8SZbigniew Bodek return (EINVAL); 21265d7cb9a8SZbigniew Bodek break; 21275d7cb9a8SZbigniew Bodek } 21285d7cb9a8SZbigniew Bodek } 21295d7cb9a8SZbigniew Bodek 21305d7cb9a8SZbigniew Bodek if (node == 0) 21315d7cb9a8SZbigniew Bodek return (0); 21325d7cb9a8SZbigniew Bodek 21335d7cb9a8SZbigniew Bodek t++; 21345d7cb9a8SZbigniew Bodek if (t >= ((sizeof(cpu_win_tbl))/(sizeof(cpu_win_tbl[0])))) { 21355d7cb9a8SZbigniew Bodek debugf("cannot fit CESA tuple into cpu_win_tbl\n"); 21365d7cb9a8SZbigniew Bodek return (ENOMEM); 21375d7cb9a8SZbigniew Bodek } 21385d7cb9a8SZbigniew Bodek 21395d7cb9a8SZbigniew Bodek /* Configure window for CESA1 */ 21405d7cb9a8SZbigniew Bodek cpu_win_tbl[t].target = MV_WIN_CESA_TARGET; 214159c993d1SWarner Losh cpu_win_tbl[t].attr = MV_WIN_CESA_ATTR(1); 214259c993d1SWarner Losh cpu_win_tbl[t].base = sram_base; 214359c993d1SWarner Losh cpu_win_tbl[t].size = sram_size; 214459c993d1SWarner Losh cpu_win_tbl[t].remap = ~0; 214559c993d1SWarner Losh cpu_wins_no++; 214659c993d1SWarner Losh debugf("sram: base = 0x%0lx size = 0x%0lx\n", sram_base, sram_size); 214759c993d1SWarner Losh 214859c993d1SWarner Losh return (0); 214959c993d1SWarner Losh } 215059c993d1SWarner Losh 215159c993d1SWarner Losh static int 215259c993d1SWarner Losh fdt_win_setup(void) 215359c993d1SWarner Losh { 215459c993d1SWarner Losh phandle_t node, child; 215559c993d1SWarner Losh struct soc_node_spec *soc_node; 215659c993d1SWarner Losh u_long size, base; 215759c993d1SWarner Losh int err, i; 215859c993d1SWarner Losh 215959c993d1SWarner Losh node = OF_finddevice("/"); 216059c993d1SWarner Losh if (node == -1) 216159c993d1SWarner Losh panic("fdt_win_setup: no root node"); 216259c993d1SWarner Losh 216359c993d1SWarner Losh /* 216459c993d1SWarner Losh * Traverse through all children of root and simple-bus nodes. 216559c993d1SWarner Losh * For each found device retrieve decode windows data (if applicable). 216659c993d1SWarner Losh */ 216759c993d1SWarner Losh child = OF_child(node); 216859c993d1SWarner Losh while (child != 0) { 216959c993d1SWarner Losh for (i = 0; soc_nodes[i].compat != NULL; i++) { 217059c993d1SWarner Losh 217159c993d1SWarner Losh soc_node = &soc_nodes[i]; 217259c993d1SWarner Losh 217359c993d1SWarner Losh if (!fdt_is_compatible(child, soc_node->compat)) 217459c993d1SWarner Losh continue; 217559c993d1SWarner Losh 217659c993d1SWarner Losh err = fdt_regsize(child, &base, &size); 217759c993d1SWarner Losh if (err != 0) 217859c993d1SWarner Losh return (err); 217959c993d1SWarner Losh 218059c993d1SWarner Losh base = (base & 0x000fffff) | fdt_immr_va; 218159c993d1SWarner Losh if (soc_node->decode_handler != NULL) 218259c993d1SWarner Losh soc_node->decode_handler(base); 218359c993d1SWarner Losh else 218459c993d1SWarner Losh return (ENXIO); 218559c993d1SWarner Losh 218659c993d1SWarner Losh if (MV_DUMP_WIN && (soc_node->dump_handler != NULL)) 218759c993d1SWarner Losh soc_node->dump_handler(base); 218859c993d1SWarner Losh } 218959c993d1SWarner Losh 219059c993d1SWarner Losh /* 219159c993d1SWarner Losh * Once done with root-level children let's move down to 219259c993d1SWarner Losh * simple-bus and its children. 219359c993d1SWarner Losh */ 219459c993d1SWarner Losh child = OF_peer(child); 219559c993d1SWarner Losh if ((child == 0) && (node == OF_finddevice("/"))) { 2196b2ea73e3SZbigniew Bodek node = fdt_find_compatible(node, "simple-bus", 0); 219759c993d1SWarner Losh if (node == 0) 219859c993d1SWarner Losh return (ENXIO); 219959c993d1SWarner Losh child = OF_child(node); 220059c993d1SWarner Losh } 220134a3d2c6SWojciech Macek /* 220234a3d2c6SWojciech Macek * Next, move one more level down to internal-regs node (if 220334a3d2c6SWojciech Macek * it is present) and its children. This node also have 220434a3d2c6SWojciech Macek * "simple-bus" compatible. 220534a3d2c6SWojciech Macek */ 220634a3d2c6SWojciech Macek if ((child == 0) && (node == OF_finddevice("simple-bus"))) { 220734a3d2c6SWojciech Macek node = fdt_find_compatible(node, "simple-bus", 0); 220834a3d2c6SWojciech Macek if (node == 0) 220934a3d2c6SWojciech Macek return (0); 221034a3d2c6SWojciech Macek child = OF_child(node); 221134a3d2c6SWojciech Macek } 221259c993d1SWarner Losh } 221359c993d1SWarner Losh 221459c993d1SWarner Losh return (0); 221559c993d1SWarner Losh } 221659c993d1SWarner Losh 221759c993d1SWarner Losh static void 221859c993d1SWarner Losh fdt_fixup_busfreq(phandle_t root) 221959c993d1SWarner Losh { 222059c993d1SWarner Losh phandle_t sb; 222159c993d1SWarner Losh pcell_t freq; 222259c993d1SWarner Losh 222359c993d1SWarner Losh freq = cpu_to_fdt32(get_tclk()); 222459c993d1SWarner Losh 222559c993d1SWarner Losh /* 222659c993d1SWarner Losh * Fix bus speed in cpu node 222759c993d1SWarner Losh */ 222859c993d1SWarner Losh if ((sb = OF_finddevice("cpu")) != 0) 222959c993d1SWarner Losh if (fdt_is_compatible_strict(sb, "ARM,88VS584")) 223059c993d1SWarner Losh OF_setprop(sb, "bus-frequency", (void *)&freq, 223159c993d1SWarner Losh sizeof(freq)); 223259c993d1SWarner Losh 223359c993d1SWarner Losh /* 223459c993d1SWarner Losh * This fixup sets the simple-bus bus-frequency property. 223559c993d1SWarner Losh */ 223659c993d1SWarner Losh if ((sb = fdt_find_compatible(root, "simple-bus", 1)) != 0) 223759c993d1SWarner Losh OF_setprop(sb, "bus-frequency", (void *)&freq, sizeof(freq)); 223859c993d1SWarner Losh } 223959c993d1SWarner Losh 224059c993d1SWarner Losh static void 224159c993d1SWarner Losh fdt_fixup_ranges(phandle_t root) 224259c993d1SWarner Losh { 224359c993d1SWarner Losh phandle_t node; 224459c993d1SWarner Losh pcell_t par_addr_cells, addr_cells, size_cells; 224559c993d1SWarner Losh pcell_t ranges[3], reg[2], *rangesptr; 224659c993d1SWarner Losh int len, tuple_size, tuples_count; 224759c993d1SWarner Losh uint32_t base; 224859c993d1SWarner Losh 224959c993d1SWarner Losh /* Fix-up SoC ranges according to real fdt_immr_pa */ 225059c993d1SWarner Losh if ((node = fdt_find_compatible(root, "simple-bus", 1)) != 0) { 225159c993d1SWarner Losh if (fdt_addrsize_cells(node, &addr_cells, &size_cells) == 0 && 225259c993d1SWarner Losh (par_addr_cells = fdt_parent_addr_cells(node) <= 2)) { 225359c993d1SWarner Losh tuple_size = sizeof(pcell_t) * (par_addr_cells + 225459c993d1SWarner Losh addr_cells + size_cells); 225559c993d1SWarner Losh len = OF_getprop(node, "ranges", ranges, 225659c993d1SWarner Losh sizeof(ranges)); 225759c993d1SWarner Losh tuples_count = len / tuple_size; 225859c993d1SWarner Losh /* Unexpected settings are not supported */ 225959c993d1SWarner Losh if (tuples_count != 1) 226059c993d1SWarner Losh goto fixup_failed; 226159c993d1SWarner Losh 226259c993d1SWarner Losh rangesptr = &ranges[0]; 226359c993d1SWarner Losh rangesptr += par_addr_cells; 226459c993d1SWarner Losh base = fdt_data_get((void *)rangesptr, addr_cells); 226559c993d1SWarner Losh *rangesptr = cpu_to_fdt32(fdt_immr_pa); 226659c993d1SWarner Losh if (OF_setprop(node, "ranges", (void *)&ranges[0], 226759c993d1SWarner Losh sizeof(ranges)) < 0) 226859c993d1SWarner Losh goto fixup_failed; 226959c993d1SWarner Losh } 227059c993d1SWarner Losh } 227159c993d1SWarner Losh 227259c993d1SWarner Losh /* Fix-up PCIe reg according to real PCIe registers' PA */ 227359c993d1SWarner Losh if ((node = fdt_find_compatible(root, "mrvl,pcie", 1)) != 0) { 227459c993d1SWarner Losh if (fdt_addrsize_cells(OF_parent(node), &par_addr_cells, 227559c993d1SWarner Losh &size_cells) == 0) { 227659c993d1SWarner Losh tuple_size = sizeof(pcell_t) * (par_addr_cells + 227759c993d1SWarner Losh size_cells); 227859c993d1SWarner Losh len = OF_getprop(node, "reg", reg, sizeof(reg)); 227959c993d1SWarner Losh tuples_count = len / tuple_size; 228059c993d1SWarner Losh /* Unexpected settings are not supported */ 228159c993d1SWarner Losh if (tuples_count != 1) 228259c993d1SWarner Losh goto fixup_failed; 228359c993d1SWarner Losh 228459c993d1SWarner Losh base = fdt_data_get((void *)®[0], par_addr_cells); 228559c993d1SWarner Losh base &= ~0xFF000000; 228659c993d1SWarner Losh base |= fdt_immr_pa; 228759c993d1SWarner Losh reg[0] = cpu_to_fdt32(base); 228859c993d1SWarner Losh if (OF_setprop(node, "reg", (void *)®[0], 228959c993d1SWarner Losh sizeof(reg)) < 0) 229059c993d1SWarner Losh goto fixup_failed; 229159c993d1SWarner Losh } 229259c993d1SWarner Losh } 229359c993d1SWarner Losh /* Fix-up succeeded. May return and continue */ 229459c993d1SWarner Losh return; 229559c993d1SWarner Losh 229659c993d1SWarner Losh fixup_failed: 229759c993d1SWarner Losh while (1) { 229859c993d1SWarner Losh /* 229959c993d1SWarner Losh * In case of any error while fixing ranges just hang. 230059c993d1SWarner Losh * 1. No message can be displayed yet since console 230159c993d1SWarner Losh * is not initialized. 230259c993d1SWarner Losh * 2. Going further will cause failure on bus_space_map() 230359c993d1SWarner Losh * relying on the wrong ranges or data abort when 230459c993d1SWarner Losh * accessing PCIe registers. 230559c993d1SWarner Losh */ 230659c993d1SWarner Losh } 230759c993d1SWarner Losh } 230859c993d1SWarner Losh 230959c993d1SWarner Losh struct fdt_fixup_entry fdt_fixup_table[] = { 231059c993d1SWarner Losh { "mrvl,DB-88F6281", &fdt_fixup_busfreq }, 231159c993d1SWarner Losh { "mrvl,DB-78460", &fdt_fixup_busfreq }, 231259c993d1SWarner Losh { "mrvl,DB-78460", &fdt_fixup_ranges }, 231359c993d1SWarner Losh { NULL, NULL } 231459c993d1SWarner Losh }; 231559c993d1SWarner Losh 231659c3cb81SAndrew Turner #ifndef INTRNG 231759c993d1SWarner Losh static int 231859c993d1SWarner Losh fdt_pic_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig, 231959c993d1SWarner Losh int *pol) 232059c993d1SWarner Losh { 232159c993d1SWarner Losh 232259c993d1SWarner Losh if (!fdt_is_compatible(node, "mrvl,pic") && 232359c993d1SWarner Losh !fdt_is_compatible(node, "mrvl,mpic")) 232459c993d1SWarner Losh return (ENXIO); 232559c993d1SWarner Losh 232659c993d1SWarner Losh *interrupt = fdt32_to_cpu(intr[0]); 232759c993d1SWarner Losh *trig = INTR_TRIGGER_CONFORM; 232859c993d1SWarner Losh *pol = INTR_POLARITY_CONFORM; 232959c993d1SWarner Losh 233059c993d1SWarner Losh return (0); 233159c993d1SWarner Losh } 233259c993d1SWarner Losh 233359c993d1SWarner Losh fdt_pic_decode_t fdt_pic_table[] = { 233481c8a263SZbigniew Bodek #ifdef SOC_MV_ARMADA38X 233581c8a263SZbigniew Bodek &gic_decode_fdt, 233681c8a263SZbigniew Bodek #endif 233759c993d1SWarner Losh &fdt_pic_decode_ic, 233859c993d1SWarner Losh NULL 233959c993d1SWarner Losh }; 2340647a3bacSAndrew Turner #endif 234159c993d1SWarner Losh 234259c993d1SWarner Losh uint64_t 234359c993d1SWarner Losh get_sar_value(void) 234459c993d1SWarner Losh { 234559c993d1SWarner Losh uint32_t sar_low, sar_high; 234659c993d1SWarner Losh 234759c993d1SWarner Losh #if defined(SOC_MV_ARMADAXP) 234859c993d1SWarner Losh sar_high = bus_space_read_4(fdtbus_bs_tag, MV_MISC_BASE, 234959c993d1SWarner Losh SAMPLE_AT_RESET_HI); 235059c993d1SWarner Losh sar_low = bus_space_read_4(fdtbus_bs_tag, MV_MISC_BASE, 235159c993d1SWarner Losh SAMPLE_AT_RESET_LO); 2352f8742b0dSZbigniew Bodek #elif defined(SOC_MV_ARMADA38X) 2353f8742b0dSZbigniew Bodek sar_high = 0; 2354f8742b0dSZbigniew Bodek sar_low = bus_space_read_4(fdtbus_bs_tag, MV_MISC_BASE, 2355f8742b0dSZbigniew Bodek SAMPLE_AT_RESET); 235659c993d1SWarner Losh #else 235759c993d1SWarner Losh /* 235859c993d1SWarner Losh * TODO: Add getting proper values for other SoC configurations 235959c993d1SWarner Losh */ 236059c993d1SWarner Losh sar_high = 0; 236159c993d1SWarner Losh sar_low = 0; 236259c993d1SWarner Losh #endif 236359c993d1SWarner Losh 236459c993d1SWarner Losh return (((uint64_t)sar_high << 32) | sar_low); 236559c993d1SWarner Losh } 2366