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> 4587acb7f8SAndrew Turner #include <dev/ofw/ofw_bus_subr.h> 4659c993d1SWarner Losh 4759c993d1SWarner Losh #include <machine/bus.h> 4859c993d1SWarner Losh #include <machine/fdt.h> 4959c993d1SWarner Losh #include <machine/vmparam.h> 5081c8a263SZbigniew Bodek #include <machine/intr.h> 5159c993d1SWarner Losh 5259c993d1SWarner Losh #include <arm/mv/mvreg.h> 5359c993d1SWarner Losh #include <arm/mv/mvvar.h> 5459c993d1SWarner Losh #include <arm/mv/mvwin.h> 5559c993d1SWarner Losh 5659c993d1SWarner Losh 5759c993d1SWarner Losh MALLOC_DEFINE(M_IDMA, "idma", "idma dma test memory"); 5859c993d1SWarner Losh 5959c993d1SWarner Losh #define IDMA_DEBUG 6059c993d1SWarner Losh #undef IDMA_DEBUG 6159c993d1SWarner Losh 6259c993d1SWarner Losh #define MAX_CPU_WIN 5 6359c993d1SWarner Losh 6459c993d1SWarner Losh #ifdef DEBUG 6559c993d1SWarner Losh #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 6659c993d1SWarner Losh printf(fmt,##args); } while (0) 6759c993d1SWarner Losh #else 6859c993d1SWarner Losh #define debugf(fmt, args...) 6959c993d1SWarner Losh #endif 7059c993d1SWarner Losh 7159c993d1SWarner Losh #ifdef DEBUG 7259c993d1SWarner Losh #define MV_DUMP_WIN 1 7359c993d1SWarner Losh #else 7459c993d1SWarner Losh #define MV_DUMP_WIN 0 7559c993d1SWarner Losh #endif 7659c993d1SWarner Losh 7759c993d1SWarner Losh static int win_eth_can_remap(int i); 7859c993d1SWarner Losh 79fcb93d74SWojciech Macek static int decode_win_cesa_valid(void); 8059c993d1SWarner Losh static int decode_win_cpu_valid(void); 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); 8698a2d78dSLuiz Otavio O Souza static int decode_win_sdhci_valid(void); 8759c993d1SWarner Losh 8859c993d1SWarner Losh static int decode_win_idma_valid(void); 8959c993d1SWarner Losh static int decode_win_xor_valid(void); 9059c993d1SWarner Losh 9159c993d1SWarner Losh static void decode_win_cpu_setup(void); 9259c993d1SWarner Losh #ifdef SOC_MV_ARMADAXP 9359c993d1SWarner Losh static int decode_win_sdram_fixup(void); 9459c993d1SWarner Losh #endif 95fcb93d74SWojciech Macek static void decode_win_cesa_setup(u_long); 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); 100ccd5b1b0SWojciech Macek static void decode_win_ahci_setup(u_long); 10198a2d78dSLuiz Otavio O Souza static void decode_win_sdhci_setup(u_long); 10259c993d1SWarner Losh 10359c993d1SWarner Losh static void decode_win_idma_setup(u_long); 10459c993d1SWarner Losh static void decode_win_xor_setup(u_long); 10559c993d1SWarner Losh 106fcb93d74SWojciech Macek static void decode_win_cesa_dump(u_long); 10759c993d1SWarner Losh static void decode_win_usb_dump(u_long); 10834a3d2c6SWojciech Macek static void decode_win_usb3_dump(u_long); 10959c993d1SWarner Losh static void decode_win_eth_dump(u_long base); 11059c993d1SWarner Losh static void decode_win_idma_dump(u_long base); 11159c993d1SWarner Losh static void decode_win_xor_dump(u_long base); 112518a87d7SWojciech Macek static void decode_win_ahci_dump(u_long base); 11398a2d78dSLuiz Otavio O Souza static void decode_win_sdhci_dump(u_long); 11459c993d1SWarner Losh 11559c993d1SWarner Losh static int fdt_get_ranges(const char *, void *, int, int *, int *); 11681c8a263SZbigniew Bodek #ifdef SOC_MV_ARMADA38X 11781c8a263SZbigniew Bodek int gic_decode_fdt(phandle_t iparent, pcell_t *intr, int *interrupt, 11881c8a263SZbigniew Bodek int *trig, int *pol); 11981c8a263SZbigniew Bodek #endif 12059c993d1SWarner Losh 12159c993d1SWarner Losh static int win_cpu_from_dt(void); 12259c993d1SWarner Losh static int fdt_win_setup(void); 12359c993d1SWarner Losh 12459c993d1SWarner Losh static uint32_t dev_mask = 0; 12559c993d1SWarner Losh static int cpu_wins_no = 0; 12659c993d1SWarner Losh static int eth_port = 0; 12759c993d1SWarner Losh static int usb_port = 0; 12859c993d1SWarner Losh 12959c993d1SWarner Losh static struct decode_win cpu_win_tbl[MAX_CPU_WIN]; 13059c993d1SWarner Losh 13159c993d1SWarner Losh const struct decode_win *cpu_wins = cpu_win_tbl; 13259c993d1SWarner Losh 13359c993d1SWarner Losh typedef void (*decode_win_setup_t)(u_long); 13459c993d1SWarner Losh typedef void (*dump_win_t)(u_long); 13559c993d1SWarner Losh 1360c79c0b1SZbigniew Bodek /* 1370c79c0b1SZbigniew Bodek * The power status of device feature is only supported on 1380c79c0b1SZbigniew Bodek * Kirkwood and Discovery SoCs. 1390c79c0b1SZbigniew Bodek */ 1400c79c0b1SZbigniew Bodek #if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY) 1410c79c0b1SZbigniew Bodek #define SOC_MV_POWER_STAT_SUPPORTED 1 1420c79c0b1SZbigniew Bodek #else 1430c79c0b1SZbigniew Bodek #define SOC_MV_POWER_STAT_SUPPORTED 0 1440c79c0b1SZbigniew Bodek #endif 1450c79c0b1SZbigniew Bodek 14659c993d1SWarner Losh struct soc_node_spec { 14759c993d1SWarner Losh const char *compat; 14859c993d1SWarner Losh decode_win_setup_t decode_handler; 14959c993d1SWarner Losh dump_win_t dump_handler; 15059c993d1SWarner Losh }; 15159c993d1SWarner Losh 15259c993d1SWarner Losh static struct soc_node_spec soc_nodes[] = { 15359c993d1SWarner Losh { "mrvl,ge", &decode_win_eth_setup, &decode_win_eth_dump }, 15459c993d1SWarner Losh { "mrvl,usb-ehci", &decode_win_usb_setup, &decode_win_usb_dump }, 155dbd1638aSZbigniew Bodek { "marvell,orion-ehci", &decode_win_usb_setup, &decode_win_usb_dump }, 15634a3d2c6SWojciech Macek { "marvell,armada-380-xhci", &decode_win_usb3_setup, &decode_win_usb3_dump }, 157518a87d7SWojciech Macek { "marvell,armada-380-ahci", &decode_win_ahci_setup, &decode_win_ahci_dump }, 15898a2d78dSLuiz Otavio O Souza { "marvell,armada-380-sdhci", &decode_win_sdhci_setup, &decode_win_sdhci_dump }, 15959c993d1SWarner Losh { "mrvl,sata", &decode_win_sata_setup, NULL }, 16059c993d1SWarner Losh { "mrvl,xor", &decode_win_xor_setup, &decode_win_xor_dump }, 16159c993d1SWarner Losh { "mrvl,idma", &decode_win_idma_setup, &decode_win_idma_dump }, 162fcb93d74SWojciech Macek { "mrvl,cesa", &decode_win_cesa_setup, &decode_win_cesa_dump }, 16359c993d1SWarner Losh { "mrvl,pcie", &decode_win_pcie_setup, NULL }, 16459c993d1SWarner Losh { NULL, NULL, NULL }, 16559c993d1SWarner Losh }; 16659c993d1SWarner Losh 167d177f4b8SAndrew Turner struct fdt_pm_mask_entry { 168d177f4b8SAndrew Turner char *compat; 169d177f4b8SAndrew Turner uint32_t mask; 170d177f4b8SAndrew Turner }; 171d177f4b8SAndrew Turner 172d177f4b8SAndrew Turner static struct fdt_pm_mask_entry fdt_pm_mask_table[] = { 17359c993d1SWarner Losh { "mrvl,ge", CPU_PM_CTRL_GE(0) }, 17459c993d1SWarner Losh { "mrvl,ge", CPU_PM_CTRL_GE(1) }, 17559c993d1SWarner Losh { "mrvl,usb-ehci", CPU_PM_CTRL_USB(0) }, 17659c993d1SWarner Losh { "mrvl,usb-ehci", CPU_PM_CTRL_USB(1) }, 17759c993d1SWarner Losh { "mrvl,usb-ehci", CPU_PM_CTRL_USB(2) }, 17859c993d1SWarner Losh { "mrvl,xor", CPU_PM_CTRL_XOR }, 17959c993d1SWarner Losh { "mrvl,sata", CPU_PM_CTRL_SATA }, 18059c993d1SWarner Losh 18159c993d1SWarner Losh { NULL, 0 } 18259c993d1SWarner Losh }; 18359c993d1SWarner Losh 18459c993d1SWarner Losh static __inline int 18559c993d1SWarner Losh pm_is_disabled(uint32_t mask) 18659c993d1SWarner Losh { 1870c79c0b1SZbigniew Bodek #if SOC_MV_POWER_STAT_SUPPORTED 18859c993d1SWarner Losh return (soc_power_ctrl_get(mask) == mask ? 0 : 1); 1890c79c0b1SZbigniew Bodek #else 1900c79c0b1SZbigniew Bodek return (0); 19159c993d1SWarner Losh #endif 19259c993d1SWarner Losh } 19359c993d1SWarner Losh 19459c993d1SWarner Losh /* 19559c993d1SWarner Losh * Disable device using power management register. 19659c993d1SWarner Losh * 1 - Device Power On 19759c993d1SWarner Losh * 0 - Device Power Off 19859c993d1SWarner Losh * Mask can be set in loader. 19959c993d1SWarner Losh * EXAMPLE: 20059c993d1SWarner Losh * loader> set hw.pm-disable-mask=0x2 20159c993d1SWarner Losh * 20259c993d1SWarner Losh * Common mask: 20359c993d1SWarner Losh * |-------------------------------| 20459c993d1SWarner Losh * | Device | Kirkwood | Discovery | 20559c993d1SWarner Losh * |-------------------------------| 20659c993d1SWarner Losh * | USB0 | 0x00008 | 0x020000 | 20759c993d1SWarner Losh * |-------------------------------| 20859c993d1SWarner Losh * | USB1 | - | 0x040000 | 20959c993d1SWarner Losh * |-------------------------------| 21059c993d1SWarner Losh * | USB2 | - | 0x080000 | 21159c993d1SWarner Losh * |-------------------------------| 21259c993d1SWarner Losh * | GE0 | 0x00001 | 0x000002 | 21359c993d1SWarner Losh * |-------------------------------| 21459c993d1SWarner Losh * | GE1 | - | 0x000004 | 21559c993d1SWarner Losh * |-------------------------------| 21659c993d1SWarner Losh * | IDMA | - | 0x100000 | 21759c993d1SWarner Losh * |-------------------------------| 21859c993d1SWarner Losh * | XOR | 0x10000 | 0x200000 | 21959c993d1SWarner Losh * |-------------------------------| 22059c993d1SWarner Losh * | CESA | 0x20000 | 0x400000 | 22159c993d1SWarner Losh * |-------------------------------| 22259c993d1SWarner Losh * | SATA | 0x04000 | 0x004000 | 22359c993d1SWarner Losh * --------------------------------| 22459c993d1SWarner Losh * This feature can be used only on Kirkwood and Discovery 22559c993d1SWarner Losh * machines. 22659c993d1SWarner Losh */ 22759c993d1SWarner Losh static __inline void 22859c993d1SWarner Losh pm_disable_device(int mask) 22959c993d1SWarner Losh { 23059c993d1SWarner Losh #ifdef DIAGNOSTIC 23159c993d1SWarner Losh uint32_t reg; 23259c993d1SWarner Losh 23359c993d1SWarner Losh reg = soc_power_ctrl_get(CPU_PM_CTRL_ALL); 23459c993d1SWarner Losh printf("Power Management Register: 0%x\n", reg); 23559c993d1SWarner Losh 23659c993d1SWarner Losh reg &= ~mask; 23759c993d1SWarner Losh soc_power_ctrl_set(reg); 23859c993d1SWarner Losh printf("Device %x is disabled\n", mask); 23959c993d1SWarner Losh 24059c993d1SWarner Losh reg = soc_power_ctrl_get(CPU_PM_CTRL_ALL); 24159c993d1SWarner Losh printf("Power Management Register: 0%x\n", reg); 24259c993d1SWarner Losh #endif 24359c993d1SWarner Losh } 24459c993d1SWarner Losh 24559c993d1SWarner Losh int 24659c993d1SWarner Losh fdt_pm(phandle_t node) 24759c993d1SWarner Losh { 24859c993d1SWarner Losh uint32_t cpu_pm_ctrl; 24959c993d1SWarner Losh int i, ena, compat; 25059c993d1SWarner Losh 25159c993d1SWarner Losh ena = 1; 25259c993d1SWarner Losh cpu_pm_ctrl = read_cpu_ctrl(CPU_PM_CTRL); 25359c993d1SWarner Losh for (i = 0; fdt_pm_mask_table[i].compat != NULL; i++) { 25459c993d1SWarner Losh if (dev_mask & (1 << i)) 25559c993d1SWarner Losh continue; 25659c993d1SWarner Losh 25787acb7f8SAndrew Turner compat = ofw_bus_node_is_compatible(node, 25887acb7f8SAndrew Turner fdt_pm_mask_table[i].compat); 25959c993d1SWarner Losh #if defined(SOC_MV_KIRKWOOD) 26059c993d1SWarner Losh if (compat && (cpu_pm_ctrl & fdt_pm_mask_table[i].mask)) { 26159c993d1SWarner Losh dev_mask |= (1 << i); 26259c993d1SWarner Losh ena = 0; 26359c993d1SWarner Losh break; 26459c993d1SWarner Losh } else if (compat) { 26559c993d1SWarner Losh dev_mask |= (1 << i); 26659c993d1SWarner Losh break; 26759c993d1SWarner Losh } 26859c993d1SWarner Losh #else 26959c993d1SWarner Losh if (compat && (~cpu_pm_ctrl & fdt_pm_mask_table[i].mask)) { 27059c993d1SWarner Losh dev_mask |= (1 << i); 27159c993d1SWarner Losh ena = 0; 27259c993d1SWarner Losh break; 27359c993d1SWarner Losh } else if (compat) { 27459c993d1SWarner Losh dev_mask |= (1 << i); 27559c993d1SWarner Losh break; 27659c993d1SWarner Losh } 27759c993d1SWarner Losh #endif 27859c993d1SWarner Losh } 27959c993d1SWarner Losh 28059c993d1SWarner Losh return (ena); 28159c993d1SWarner Losh } 28259c993d1SWarner Losh 28359c993d1SWarner Losh uint32_t 28459c993d1SWarner Losh read_cpu_ctrl(uint32_t reg) 28559c993d1SWarner Losh { 28659c993d1SWarner Losh 28759c993d1SWarner Losh return (bus_space_read_4(fdtbus_bs_tag, MV_CPU_CONTROL_BASE, reg)); 28859c993d1SWarner Losh } 28959c993d1SWarner Losh 29059c993d1SWarner Losh void 29159c993d1SWarner Losh write_cpu_ctrl(uint32_t reg, uint32_t val) 29259c993d1SWarner Losh { 29359c993d1SWarner Losh 29459c993d1SWarner Losh bus_space_write_4(fdtbus_bs_tag, MV_CPU_CONTROL_BASE, reg, val); 29559c993d1SWarner Losh } 29659c993d1SWarner Losh 297f8742b0dSZbigniew Bodek #if defined(SOC_MV_ARMADAXP) || defined(SOC_MV_ARMADA38X) 29859c993d1SWarner Losh uint32_t 29959c993d1SWarner Losh read_cpu_mp_clocks(uint32_t reg) 30059c993d1SWarner Losh { 30159c993d1SWarner Losh 30259c993d1SWarner Losh return (bus_space_read_4(fdtbus_bs_tag, MV_MP_CLOCKS_BASE, reg)); 30359c993d1SWarner Losh } 30459c993d1SWarner Losh 30559c993d1SWarner Losh void 30659c993d1SWarner Losh write_cpu_mp_clocks(uint32_t reg, uint32_t val) 30759c993d1SWarner Losh { 30859c993d1SWarner Losh 30959c993d1SWarner Losh bus_space_write_4(fdtbus_bs_tag, MV_MP_CLOCKS_BASE, reg, val); 31059c993d1SWarner Losh } 31159c993d1SWarner Losh 31259c993d1SWarner Losh uint32_t 31359c993d1SWarner Losh read_cpu_misc(uint32_t reg) 31459c993d1SWarner Losh { 31559c993d1SWarner Losh 31659c993d1SWarner Losh return (bus_space_read_4(fdtbus_bs_tag, MV_MISC_BASE, reg)); 31759c993d1SWarner Losh } 31859c993d1SWarner Losh 31959c993d1SWarner Losh void 32059c993d1SWarner Losh write_cpu_misc(uint32_t reg, uint32_t val) 32159c993d1SWarner Losh { 32259c993d1SWarner Losh 32359c993d1SWarner Losh bus_space_write_4(fdtbus_bs_tag, MV_MISC_BASE, reg, val); 32459c993d1SWarner Losh } 32559c993d1SWarner Losh #endif 32659c993d1SWarner Losh 32759c993d1SWarner Losh void 32859c993d1SWarner Losh cpu_reset(void) 32959c993d1SWarner Losh { 33059c993d1SWarner Losh 331f8742b0dSZbigniew Bodek #if defined(SOC_MV_ARMADAXP) || defined (SOC_MV_ARMADA38X) 33259c993d1SWarner Losh write_cpu_misc(RSTOUTn_MASK, SOFT_RST_OUT_EN); 33359c993d1SWarner Losh write_cpu_misc(SYSTEM_SOFT_RESET, SYS_SOFT_RST); 33459c993d1SWarner Losh #else 33559c993d1SWarner Losh write_cpu_ctrl(RSTOUTn_MASK, SOFT_RST_OUT_EN); 33659c993d1SWarner Losh write_cpu_ctrl(SYSTEM_SOFT_RESET, SYS_SOFT_RST); 33759c993d1SWarner Losh #endif 33859c993d1SWarner Losh while (1); 33959c993d1SWarner Losh } 34059c993d1SWarner Losh 34159c993d1SWarner Losh uint32_t 34259c993d1SWarner Losh cpu_extra_feat(void) 34359c993d1SWarner Losh { 34459c993d1SWarner Losh uint32_t dev, rev; 34559c993d1SWarner Losh uint32_t ef = 0; 34659c993d1SWarner Losh 34759c993d1SWarner Losh soc_id(&dev, &rev); 34859c993d1SWarner Losh 34959c993d1SWarner Losh switch (dev) { 35059c993d1SWarner Losh case MV_DEV_88F6281: 35159c993d1SWarner Losh case MV_DEV_88F6282: 35259c993d1SWarner Losh case MV_DEV_88RC8180: 35359c993d1SWarner Losh case MV_DEV_MV78100_Z0: 35459c993d1SWarner Losh case MV_DEV_MV78100: 35559c993d1SWarner Losh __asm __volatile("mrc p15, 1, %0, c15, c1, 0" : "=r" (ef)); 35659c993d1SWarner Losh break; 35759c993d1SWarner Losh case MV_DEV_88F5182: 35859c993d1SWarner Losh case MV_DEV_88F5281: 35959c993d1SWarner Losh __asm __volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (ef)); 36059c993d1SWarner Losh break; 36159c993d1SWarner Losh default: 36259c993d1SWarner Losh if (bootverbose) 36359c993d1SWarner Losh printf("This ARM Core does not support any extra features\n"); 36459c993d1SWarner Losh } 36559c993d1SWarner Losh 36659c993d1SWarner Losh return (ef); 36759c993d1SWarner Losh } 36859c993d1SWarner Losh 36959c993d1SWarner Losh /* 37059c993d1SWarner Losh * Get the power status of device. This feature is only supported on 37159c993d1SWarner Losh * Kirkwood and Discovery SoCs. 37259c993d1SWarner Losh */ 37359c993d1SWarner Losh uint32_t 37459c993d1SWarner Losh soc_power_ctrl_get(uint32_t mask) 37559c993d1SWarner Losh { 37659c993d1SWarner Losh 3770c79c0b1SZbigniew Bodek #if SOC_MV_POWER_STAT_SUPPORTED 37859c993d1SWarner Losh if (mask != CPU_PM_CTRL_NONE) 37959c993d1SWarner Losh mask &= read_cpu_ctrl(CPU_PM_CTRL); 38059c993d1SWarner Losh 38159c993d1SWarner Losh return (mask); 38259c993d1SWarner Losh #else 38359c993d1SWarner Losh return (mask); 38459c993d1SWarner Losh #endif 38559c993d1SWarner Losh } 38659c993d1SWarner Losh 38759c993d1SWarner Losh /* 38859c993d1SWarner Losh * Set the power status of device. This feature is only supported on 38959c993d1SWarner Losh * Kirkwood and Discovery SoCs. 39059c993d1SWarner Losh */ 39159c993d1SWarner Losh void 39259c993d1SWarner Losh soc_power_ctrl_set(uint32_t mask) 39359c993d1SWarner Losh { 39459c993d1SWarner Losh 3951eff4c0cSAndrew Turner #if !defined(SOC_MV_ORION) 39659c993d1SWarner Losh if (mask != CPU_PM_CTRL_NONE) 39759c993d1SWarner Losh write_cpu_ctrl(CPU_PM_CTRL, mask); 39859c993d1SWarner Losh #endif 39959c993d1SWarner Losh } 40059c993d1SWarner Losh 40159c993d1SWarner Losh void 40259c993d1SWarner Losh soc_id(uint32_t *dev, uint32_t *rev) 40359c993d1SWarner Losh { 40459c993d1SWarner Losh 40559c993d1SWarner Losh /* 40659c993d1SWarner Losh * Notice: system identifiers are available in the registers range of 40759c993d1SWarner Losh * PCIE controller, so using this function is only allowed (and 40859c993d1SWarner Losh * possible) after the internal registers range has been mapped in via 40930b72b68SRuslan Bukin * devmap_bootstrap(). 41059c993d1SWarner Losh */ 41159c993d1SWarner Losh *dev = bus_space_read_4(fdtbus_bs_tag, MV_PCIE_BASE, 0) >> 16; 41259c993d1SWarner Losh *rev = bus_space_read_4(fdtbus_bs_tag, MV_PCIE_BASE, 8) & 0xff; 41359c993d1SWarner Losh } 41459c993d1SWarner Losh 41559c993d1SWarner Losh static void 41659c993d1SWarner Losh soc_identify(void) 41759c993d1SWarner Losh { 41859c993d1SWarner Losh uint32_t d, r, size, mode; 41959c993d1SWarner Losh const char *dev; 42059c993d1SWarner Losh const char *rev; 42159c993d1SWarner Losh 42259c993d1SWarner Losh soc_id(&d, &r); 42359c993d1SWarner Losh 42459c993d1SWarner Losh printf("SOC: "); 42559c993d1SWarner Losh if (bootverbose) 42659c993d1SWarner Losh printf("(0x%4x:0x%02x) ", d, r); 42759c993d1SWarner Losh 42859c993d1SWarner Losh rev = ""; 42959c993d1SWarner Losh switch (d) { 43059c993d1SWarner Losh case MV_DEV_88F5181: 43159c993d1SWarner Losh dev = "Marvell 88F5181"; 43259c993d1SWarner Losh if (r == 3) 43359c993d1SWarner Losh rev = "B1"; 43459c993d1SWarner Losh break; 43559c993d1SWarner Losh case MV_DEV_88F5182: 43659c993d1SWarner Losh dev = "Marvell 88F5182"; 43759c993d1SWarner Losh if (r == 2) 43859c993d1SWarner Losh rev = "A2"; 43959c993d1SWarner Losh break; 44059c993d1SWarner Losh case MV_DEV_88F5281: 44159c993d1SWarner Losh dev = "Marvell 88F5281"; 44259c993d1SWarner Losh if (r == 4) 44359c993d1SWarner Losh rev = "D0"; 44459c993d1SWarner Losh else if (r == 5) 44559c993d1SWarner Losh rev = "D1"; 44659c993d1SWarner Losh else if (r == 6) 44759c993d1SWarner Losh rev = "D2"; 44859c993d1SWarner Losh break; 44959c993d1SWarner Losh case MV_DEV_88F6281: 45059c993d1SWarner Losh dev = "Marvell 88F6281"; 45159c993d1SWarner Losh if (r == 0) 45259c993d1SWarner Losh rev = "Z0"; 45359c993d1SWarner Losh else if (r == 2) 45459c993d1SWarner Losh rev = "A0"; 45559c993d1SWarner Losh else if (r == 3) 45659c993d1SWarner Losh rev = "A1"; 45759c993d1SWarner Losh break; 45859c993d1SWarner Losh case MV_DEV_88RC8180: 45959c993d1SWarner Losh dev = "Marvell 88RC8180"; 46059c993d1SWarner Losh break; 46159c993d1SWarner Losh case MV_DEV_88RC9480: 46259c993d1SWarner Losh dev = "Marvell 88RC9480"; 46359c993d1SWarner Losh break; 46459c993d1SWarner Losh case MV_DEV_88RC9580: 46559c993d1SWarner Losh dev = "Marvell 88RC9580"; 46659c993d1SWarner Losh break; 46759c993d1SWarner Losh case MV_DEV_88F6781: 46859c993d1SWarner Losh dev = "Marvell 88F6781"; 46959c993d1SWarner Losh if (r == 2) 47059c993d1SWarner Losh rev = "Y0"; 47159c993d1SWarner Losh break; 47259c993d1SWarner Losh case MV_DEV_88F6282: 47359c993d1SWarner Losh dev = "Marvell 88F6282"; 47459c993d1SWarner Losh if (r == 0) 47559c993d1SWarner Losh rev = "A0"; 47659c993d1SWarner Losh else if (r == 1) 47759c993d1SWarner Losh rev = "A1"; 47859c993d1SWarner Losh break; 479f8742b0dSZbigniew Bodek case MV_DEV_88F6828: 480f8742b0dSZbigniew Bodek dev = "Marvell 88F6828"; 481f8742b0dSZbigniew Bodek break; 482f8742b0dSZbigniew Bodek case MV_DEV_88F6820: 483f8742b0dSZbigniew Bodek dev = "Marvell 88F6820"; 484f8742b0dSZbigniew Bodek break; 485f8742b0dSZbigniew Bodek case MV_DEV_88F6810: 486f8742b0dSZbigniew Bodek dev = "Marvell 88F6810"; 487f8742b0dSZbigniew Bodek break; 48859c993d1SWarner Losh case MV_DEV_MV78100_Z0: 48959c993d1SWarner Losh dev = "Marvell MV78100 Z0"; 49059c993d1SWarner Losh break; 49159c993d1SWarner Losh case MV_DEV_MV78100: 49259c993d1SWarner Losh dev = "Marvell MV78100"; 49359c993d1SWarner Losh break; 49459c993d1SWarner Losh case MV_DEV_MV78160: 49559c993d1SWarner Losh dev = "Marvell MV78160"; 49659c993d1SWarner Losh break; 49759c993d1SWarner Losh case MV_DEV_MV78260: 49859c993d1SWarner Losh dev = "Marvell MV78260"; 49959c993d1SWarner Losh break; 50059c993d1SWarner Losh case MV_DEV_MV78460: 50159c993d1SWarner Losh dev = "Marvell MV78460"; 50259c993d1SWarner Losh break; 50359c993d1SWarner Losh default: 50459c993d1SWarner Losh dev = "UNKNOWN"; 50559c993d1SWarner Losh break; 50659c993d1SWarner Losh } 50759c993d1SWarner Losh 50859c993d1SWarner Losh printf("%s", dev); 50959c993d1SWarner Losh if (*rev != '\0') 51059c993d1SWarner Losh printf(" rev %s", rev); 51159c993d1SWarner Losh printf(", TClock %dMHz\n", get_tclk() / 1000 / 1000); 51259c993d1SWarner Losh 51359c993d1SWarner Losh mode = read_cpu_ctrl(CPU_CONFIG); 51459c993d1SWarner Losh printf(" Instruction cache prefetch %s, data cache prefetch %s\n", 51559c993d1SWarner Losh (mode & CPU_CONFIG_IC_PREF) ? "enabled" : "disabled", 51659c993d1SWarner Losh (mode & CPU_CONFIG_DC_PREF) ? "enabled" : "disabled"); 51759c993d1SWarner Losh 51859c993d1SWarner Losh switch (d) { 51959c993d1SWarner Losh case MV_DEV_88F6281: 52059c993d1SWarner Losh case MV_DEV_88F6282: 52159c993d1SWarner Losh mode = read_cpu_ctrl(CPU_L2_CONFIG) & CPU_L2_CONFIG_MODE; 52259c993d1SWarner Losh printf(" 256KB 4-way set-associative %s unified L2 cache\n", 52359c993d1SWarner Losh mode ? "write-through" : "write-back"); 52459c993d1SWarner Losh break; 52559c993d1SWarner Losh case MV_DEV_MV78100: 52659c993d1SWarner Losh mode = read_cpu_ctrl(CPU_CONTROL); 52759c993d1SWarner Losh size = mode & CPU_CONTROL_L2_SIZE; 52859c993d1SWarner Losh mode = mode & CPU_CONTROL_L2_MODE; 52959c993d1SWarner Losh printf(" %s set-associative %s unified L2 cache\n", 53059c993d1SWarner Losh size ? "256KB 4-way" : "512KB 8-way", 53159c993d1SWarner Losh mode ? "write-through" : "write-back"); 53259c993d1SWarner Losh break; 53359c993d1SWarner Losh default: 53459c993d1SWarner Losh break; 53559c993d1SWarner Losh } 53659c993d1SWarner Losh } 53759c993d1SWarner Losh 53859c993d1SWarner Losh static void 53959c993d1SWarner Losh platform_identify(void *dummy) 54059c993d1SWarner Losh { 54159c993d1SWarner Losh 54259c993d1SWarner Losh soc_identify(); 54359c993d1SWarner Losh 54459c993d1SWarner Losh /* 54559c993d1SWarner Losh * XXX Board identification e.g. read out from FPGA or similar should 54659c993d1SWarner Losh * go here 54759c993d1SWarner Losh */ 54859c993d1SWarner Losh } 54959c993d1SWarner Losh SYSINIT(platform_identify, SI_SUB_CPU, SI_ORDER_SECOND, platform_identify, 55059c993d1SWarner Losh NULL); 55159c993d1SWarner Losh 55259c993d1SWarner Losh #ifdef KDB 55359c993d1SWarner Losh static void 55459c993d1SWarner Losh mv_enter_debugger(void *dummy) 55559c993d1SWarner Losh { 55659c993d1SWarner Losh 55759c993d1SWarner Losh if (boothowto & RB_KDB) 55859c993d1SWarner Losh kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); 55959c993d1SWarner Losh } 56059c993d1SWarner Losh SYSINIT(mv_enter_debugger, SI_SUB_CPU, SI_ORDER_ANY, mv_enter_debugger, NULL); 56159c993d1SWarner Losh #endif 56259c993d1SWarner Losh 56359c993d1SWarner Losh int 56459c993d1SWarner Losh soc_decode_win(void) 56559c993d1SWarner Losh { 56659c993d1SWarner Losh uint32_t dev, rev; 56759c993d1SWarner Losh int mask, err; 56859c993d1SWarner Losh 56959c993d1SWarner Losh mask = 0; 57059c993d1SWarner Losh TUNABLE_INT_FETCH("hw.pm-disable-mask", &mask); 57159c993d1SWarner Losh 57259c993d1SWarner Losh if (mask != 0) 57359c993d1SWarner Losh pm_disable_device(mask); 57459c993d1SWarner Losh 57559c993d1SWarner Losh /* Retrieve data about physical addresses from device tree. */ 57659c993d1SWarner Losh if ((err = win_cpu_from_dt()) != 0) 57759c993d1SWarner Losh return (err); 57859c993d1SWarner Losh 57959c993d1SWarner Losh /* Retrieve our ID: some windows facilities vary between SoC models */ 58059c993d1SWarner Losh soc_id(&dev, &rev); 58159c993d1SWarner Losh 58259c993d1SWarner Losh #ifdef SOC_MV_ARMADAXP 58359c993d1SWarner Losh if ((err = decode_win_sdram_fixup()) != 0) 58459c993d1SWarner Losh return(err); 58559c993d1SWarner Losh #endif 58659c993d1SWarner Losh 58759c993d1SWarner Losh if (!decode_win_cpu_valid() || !decode_win_usb_valid() || 58859c993d1SWarner Losh !decode_win_eth_valid() || !decode_win_idma_valid() || 58959c993d1SWarner Losh !decode_win_pcie_valid() || !decode_win_sata_valid() || 59098a2d78dSLuiz Otavio O Souza !decode_win_xor_valid() || !decode_win_usb3_valid() || 591fcb93d74SWojciech Macek !decode_win_sdhci_valid() || !decode_win_cesa_valid()) 59259c993d1SWarner Losh return (EINVAL); 59359c993d1SWarner Losh 59459c993d1SWarner Losh decode_win_cpu_setup(); 59559c993d1SWarner Losh if (MV_DUMP_WIN) 59659c993d1SWarner Losh soc_dump_decode_win(); 59759c993d1SWarner Losh 59859c993d1SWarner Losh eth_port = 0; 59959c993d1SWarner Losh usb_port = 0; 60059c993d1SWarner Losh if ((err = fdt_win_setup()) != 0) 60159c993d1SWarner Losh return (err); 60259c993d1SWarner Losh 60359c993d1SWarner Losh return (0); 60459c993d1SWarner Losh } 60559c993d1SWarner Losh 60659c993d1SWarner Losh /************************************************************************** 60759c993d1SWarner Losh * Decode windows registers accessors 60859c993d1SWarner Losh **************************************************************************/ 60959c993d1SWarner Losh WIN_REG_IDX_RD(win_cpu, cr, MV_WIN_CPU_CTRL, MV_MBUS_BRIDGE_BASE) 61059c993d1SWarner Losh WIN_REG_IDX_RD(win_cpu, br, MV_WIN_CPU_BASE, MV_MBUS_BRIDGE_BASE) 61159c993d1SWarner Losh WIN_REG_IDX_RD(win_cpu, remap_l, MV_WIN_CPU_REMAP_LO, MV_MBUS_BRIDGE_BASE) 61259c993d1SWarner Losh WIN_REG_IDX_RD(win_cpu, remap_h, MV_WIN_CPU_REMAP_HI, MV_MBUS_BRIDGE_BASE) 61359c993d1SWarner Losh WIN_REG_IDX_WR(win_cpu, cr, MV_WIN_CPU_CTRL, MV_MBUS_BRIDGE_BASE) 61459c993d1SWarner Losh WIN_REG_IDX_WR(win_cpu, br, MV_WIN_CPU_BASE, MV_MBUS_BRIDGE_BASE) 61559c993d1SWarner Losh WIN_REG_IDX_WR(win_cpu, remap_l, MV_WIN_CPU_REMAP_LO, MV_MBUS_BRIDGE_BASE) 61659c993d1SWarner Losh WIN_REG_IDX_WR(win_cpu, remap_h, MV_WIN_CPU_REMAP_HI, MV_MBUS_BRIDGE_BASE) 61759c993d1SWarner Losh 618fcb93d74SWojciech Macek WIN_REG_BASE_IDX_RD(win_cesa, cr, MV_WIN_CESA_CTRL) 619fcb93d74SWojciech Macek WIN_REG_BASE_IDX_RD(win_cesa, br, MV_WIN_CESA_BASE) 620fcb93d74SWojciech Macek WIN_REG_BASE_IDX_WR(win_cesa, cr, MV_WIN_CESA_CTRL) 621fcb93d74SWojciech Macek WIN_REG_BASE_IDX_WR(win_cesa, br, MV_WIN_CESA_BASE) 622fcb93d74SWojciech Macek 62359c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_usb, cr, MV_WIN_USB_CTRL) 62459c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_usb, br, MV_WIN_USB_BASE) 62559c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_usb, cr, MV_WIN_USB_CTRL) 62659c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_usb, br, MV_WIN_USB_BASE) 62759c993d1SWarner Losh 62834a3d2c6SWojciech Macek #ifdef SOC_MV_ARMADA38X 62934a3d2c6SWojciech Macek WIN_REG_BASE_IDX_RD(win_usb3, cr, MV_WIN_USB3_CTRL) 63034a3d2c6SWojciech Macek WIN_REG_BASE_IDX_RD(win_usb3, br, MV_WIN_USB3_BASE) 63134a3d2c6SWojciech Macek WIN_REG_BASE_IDX_WR(win_usb3, cr, MV_WIN_USB3_CTRL) 63234a3d2c6SWojciech Macek WIN_REG_BASE_IDX_WR(win_usb3, br, MV_WIN_USB3_BASE) 63334a3d2c6SWojciech Macek #endif 63434a3d2c6SWojciech Macek 63559c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_eth, br, MV_WIN_ETH_BASE) 63659c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_eth, sz, MV_WIN_ETH_SIZE) 63759c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_eth, har, MV_WIN_ETH_REMAP) 63859c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_eth, br, MV_WIN_ETH_BASE) 63959c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_eth, sz, MV_WIN_ETH_SIZE) 64059c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_eth, har, MV_WIN_ETH_REMAP) 64159c993d1SWarner Losh 64259c993d1SWarner Losh WIN_REG_BASE_IDX_RD2(win_xor, br, MV_WIN_XOR_BASE) 64359c993d1SWarner Losh WIN_REG_BASE_IDX_RD2(win_xor, sz, MV_WIN_XOR_SIZE) 64459c993d1SWarner Losh WIN_REG_BASE_IDX_RD2(win_xor, har, MV_WIN_XOR_REMAP) 64559c993d1SWarner Losh WIN_REG_BASE_IDX_RD2(win_xor, ctrl, MV_WIN_XOR_CTRL) 64659c993d1SWarner Losh WIN_REG_BASE_IDX_WR2(win_xor, br, MV_WIN_XOR_BASE) 64759c993d1SWarner Losh WIN_REG_BASE_IDX_WR2(win_xor, sz, MV_WIN_XOR_SIZE) 64859c993d1SWarner Losh WIN_REG_BASE_IDX_WR2(win_xor, har, MV_WIN_XOR_REMAP) 64959c993d1SWarner Losh WIN_REG_BASE_IDX_WR2(win_xor, ctrl, MV_WIN_XOR_CTRL) 65059c993d1SWarner Losh 65159c993d1SWarner Losh WIN_REG_BASE_RD(win_eth, bare, 0x290) 65259c993d1SWarner Losh WIN_REG_BASE_RD(win_eth, epap, 0x294) 65359c993d1SWarner Losh WIN_REG_BASE_WR(win_eth, bare, 0x290) 65459c993d1SWarner Losh WIN_REG_BASE_WR(win_eth, epap, 0x294) 65559c993d1SWarner Losh 65659c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_pcie, cr, MV_WIN_PCIE_CTRL); 65759c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_pcie, br, MV_WIN_PCIE_BASE); 65859c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_pcie, remap, MV_WIN_PCIE_REMAP); 65959c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_pcie, cr, MV_WIN_PCIE_CTRL); 66059c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_pcie, br, MV_WIN_PCIE_BASE); 66159c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_pcie, remap, MV_WIN_PCIE_REMAP); 66259c993d1SWarner Losh WIN_REG_BASE_IDX_RD(pcie_bar, br, MV_PCIE_BAR_BASE); 66359c993d1SWarner Losh WIN_REG_BASE_IDX_WR(pcie_bar, br, MV_PCIE_BAR_BASE); 66459c993d1SWarner Losh WIN_REG_BASE_IDX_WR(pcie_bar, brh, MV_PCIE_BAR_BASE_H); 66559c993d1SWarner Losh WIN_REG_BASE_IDX_WR(pcie_bar, cr, MV_PCIE_BAR_CTRL); 66659c993d1SWarner Losh 66759c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_idma, br, MV_WIN_IDMA_BASE) 66859c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_idma, sz, MV_WIN_IDMA_SIZE) 66959c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_idma, har, MV_WIN_IDMA_REMAP) 67059c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_idma, cap, MV_WIN_IDMA_CAP) 67159c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_idma, br, MV_WIN_IDMA_BASE) 67259c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_idma, sz, MV_WIN_IDMA_SIZE) 67359c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_idma, har, MV_WIN_IDMA_REMAP) 67459c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_idma, cap, MV_WIN_IDMA_CAP) 67559c993d1SWarner Losh WIN_REG_BASE_RD(win_idma, bare, 0xa80) 67659c993d1SWarner Losh WIN_REG_BASE_WR(win_idma, bare, 0xa80) 67759c993d1SWarner Losh 67859c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_sata, cr, MV_WIN_SATA_CTRL); 67959c993d1SWarner Losh WIN_REG_BASE_IDX_RD(win_sata, br, MV_WIN_SATA_BASE); 68059c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_sata, cr, MV_WIN_SATA_CTRL); 68159c993d1SWarner Losh WIN_REG_BASE_IDX_WR(win_sata, br, MV_WIN_SATA_BASE); 682ccd5b1b0SWojciech Macek #if defined(SOC_MV_ARMADA38X) 683ccd5b1b0SWojciech Macek WIN_REG_BASE_IDX_RD(win_sata, sz, MV_WIN_SATA_SIZE); 684ccd5b1b0SWojciech Macek WIN_REG_BASE_IDX_WR(win_sata, sz, MV_WIN_SATA_SIZE); 685ccd5b1b0SWojciech Macek #endif 686ccd5b1b0SWojciech Macek 68798a2d78dSLuiz Otavio O Souza WIN_REG_BASE_IDX_RD(win_sdhci, cr, MV_WIN_SDHCI_CTRL); 68898a2d78dSLuiz Otavio O Souza WIN_REG_BASE_IDX_RD(win_sdhci, br, MV_WIN_SDHCI_BASE); 68998a2d78dSLuiz Otavio O Souza WIN_REG_BASE_IDX_WR(win_sdhci, cr, MV_WIN_SDHCI_CTRL); 69098a2d78dSLuiz Otavio O Souza WIN_REG_BASE_IDX_WR(win_sdhci, br, MV_WIN_SDHCI_BASE); 69198a2d78dSLuiz Otavio O Souza 69259c993d1SWarner Losh #ifndef SOC_MV_DOVE 69359c993d1SWarner Losh WIN_REG_IDX_RD(ddr, br, MV_WIN_DDR_BASE, MV_DDR_CADR_BASE) 69459c993d1SWarner Losh WIN_REG_IDX_RD(ddr, sz, MV_WIN_DDR_SIZE, MV_DDR_CADR_BASE) 69559c993d1SWarner Losh WIN_REG_IDX_WR(ddr, br, MV_WIN_DDR_BASE, MV_DDR_CADR_BASE) 69659c993d1SWarner Losh WIN_REG_IDX_WR(ddr, sz, MV_WIN_DDR_SIZE, MV_DDR_CADR_BASE) 69759c993d1SWarner Losh #else 69859c993d1SWarner Losh /* 69959c993d1SWarner Losh * On 88F6781 (Dove) SoC DDR Controller is accessed through 70059c993d1SWarner Losh * single MBUS <-> AXI bridge. In this case we provide emulated 70159c993d1SWarner Losh * ddr_br_read() and ddr_sz_read() functions to keep compatibility 70259c993d1SWarner Losh * with common decoding windows setup code. 70359c993d1SWarner Losh */ 70459c993d1SWarner Losh 70559c993d1SWarner Losh static inline uint32_t ddr_br_read(int i) 70659c993d1SWarner Losh { 70759c993d1SWarner Losh uint32_t mmap; 70859c993d1SWarner Losh 70959c993d1SWarner Losh /* Read Memory Address Map Register for CS i */ 71059c993d1SWarner Losh mmap = bus_space_read_4(fdtbus_bs_tag, MV_DDR_CADR_BASE + (i * 0x10), 0); 71159c993d1SWarner Losh 71259c993d1SWarner Losh /* Return CS i base address */ 71359c993d1SWarner Losh return (mmap & 0xFF000000); 71459c993d1SWarner Losh } 71559c993d1SWarner Losh 71659c993d1SWarner Losh static inline uint32_t ddr_sz_read(int i) 71759c993d1SWarner Losh { 71859c993d1SWarner Losh uint32_t mmap, size; 71959c993d1SWarner Losh 72059c993d1SWarner Losh /* Read Memory Address Map Register for CS i */ 72159c993d1SWarner Losh mmap = bus_space_read_4(fdtbus_bs_tag, MV_DDR_CADR_BASE + (i * 0x10), 0); 72259c993d1SWarner Losh 72359c993d1SWarner Losh /* Extract size of CS space in 64kB units */ 72459c993d1SWarner Losh size = (1 << ((mmap >> 16) & 0x0F)); 72559c993d1SWarner Losh 72659c993d1SWarner Losh /* Return CS size and enable/disable status */ 72759c993d1SWarner Losh return (((size - 1) << 16) | (mmap & 0x01)); 72859c993d1SWarner Losh } 72959c993d1SWarner Losh #endif 73059c993d1SWarner Losh 73159c993d1SWarner Losh /************************************************************************** 73259c993d1SWarner Losh * Decode windows helper routines 73359c993d1SWarner Losh **************************************************************************/ 73459c993d1SWarner Losh void 73559c993d1SWarner Losh soc_dump_decode_win(void) 73659c993d1SWarner Losh { 73759c993d1SWarner Losh uint32_t dev, rev; 73859c993d1SWarner Losh int i; 73959c993d1SWarner Losh 74059c993d1SWarner Losh soc_id(&dev, &rev); 74159c993d1SWarner Losh 74259c993d1SWarner Losh for (i = 0; i < MV_WIN_CPU_MAX; i++) { 74359c993d1SWarner Losh printf("CPU window#%d: c 0x%08x, b 0x%08x", i, 74459c993d1SWarner Losh win_cpu_cr_read(i), 74559c993d1SWarner Losh win_cpu_br_read(i)); 74659c993d1SWarner Losh 74759c993d1SWarner Losh if (win_cpu_can_remap(i)) 74859c993d1SWarner Losh printf(", rl 0x%08x, rh 0x%08x", 74959c993d1SWarner Losh win_cpu_remap_l_read(i), 75059c993d1SWarner Losh win_cpu_remap_h_read(i)); 75159c993d1SWarner Losh 75259c993d1SWarner Losh printf("\n"); 75359c993d1SWarner Losh } 75459c993d1SWarner Losh printf("Internal regs base: 0x%08x\n", 75559c993d1SWarner Losh bus_space_read_4(fdtbus_bs_tag, MV_INTREGS_BASE, 0)); 75659c993d1SWarner Losh 75759c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) 75859c993d1SWarner Losh printf("DDR CS#%d: b 0x%08x, s 0x%08x\n", i, 75959c993d1SWarner Losh ddr_br_read(i), ddr_sz_read(i)); 76059c993d1SWarner Losh } 76159c993d1SWarner Losh 76259c993d1SWarner Losh /************************************************************************** 76359c993d1SWarner Losh * CPU windows routines 76459c993d1SWarner Losh **************************************************************************/ 76559c993d1SWarner Losh int 76659c993d1SWarner Losh win_cpu_can_remap(int i) 76759c993d1SWarner Losh { 76859c993d1SWarner Losh uint32_t dev, rev; 76959c993d1SWarner Losh 77059c993d1SWarner Losh soc_id(&dev, &rev); 77159c993d1SWarner Losh 77259c993d1SWarner Losh /* Depending on the SoC certain windows have remap capability */ 77359c993d1SWarner Losh if ((dev == MV_DEV_88F5182 && i < 2) || 77459c993d1SWarner Losh (dev == MV_DEV_88F5281 && i < 4) || 77559c993d1SWarner Losh (dev == MV_DEV_88F6281 && i < 4) || 77659c993d1SWarner Losh (dev == MV_DEV_88F6282 && i < 4) || 777515af5ceSZbigniew Bodek (dev == MV_DEV_88F6828 && i < 20) || 778515af5ceSZbigniew Bodek (dev == MV_DEV_88F6820 && i < 20) || 779515af5ceSZbigniew Bodek (dev == MV_DEV_88F6810 && i < 20) || 78059c993d1SWarner Losh (dev == MV_DEV_88RC8180 && i < 2) || 78159c993d1SWarner Losh (dev == MV_DEV_88F6781 && i < 4) || 78259c993d1SWarner Losh (dev == MV_DEV_MV78100_Z0 && i < 8) || 78359c993d1SWarner Losh ((dev & MV_DEV_FAMILY_MASK) == MV_DEV_DISCOVERY && i < 8)) 78459c993d1SWarner Losh return (1); 78559c993d1SWarner Losh 78659c993d1SWarner Losh return (0); 78759c993d1SWarner Losh } 78859c993d1SWarner Losh 78959c993d1SWarner Losh /* XXX This should check for overlapping remap fields too.. */ 79059c993d1SWarner Losh int 79159c993d1SWarner Losh decode_win_overlap(int win, int win_no, const struct decode_win *wintab) 79259c993d1SWarner Losh { 79359c993d1SWarner Losh const struct decode_win *tab; 79459c993d1SWarner Losh int i; 79559c993d1SWarner Losh 79659c993d1SWarner Losh tab = wintab; 79759c993d1SWarner Losh 79859c993d1SWarner Losh for (i = 0; i < win_no; i++, tab++) { 79959c993d1SWarner Losh if (i == win) 80059c993d1SWarner Losh /* Skip self */ 80159c993d1SWarner Losh continue; 80259c993d1SWarner Losh 80359c993d1SWarner Losh if ((tab->base + tab->size - 1) < (wintab + win)->base) 80459c993d1SWarner Losh continue; 80559c993d1SWarner Losh 80659c993d1SWarner Losh else if (((wintab + win)->base + (wintab + win)->size - 1) < 80759c993d1SWarner Losh tab->base) 80859c993d1SWarner Losh continue; 80959c993d1SWarner Losh else 81059c993d1SWarner Losh return (i); 81159c993d1SWarner Losh } 81259c993d1SWarner Losh 81359c993d1SWarner Losh return (-1); 81459c993d1SWarner Losh } 81559c993d1SWarner Losh 81659c993d1SWarner Losh static int 81759c993d1SWarner Losh decode_win_cpu_valid(void) 81859c993d1SWarner Losh { 81959c993d1SWarner Losh int i, j, rv; 82059c993d1SWarner Losh uint32_t b, e, s; 82159c993d1SWarner Losh 82259c993d1SWarner Losh if (cpu_wins_no > MV_WIN_CPU_MAX) { 82359c993d1SWarner Losh printf("CPU windows: too many entries: %d\n", cpu_wins_no); 82459c993d1SWarner Losh return (0); 82559c993d1SWarner Losh } 82659c993d1SWarner Losh 82759c993d1SWarner Losh rv = 1; 82859c993d1SWarner Losh for (i = 0; i < cpu_wins_no; i++) { 82959c993d1SWarner Losh 83059c993d1SWarner Losh if (cpu_wins[i].target == 0) { 83159c993d1SWarner Losh printf("CPU window#%d: DDR target window is not " 83259c993d1SWarner Losh "supposed to be reprogrammed!\n", i); 83359c993d1SWarner Losh rv = 0; 83459c993d1SWarner Losh } 83559c993d1SWarner Losh 83659c993d1SWarner Losh if (cpu_wins[i].remap != ~0 && win_cpu_can_remap(i) != 1) { 83759c993d1SWarner Losh printf("CPU window#%d: not capable of remapping, but " 83859c993d1SWarner Losh "val 0x%08x defined\n", i, cpu_wins[i].remap); 83959c993d1SWarner Losh rv = 0; 84059c993d1SWarner Losh } 84159c993d1SWarner Losh 84259c993d1SWarner Losh s = cpu_wins[i].size; 84359c993d1SWarner Losh b = cpu_wins[i].base; 84459c993d1SWarner Losh e = b + s - 1; 84559c993d1SWarner Losh if (s > (0xFFFFFFFF - b + 1)) { 84659c993d1SWarner Losh /* 84759c993d1SWarner Losh * XXX this boundary check should account for 64bit 84859c993d1SWarner Losh * and remapping.. 84959c993d1SWarner Losh */ 85059c993d1SWarner Losh printf("CPU window#%d: no space for size 0x%08x at " 85159c993d1SWarner Losh "0x%08x\n", i, s, b); 85259c993d1SWarner Losh rv = 0; 85359c993d1SWarner Losh continue; 85459c993d1SWarner Losh } 85559c993d1SWarner Losh 856d9c9c81cSPedro F. Giffuni if (b != rounddown2(b, s)) { 85759c993d1SWarner Losh printf("CPU window#%d: address 0x%08x is not aligned " 85859c993d1SWarner Losh "to 0x%08x\n", i, b, s); 85959c993d1SWarner Losh rv = 0; 86059c993d1SWarner Losh continue; 86159c993d1SWarner Losh } 86259c993d1SWarner Losh 86359c993d1SWarner Losh j = decode_win_overlap(i, cpu_wins_no, &cpu_wins[0]); 86459c993d1SWarner Losh if (j >= 0) { 86559c993d1SWarner Losh printf("CPU window#%d: (0x%08x - 0x%08x) overlaps " 86659c993d1SWarner Losh "with #%d (0x%08x - 0x%08x)\n", i, b, e, j, 86759c993d1SWarner Losh cpu_wins[j].base, 86859c993d1SWarner Losh cpu_wins[j].base + cpu_wins[j].size - 1); 86959c993d1SWarner Losh rv = 0; 87059c993d1SWarner Losh } 87159c993d1SWarner Losh } 87259c993d1SWarner Losh 87359c993d1SWarner Losh return (rv); 87459c993d1SWarner Losh } 87559c993d1SWarner Losh 87659c993d1SWarner Losh int 87759c993d1SWarner Losh decode_win_cpu_set(int target, int attr, vm_paddr_t base, uint32_t size, 87859c993d1SWarner Losh vm_paddr_t remap) 87959c993d1SWarner Losh { 88059c993d1SWarner Losh uint32_t br, cr; 88159c993d1SWarner Losh int win, i; 88259c993d1SWarner Losh 88359c993d1SWarner Losh if (remap == ~0) { 88459c993d1SWarner Losh win = MV_WIN_CPU_MAX - 1; 88559c993d1SWarner Losh i = -1; 88659c993d1SWarner Losh } else { 88759c993d1SWarner Losh win = 0; 88859c993d1SWarner Losh i = 1; 88959c993d1SWarner Losh } 89059c993d1SWarner Losh 89159c993d1SWarner Losh while ((win >= 0) && (win < MV_WIN_CPU_MAX)) { 89259c993d1SWarner Losh cr = win_cpu_cr_read(win); 89359c993d1SWarner Losh if ((cr & MV_WIN_CPU_ENABLE_BIT) == 0) 89459c993d1SWarner Losh break; 89559c993d1SWarner Losh if ((cr & ((0xff << MV_WIN_CPU_ATTR_SHIFT) | 89659c993d1SWarner Losh (0x1f << MV_WIN_CPU_TARGET_SHIFT))) == 89759c993d1SWarner Losh ((attr << MV_WIN_CPU_ATTR_SHIFT) | 89859c993d1SWarner Losh (target << MV_WIN_CPU_TARGET_SHIFT))) 89959c993d1SWarner Losh break; 90059c993d1SWarner Losh win += i; 90159c993d1SWarner Losh } 90259c993d1SWarner Losh if ((win < 0) || (win >= MV_WIN_CPU_MAX) || 90359c993d1SWarner Losh ((remap != ~0) && (win_cpu_can_remap(win) == 0))) 90459c993d1SWarner Losh return (-1); 90559c993d1SWarner Losh 90659c993d1SWarner Losh br = base & 0xffff0000; 90759c993d1SWarner Losh win_cpu_br_write(win, br); 90859c993d1SWarner Losh 90959c993d1SWarner Losh if (win_cpu_can_remap(win)) { 91059c993d1SWarner Losh if (remap != ~0) { 91159c993d1SWarner Losh win_cpu_remap_l_write(win, remap & 0xffff0000); 91259c993d1SWarner Losh win_cpu_remap_h_write(win, 0); 91359c993d1SWarner Losh } else { 91459c993d1SWarner Losh /* 91559c993d1SWarner Losh * Remap function is not used for a given window 91659c993d1SWarner Losh * (capable of remapping) - set remap field with the 91759c993d1SWarner Losh * same value as base. 91859c993d1SWarner Losh */ 91959c993d1SWarner Losh win_cpu_remap_l_write(win, base & 0xffff0000); 92059c993d1SWarner Losh win_cpu_remap_h_write(win, 0); 92159c993d1SWarner Losh } 92259c993d1SWarner Losh } 92359c993d1SWarner Losh 92459c993d1SWarner Losh cr = ((size - 1) & 0xffff0000) | (attr << MV_WIN_CPU_ATTR_SHIFT) | 92559c993d1SWarner Losh (target << MV_WIN_CPU_TARGET_SHIFT) | MV_WIN_CPU_ENABLE_BIT; 92659c993d1SWarner Losh win_cpu_cr_write(win, cr); 92759c993d1SWarner Losh 92859c993d1SWarner Losh return (0); 92959c993d1SWarner Losh } 93059c993d1SWarner Losh 93159c993d1SWarner Losh static void 93259c993d1SWarner Losh decode_win_cpu_setup(void) 93359c993d1SWarner Losh { 93459c993d1SWarner Losh int i; 93559c993d1SWarner Losh 93659c993d1SWarner Losh /* Disable all CPU windows */ 93759c993d1SWarner Losh for (i = 0; i < MV_WIN_CPU_MAX; i++) { 93859c993d1SWarner Losh win_cpu_cr_write(i, 0); 93959c993d1SWarner Losh win_cpu_br_write(i, 0); 94059c993d1SWarner Losh if (win_cpu_can_remap(i)) { 94159c993d1SWarner Losh win_cpu_remap_l_write(i, 0); 94259c993d1SWarner Losh win_cpu_remap_h_write(i, 0); 94359c993d1SWarner Losh } 94459c993d1SWarner Losh } 94559c993d1SWarner Losh 94659c993d1SWarner Losh for (i = 0; i < cpu_wins_no; i++) 94759c993d1SWarner Losh if (cpu_wins[i].target > 0) 94859c993d1SWarner Losh decode_win_cpu_set(cpu_wins[i].target, 94959c993d1SWarner Losh cpu_wins[i].attr, cpu_wins[i].base, 95059c993d1SWarner Losh cpu_wins[i].size, cpu_wins[i].remap); 95159c993d1SWarner Losh 95259c993d1SWarner Losh } 95359c993d1SWarner Losh 95459c993d1SWarner Losh #ifdef SOC_MV_ARMADAXP 95559c993d1SWarner Losh static int 95659c993d1SWarner Losh decode_win_sdram_fixup(void) 95759c993d1SWarner Losh { 95859c993d1SWarner Losh struct mem_region mr[FDT_MEM_REGIONS]; 95959c993d1SWarner Losh uint8_t window_valid[MV_WIN_DDR_MAX]; 960e571e15cSWojciech Macek int mr_cnt, err, i, j; 96159c993d1SWarner Losh uint32_t valid_win_num = 0; 96259c993d1SWarner Losh 96359c993d1SWarner Losh /* Grab physical memory regions information from device tree. */ 964a4376069SAndrew Turner err = fdt_get_mem_regions(mr, &mr_cnt, NULL); 96559c993d1SWarner Losh if (err != 0) 96659c993d1SWarner Losh return (err); 96759c993d1SWarner Losh 96859c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) 96959c993d1SWarner Losh window_valid[i] = 0; 97059c993d1SWarner Losh 97159c993d1SWarner Losh /* Try to match entries from device tree with settings from u-boot */ 97259c993d1SWarner Losh for (i = 0; i < mr_cnt; i++) { 97359c993d1SWarner Losh for (j = 0; j < MV_WIN_DDR_MAX; j++) { 97459c993d1SWarner Losh if (ddr_is_active(j) && 97559c993d1SWarner Losh (ddr_base(j) == mr[i].mr_start) && 97659c993d1SWarner Losh (ddr_size(j) == mr[i].mr_size)) { 97759c993d1SWarner Losh window_valid[j] = 1; 97859c993d1SWarner Losh valid_win_num++; 97959c993d1SWarner Losh } 98059c993d1SWarner Losh } 98159c993d1SWarner Losh } 98259c993d1SWarner Losh 98359c993d1SWarner Losh if (mr_cnt != valid_win_num) 98459c993d1SWarner Losh return (EINVAL); 98559c993d1SWarner Losh 98659c993d1SWarner Losh /* Destroy windows without corresponding device tree entry */ 98759c993d1SWarner Losh for (j = 0; j < MV_WIN_DDR_MAX; j++) { 98859c993d1SWarner Losh if (ddr_is_active(j) && (window_valid[j] != 1)) { 98959c993d1SWarner Losh printf("Disabling SDRAM decoding window: %d\n", j); 99059c993d1SWarner Losh ddr_disable(j); 99159c993d1SWarner Losh } 99259c993d1SWarner Losh } 99359c993d1SWarner Losh 99459c993d1SWarner Losh return (0); 99559c993d1SWarner Losh } 99659c993d1SWarner Losh #endif 99759c993d1SWarner Losh /* 99859c993d1SWarner Losh * Check if we're able to cover all active DDR banks. 99959c993d1SWarner Losh */ 100059c993d1SWarner Losh static int 100159c993d1SWarner Losh decode_win_can_cover_ddr(int max) 100259c993d1SWarner Losh { 100359c993d1SWarner Losh int i, c; 100459c993d1SWarner Losh 100559c993d1SWarner Losh c = 0; 100659c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) 100759c993d1SWarner Losh if (ddr_is_active(i)) 100859c993d1SWarner Losh c++; 100959c993d1SWarner Losh 101059c993d1SWarner Losh if (c > max) { 101159c993d1SWarner Losh printf("Unable to cover all active DDR banks: " 101259c993d1SWarner Losh "%d, available windows: %d\n", c, max); 101359c993d1SWarner Losh return (0); 101459c993d1SWarner Losh } 101559c993d1SWarner Losh 101659c993d1SWarner Losh return (1); 101759c993d1SWarner Losh } 101859c993d1SWarner Losh 101959c993d1SWarner Losh /************************************************************************** 102059c993d1SWarner Losh * DDR windows routines 102159c993d1SWarner Losh **************************************************************************/ 102259c993d1SWarner Losh int 102359c993d1SWarner Losh ddr_is_active(int i) 102459c993d1SWarner Losh { 102559c993d1SWarner Losh 102659c993d1SWarner Losh if (ddr_sz_read(i) & 0x1) 102759c993d1SWarner Losh return (1); 102859c993d1SWarner Losh 102959c993d1SWarner Losh return (0); 103059c993d1SWarner Losh } 103159c993d1SWarner Losh 103259c993d1SWarner Losh void 103359c993d1SWarner Losh ddr_disable(int i) 103459c993d1SWarner Losh { 103559c993d1SWarner Losh 103659c993d1SWarner Losh ddr_sz_write(i, 0); 103759c993d1SWarner Losh ddr_br_write(i, 0); 103859c993d1SWarner Losh } 103959c993d1SWarner Losh 104059c993d1SWarner Losh uint32_t 104159c993d1SWarner Losh ddr_base(int i) 104259c993d1SWarner Losh { 104359c993d1SWarner Losh 104459c993d1SWarner Losh return (ddr_br_read(i) & 0xff000000); 104559c993d1SWarner Losh } 104659c993d1SWarner Losh 104759c993d1SWarner Losh uint32_t 104859c993d1SWarner Losh ddr_size(int i) 104959c993d1SWarner Losh { 105059c993d1SWarner Losh 105159c993d1SWarner Losh return ((ddr_sz_read(i) | 0x00ffffff) + 1); 105259c993d1SWarner Losh } 105359c993d1SWarner Losh 105459c993d1SWarner Losh uint32_t 105559c993d1SWarner Losh ddr_attr(int i) 105659c993d1SWarner Losh { 105759c993d1SWarner Losh uint32_t dev, rev; 105859c993d1SWarner Losh 105959c993d1SWarner Losh soc_id(&dev, &rev); 106059c993d1SWarner Losh if (dev == MV_DEV_88RC8180) 106159c993d1SWarner Losh return ((ddr_sz_read(i) & 0xf0) >> 4); 106259c993d1SWarner Losh if (dev == MV_DEV_88F6781) 106359c993d1SWarner Losh return (0); 106459c993d1SWarner Losh 106559c993d1SWarner Losh return (i == 0 ? 0xe : 106659c993d1SWarner Losh (i == 1 ? 0xd : 106759c993d1SWarner Losh (i == 2 ? 0xb : 106859c993d1SWarner Losh (i == 3 ? 0x7 : 0xff)))); 106959c993d1SWarner Losh } 107059c993d1SWarner Losh 107159c993d1SWarner Losh uint32_t 107259c993d1SWarner Losh ddr_target(int i) 107359c993d1SWarner Losh { 107459c993d1SWarner Losh uint32_t dev, rev; 107559c993d1SWarner Losh 107659c993d1SWarner Losh soc_id(&dev, &rev); 107759c993d1SWarner Losh if (dev == MV_DEV_88RC8180) { 107859c993d1SWarner Losh i = (ddr_sz_read(i) & 0xf0) >> 4; 107959c993d1SWarner Losh return (i == 0xe ? 0xc : 108059c993d1SWarner Losh (i == 0xd ? 0xd : 108159c993d1SWarner Losh (i == 0xb ? 0xe : 108259c993d1SWarner Losh (i == 0x7 ? 0xf : 0xc)))); 108359c993d1SWarner Losh } 108459c993d1SWarner Losh 108559c993d1SWarner Losh /* 108659c993d1SWarner Losh * On SOCs other than 88RC8180 Mbus unit ID for 108759c993d1SWarner Losh * DDR SDRAM controller is always 0x0. 108859c993d1SWarner Losh */ 108959c993d1SWarner Losh return (0); 109059c993d1SWarner Losh } 109159c993d1SWarner Losh 109259c993d1SWarner Losh /************************************************************************** 1093fcb93d74SWojciech Macek * CESA windows routines 1094fcb93d74SWojciech Macek **************************************************************************/ 1095fcb93d74SWojciech Macek static int 1096fcb93d74SWojciech Macek decode_win_cesa_valid(void) 1097fcb93d74SWojciech Macek { 1098fcb93d74SWojciech Macek 1099fcb93d74SWojciech Macek return (decode_win_can_cover_ddr(MV_WIN_CESA_MAX)); 1100fcb93d74SWojciech Macek } 1101fcb93d74SWojciech Macek 1102fcb93d74SWojciech Macek static void 1103fcb93d74SWojciech Macek decode_win_cesa_dump(u_long base) 1104fcb93d74SWojciech Macek { 1105fcb93d74SWojciech Macek int i; 1106fcb93d74SWojciech Macek 1107fcb93d74SWojciech Macek for (i = 0; i < MV_WIN_CESA_MAX; i++) 1108fcb93d74SWojciech Macek printf("CESA window#%d: c 0x%08x, b 0x%08x\n", i, 1109fcb93d74SWojciech Macek win_cesa_cr_read(base, i), win_cesa_br_read(base, i)); 1110fcb93d74SWojciech Macek } 1111fcb93d74SWojciech Macek 1112fcb93d74SWojciech Macek /* 1113fcb93d74SWojciech Macek * Set CESA decode windows. 1114fcb93d74SWojciech Macek */ 1115fcb93d74SWojciech Macek static void 1116fcb93d74SWojciech Macek decode_win_cesa_setup(u_long base) 1117fcb93d74SWojciech Macek { 1118fcb93d74SWojciech Macek uint32_t br, cr; 1119fa5f501dSZbigniew Bodek uint64_t size; 1120fcb93d74SWojciech Macek int i, j; 1121fcb93d74SWojciech Macek 1122fcb93d74SWojciech Macek for (i = 0; i < MV_WIN_CESA_MAX; i++) { 1123fcb93d74SWojciech Macek win_cesa_cr_write(base, i, 0); 1124fcb93d74SWojciech Macek win_cesa_br_write(base, i, 0); 1125fcb93d74SWojciech Macek } 1126fcb93d74SWojciech Macek 1127fcb93d74SWojciech Macek /* Only access to active DRAM banks is required */ 1128fcb93d74SWojciech Macek for (i = 0; i < MV_WIN_DDR_MAX; i++) { 1129fcb93d74SWojciech Macek if (ddr_is_active(i)) { 1130fcb93d74SWojciech Macek br = ddr_base(i); 1131fcb93d74SWojciech Macek 1132fa5f501dSZbigniew Bodek size = ddr_size(i); 1133fa5f501dSZbigniew Bodek #ifdef SOC_MV_ARMADA38X 1134fa5f501dSZbigniew Bodek /* 1135fa5f501dSZbigniew Bodek * Armada 38x SoC's equipped with 4GB DRAM 1136fa5f501dSZbigniew Bodek * suffer freeze during CESA operation, if 1137fa5f501dSZbigniew Bodek * MBUS window opened at given DRAM CS reaches 1138fa5f501dSZbigniew Bodek * end of the address space. Apply a workaround 1139fa5f501dSZbigniew Bodek * by setting the window size to the closest possible 1140fa5f501dSZbigniew Bodek * value, i.e. divide it by 2. 1141fa5f501dSZbigniew Bodek */ 1142fa5f501dSZbigniew Bodek if (size + ddr_base(i) == 0x100000000ULL) 1143fa5f501dSZbigniew Bodek size /= 2; 1144fa5f501dSZbigniew Bodek #endif 1145fa5f501dSZbigniew Bodek 1146fa5f501dSZbigniew Bodek cr = (((size - 1) & 0xffff0000) | 1147fcb93d74SWojciech Macek (ddr_attr(i) << IO_WIN_ATTR_SHIFT) | 1148fcb93d74SWojciech Macek (ddr_target(i) << IO_WIN_TGT_SHIFT) | 1149fcb93d74SWojciech Macek IO_WIN_ENA_MASK); 1150fcb93d74SWojciech Macek 1151fcb93d74SWojciech Macek /* Set the first free CESA window */ 1152fcb93d74SWojciech Macek for (j = 0; j < MV_WIN_CESA_MAX; j++) { 1153fcb93d74SWojciech Macek if (win_cesa_cr_read(base, j) & 0x1) 1154fcb93d74SWojciech Macek continue; 1155fcb93d74SWojciech Macek 1156fcb93d74SWojciech Macek win_cesa_br_write(base, j, br); 1157fcb93d74SWojciech Macek win_cesa_cr_write(base, j, cr); 1158fcb93d74SWojciech Macek break; 1159fcb93d74SWojciech Macek } 1160fcb93d74SWojciech Macek } 1161fcb93d74SWojciech Macek } 1162fcb93d74SWojciech Macek } 1163fcb93d74SWojciech Macek 1164fcb93d74SWojciech Macek /************************************************************************** 116559c993d1SWarner Losh * USB windows routines 116659c993d1SWarner Losh **************************************************************************/ 116759c993d1SWarner Losh static int 116859c993d1SWarner Losh decode_win_usb_valid(void) 116959c993d1SWarner Losh { 117059c993d1SWarner Losh 117159c993d1SWarner Losh return (decode_win_can_cover_ddr(MV_WIN_USB_MAX)); 117259c993d1SWarner Losh } 117359c993d1SWarner Losh 117459c993d1SWarner Losh static void 117559c993d1SWarner Losh decode_win_usb_dump(u_long base) 117659c993d1SWarner Losh { 117759c993d1SWarner Losh int i; 117859c993d1SWarner Losh 117959c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_USB(usb_port - 1))) 118059c993d1SWarner Losh return; 118159c993d1SWarner Losh 118259c993d1SWarner Losh for (i = 0; i < MV_WIN_USB_MAX; i++) 118359c993d1SWarner Losh printf("USB window#%d: c 0x%08x, b 0x%08x\n", i, 118459c993d1SWarner Losh win_usb_cr_read(base, i), win_usb_br_read(base, i)); 118559c993d1SWarner Losh } 118659c993d1SWarner Losh 118759c993d1SWarner Losh /* 118859c993d1SWarner Losh * Set USB decode windows. 118959c993d1SWarner Losh */ 119059c993d1SWarner Losh static void 119159c993d1SWarner Losh decode_win_usb_setup(u_long base) 119259c993d1SWarner Losh { 119359c993d1SWarner Losh uint32_t br, cr; 119459c993d1SWarner Losh int i, j; 119559c993d1SWarner Losh 119659c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_USB(usb_port))) 119759c993d1SWarner Losh return; 119859c993d1SWarner Losh 119959c993d1SWarner Losh usb_port++; 120059c993d1SWarner Losh 120159c993d1SWarner Losh for (i = 0; i < MV_WIN_USB_MAX; i++) { 120259c993d1SWarner Losh win_usb_cr_write(base, i, 0); 120359c993d1SWarner Losh win_usb_br_write(base, i, 0); 120459c993d1SWarner Losh } 120559c993d1SWarner Losh 120659c993d1SWarner Losh /* Only access to active DRAM banks is required */ 120759c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) { 120859c993d1SWarner Losh if (ddr_is_active(i)) { 120959c993d1SWarner Losh br = ddr_base(i); 121059c993d1SWarner Losh /* 121159c993d1SWarner Losh * XXX for 6281 we should handle Mbus write 121259c993d1SWarner Losh * burst limit field in the ctrl reg 121359c993d1SWarner Losh */ 121459c993d1SWarner Losh cr = (((ddr_size(i) - 1) & 0xffff0000) | 121559c993d1SWarner Losh (ddr_attr(i) << 8) | 121659c993d1SWarner Losh (ddr_target(i) << 4) | 1); 121759c993d1SWarner Losh 121859c993d1SWarner Losh /* Set the first free USB window */ 121959c993d1SWarner Losh for (j = 0; j < MV_WIN_USB_MAX; j++) { 122059c993d1SWarner Losh if (win_usb_cr_read(base, j) & 0x1) 122159c993d1SWarner Losh continue; 122259c993d1SWarner Losh 122359c993d1SWarner Losh win_usb_br_write(base, j, br); 122459c993d1SWarner Losh win_usb_cr_write(base, j, cr); 122559c993d1SWarner Losh break; 122659c993d1SWarner Losh } 122759c993d1SWarner Losh } 122859c993d1SWarner Losh } 122959c993d1SWarner Losh } 123059c993d1SWarner Losh 123159c993d1SWarner Losh /************************************************************************** 123234a3d2c6SWojciech Macek * USB3 windows routines 123334a3d2c6SWojciech Macek **************************************************************************/ 123434a3d2c6SWojciech Macek #ifdef SOC_MV_ARMADA38X 123534a3d2c6SWojciech Macek static int 123634a3d2c6SWojciech Macek decode_win_usb3_valid(void) 123734a3d2c6SWojciech Macek { 123834a3d2c6SWojciech Macek 123934a3d2c6SWojciech Macek return (decode_win_can_cover_ddr(MV_WIN_USB3_MAX)); 124034a3d2c6SWojciech Macek } 124134a3d2c6SWojciech Macek 124234a3d2c6SWojciech Macek static void 124334a3d2c6SWojciech Macek decode_win_usb3_dump(u_long base) 124434a3d2c6SWojciech Macek { 124534a3d2c6SWojciech Macek int i; 124634a3d2c6SWojciech Macek 124734a3d2c6SWojciech Macek for (i = 0; i < MV_WIN_USB3_MAX; i++) 124834a3d2c6SWojciech Macek printf("USB3.0 window#%d: c 0x%08x, b 0x%08x\n", i, 124934a3d2c6SWojciech Macek win_usb3_cr_read(base, i), win_usb3_br_read(base, i)); 125034a3d2c6SWojciech Macek } 125134a3d2c6SWojciech Macek 125234a3d2c6SWojciech Macek /* 125334a3d2c6SWojciech Macek * Set USB3 decode windows 125434a3d2c6SWojciech Macek */ 125534a3d2c6SWojciech Macek static void 125634a3d2c6SWojciech Macek decode_win_usb3_setup(u_long base) 125734a3d2c6SWojciech Macek { 125834a3d2c6SWojciech Macek uint32_t br, cr; 125934a3d2c6SWojciech Macek int i, j; 126034a3d2c6SWojciech Macek 126134a3d2c6SWojciech Macek for (i = 0; i < MV_WIN_USB3_MAX; i++) { 126234a3d2c6SWojciech Macek win_usb3_cr_write(base, i, 0); 126334a3d2c6SWojciech Macek win_usb3_br_write(base, i, 0); 126434a3d2c6SWojciech Macek } 126534a3d2c6SWojciech Macek 126634a3d2c6SWojciech Macek /* Only access to active DRAM banks is required */ 126734a3d2c6SWojciech Macek for (i = 0; i < MV_WIN_DDR_MAX; i++) { 126834a3d2c6SWojciech Macek if (ddr_is_active(i)) { 126934a3d2c6SWojciech Macek br = ddr_base(i); 127034a3d2c6SWojciech Macek cr = (((ddr_size(i) - 1) & 127134a3d2c6SWojciech Macek (IO_WIN_SIZE_MASK << IO_WIN_SIZE_SHIFT)) | 127234a3d2c6SWojciech Macek (ddr_attr(i) << IO_WIN_ATTR_SHIFT) | 127334a3d2c6SWojciech Macek (ddr_target(i) << IO_WIN_TGT_SHIFT) | 127434a3d2c6SWojciech Macek IO_WIN_ENA_MASK); 127534a3d2c6SWojciech Macek 127634a3d2c6SWojciech Macek /* Set the first free USB3.0 window */ 127734a3d2c6SWojciech Macek for (j = 0; j < MV_WIN_USB3_MAX; j++) { 127834a3d2c6SWojciech Macek if (win_usb3_cr_read(base, j) & IO_WIN_ENA_MASK) 127934a3d2c6SWojciech Macek continue; 128034a3d2c6SWojciech Macek 128134a3d2c6SWojciech Macek win_usb3_br_write(base, j, br); 128234a3d2c6SWojciech Macek win_usb3_cr_write(base, j, cr); 128334a3d2c6SWojciech Macek break; 128434a3d2c6SWojciech Macek } 128534a3d2c6SWojciech Macek } 128634a3d2c6SWojciech Macek } 128734a3d2c6SWojciech Macek } 128834a3d2c6SWojciech Macek #else 128934a3d2c6SWojciech Macek /* 129034a3d2c6SWojciech Macek * Provide dummy functions to satisfy the build 129134a3d2c6SWojciech Macek * for SoCs not equipped with USB3 129234a3d2c6SWojciech Macek */ 129334a3d2c6SWojciech Macek static int 129434a3d2c6SWojciech Macek decode_win_usb3_valid(void) 129534a3d2c6SWojciech Macek { 129634a3d2c6SWojciech Macek 129734a3d2c6SWojciech Macek return (1); 129834a3d2c6SWojciech Macek } 129934a3d2c6SWojciech Macek 130034a3d2c6SWojciech Macek static void 130134a3d2c6SWojciech Macek decode_win_usb3_setup(u_long base) 130234a3d2c6SWojciech Macek { 130334a3d2c6SWojciech Macek } 130434a3d2c6SWojciech Macek 130534a3d2c6SWojciech Macek static void 130634a3d2c6SWojciech Macek decode_win_usb3_dump(u_long base) 130734a3d2c6SWojciech Macek { 130834a3d2c6SWojciech Macek } 130934a3d2c6SWojciech Macek #endif 131034a3d2c6SWojciech Macek /************************************************************************** 131159c993d1SWarner Losh * ETH windows routines 131259c993d1SWarner Losh **************************************************************************/ 131359c993d1SWarner Losh 131459c993d1SWarner Losh static int 131559c993d1SWarner Losh win_eth_can_remap(int i) 131659c993d1SWarner Losh { 131759c993d1SWarner Losh 131859c993d1SWarner Losh /* ETH encode windows 0-3 have remap capability */ 131959c993d1SWarner Losh if (i < 4) 132059c993d1SWarner Losh return (1); 132159c993d1SWarner Losh 132259c993d1SWarner Losh return (0); 132359c993d1SWarner Losh } 132459c993d1SWarner Losh 132559c993d1SWarner Losh static int 132659c993d1SWarner Losh eth_bare_read(uint32_t base, int i) 132759c993d1SWarner Losh { 132859c993d1SWarner Losh uint32_t v; 132959c993d1SWarner Losh 133059c993d1SWarner Losh v = win_eth_bare_read(base); 133159c993d1SWarner Losh v &= (1 << i); 133259c993d1SWarner Losh 133359c993d1SWarner Losh return (v >> i); 133459c993d1SWarner Losh } 133559c993d1SWarner Losh 133659c993d1SWarner Losh static void 133759c993d1SWarner Losh eth_bare_write(uint32_t base, int i, int val) 133859c993d1SWarner Losh { 133959c993d1SWarner Losh uint32_t v; 134059c993d1SWarner Losh 134159c993d1SWarner Losh v = win_eth_bare_read(base); 134259c993d1SWarner Losh v &= ~(1 << i); 134359c993d1SWarner Losh v |= (val << i); 134459c993d1SWarner Losh win_eth_bare_write(base, v); 134559c993d1SWarner Losh } 134659c993d1SWarner Losh 134759c993d1SWarner Losh static void 134859c993d1SWarner Losh eth_epap_write(uint32_t base, int i, int val) 134959c993d1SWarner Losh { 135059c993d1SWarner Losh uint32_t v; 135159c993d1SWarner Losh 135259c993d1SWarner Losh v = win_eth_epap_read(base); 135359c993d1SWarner Losh v &= ~(0x3 << (i * 2)); 135459c993d1SWarner Losh v |= (val << (i * 2)); 135559c993d1SWarner Losh win_eth_epap_write(base, v); 135659c993d1SWarner Losh } 135759c993d1SWarner Losh 135859c993d1SWarner Losh static void 135959c993d1SWarner Losh decode_win_eth_dump(u_long base) 136059c993d1SWarner Losh { 136159c993d1SWarner Losh int i; 136259c993d1SWarner Losh 136359c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_GE(eth_port - 1))) 136459c993d1SWarner Losh return; 136559c993d1SWarner Losh 136659c993d1SWarner Losh for (i = 0; i < MV_WIN_ETH_MAX; i++) { 136759c993d1SWarner Losh printf("ETH window#%d: b 0x%08x, s 0x%08x", i, 136859c993d1SWarner Losh win_eth_br_read(base, i), 136959c993d1SWarner Losh win_eth_sz_read(base, i)); 137059c993d1SWarner Losh 137159c993d1SWarner Losh if (win_eth_can_remap(i)) 137259c993d1SWarner Losh printf(", ha 0x%08x", 137359c993d1SWarner Losh win_eth_har_read(base, i)); 137459c993d1SWarner Losh 137559c993d1SWarner Losh printf("\n"); 137659c993d1SWarner Losh } 137759c993d1SWarner Losh printf("ETH windows: bare 0x%08x, epap 0x%08x\n", 137859c993d1SWarner Losh win_eth_bare_read(base), 137959c993d1SWarner Losh win_eth_epap_read(base)); 138059c993d1SWarner Losh } 138159c993d1SWarner Losh 138259c993d1SWarner Losh #define MV_WIN_ETH_DDR_TRGT(n) ddr_target(n) 138359c993d1SWarner Losh 138459c993d1SWarner Losh static void 138559c993d1SWarner Losh decode_win_eth_setup(u_long base) 138659c993d1SWarner Losh { 138759c993d1SWarner Losh uint32_t br, sz; 138859c993d1SWarner Losh int i, j; 138959c993d1SWarner Losh 139059c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_GE(eth_port))) 139159c993d1SWarner Losh return; 139259c993d1SWarner Losh 139359c993d1SWarner Losh eth_port++; 139459c993d1SWarner Losh 139559c993d1SWarner Losh /* Disable, clear and revoke protection for all ETH windows */ 139659c993d1SWarner Losh for (i = 0; i < MV_WIN_ETH_MAX; i++) { 139759c993d1SWarner Losh 139859c993d1SWarner Losh eth_bare_write(base, i, 1); 139959c993d1SWarner Losh eth_epap_write(base, i, 0); 140059c993d1SWarner Losh win_eth_br_write(base, i, 0); 140159c993d1SWarner Losh win_eth_sz_write(base, i, 0); 140259c993d1SWarner Losh if (win_eth_can_remap(i)) 140359c993d1SWarner Losh win_eth_har_write(base, i, 0); 140459c993d1SWarner Losh } 140559c993d1SWarner Losh 140659c993d1SWarner Losh /* Only access to active DRAM banks is required */ 140759c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) 140859c993d1SWarner Losh if (ddr_is_active(i)) { 140959c993d1SWarner Losh 141059c993d1SWarner Losh br = ddr_base(i) | (ddr_attr(i) << 8) | MV_WIN_ETH_DDR_TRGT(i); 141159c993d1SWarner Losh sz = ((ddr_size(i) - 1) & 0xffff0000); 141259c993d1SWarner Losh 141359c993d1SWarner Losh /* Set the first free ETH window */ 141459c993d1SWarner Losh for (j = 0; j < MV_WIN_ETH_MAX; j++) { 141559c993d1SWarner Losh if (eth_bare_read(base, j) == 0) 141659c993d1SWarner Losh continue; 141759c993d1SWarner Losh 141859c993d1SWarner Losh win_eth_br_write(base, j, br); 141959c993d1SWarner Losh win_eth_sz_write(base, j, sz); 142059c993d1SWarner Losh 142159c993d1SWarner Losh /* XXX remapping ETH windows not supported */ 142259c993d1SWarner Losh 142359c993d1SWarner Losh /* Set protection RW */ 142459c993d1SWarner Losh eth_epap_write(base, j, 0x3); 142559c993d1SWarner Losh 142659c993d1SWarner Losh /* Enable window */ 142759c993d1SWarner Losh eth_bare_write(base, j, 0); 142859c993d1SWarner Losh break; 142959c993d1SWarner Losh } 143059c993d1SWarner Losh } 143159c993d1SWarner Losh } 143259c993d1SWarner Losh 143359c993d1SWarner Losh static int 143459c993d1SWarner Losh decode_win_eth_valid(void) 143559c993d1SWarner Losh { 143659c993d1SWarner Losh 143759c993d1SWarner Losh return (decode_win_can_cover_ddr(MV_WIN_ETH_MAX)); 143859c993d1SWarner Losh } 143959c993d1SWarner Losh 144059c993d1SWarner Losh /************************************************************************** 144159c993d1SWarner Losh * PCIE windows routines 144259c993d1SWarner Losh **************************************************************************/ 144359c993d1SWarner Losh 144459c993d1SWarner Losh void 144559c993d1SWarner Losh decode_win_pcie_setup(u_long base) 144659c993d1SWarner Losh { 144759c993d1SWarner Losh uint32_t size = 0, ddrbase = ~0; 144859c993d1SWarner Losh uint32_t cr, br; 144959c993d1SWarner Losh int i, j; 145059c993d1SWarner Losh 145159c993d1SWarner Losh for (i = 0; i < MV_PCIE_BAR_MAX; i++) { 145259c993d1SWarner Losh pcie_bar_br_write(base, i, 145359c993d1SWarner Losh MV_PCIE_BAR_64BIT | MV_PCIE_BAR_PREFETCH_EN); 145459c993d1SWarner Losh if (i < 3) 145559c993d1SWarner Losh pcie_bar_brh_write(base, i, 0); 145659c993d1SWarner Losh if (i > 0) 145759c993d1SWarner Losh pcie_bar_cr_write(base, i, 0); 145859c993d1SWarner Losh } 145959c993d1SWarner Losh 146059c993d1SWarner Losh for (i = 0; i < MV_WIN_PCIE_MAX; i++) { 146159c993d1SWarner Losh win_pcie_cr_write(base, i, 0); 146259c993d1SWarner Losh win_pcie_br_write(base, i, 0); 146359c993d1SWarner Losh win_pcie_remap_write(base, i, 0); 146459c993d1SWarner Losh } 146559c993d1SWarner Losh 146659c993d1SWarner Losh /* On End-Point only set BAR size to 1MB regardless of DDR size */ 146759c993d1SWarner Losh if ((bus_space_read_4(fdtbus_bs_tag, base, MV_PCIE_CONTROL) 146859c993d1SWarner Losh & MV_PCIE_ROOT_CMPLX) == 0) { 146959c993d1SWarner Losh pcie_bar_cr_write(base, 1, 0xf0000 | 1); 147059c993d1SWarner Losh return; 147159c993d1SWarner Losh } 147259c993d1SWarner Losh 147359c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) { 147459c993d1SWarner Losh if (ddr_is_active(i)) { 147559c993d1SWarner Losh /* Map DDR to BAR 1 */ 147659c993d1SWarner Losh cr = (ddr_size(i) - 1) & 0xffff0000; 147759c993d1SWarner Losh size += ddr_size(i) & 0xffff0000; 147859c993d1SWarner Losh cr |= (ddr_attr(i) << 8) | (ddr_target(i) << 4) | 1; 147959c993d1SWarner Losh br = ddr_base(i); 148059c993d1SWarner Losh if (br < ddrbase) 148159c993d1SWarner Losh ddrbase = br; 148259c993d1SWarner Losh 148359c993d1SWarner Losh /* Use the first available PCIE window */ 148459c993d1SWarner Losh for (j = 0; j < MV_WIN_PCIE_MAX; j++) { 148559c993d1SWarner Losh if (win_pcie_cr_read(base, j) != 0) 148659c993d1SWarner Losh continue; 148759c993d1SWarner Losh 148859c993d1SWarner Losh win_pcie_br_write(base, j, br); 148959c993d1SWarner Losh win_pcie_cr_write(base, j, cr); 149059c993d1SWarner Losh break; 149159c993d1SWarner Losh } 149259c993d1SWarner Losh } 149359c993d1SWarner Losh } 149459c993d1SWarner Losh 149559c993d1SWarner Losh /* 149659c993d1SWarner Losh * Upper 16 bits in BAR register is interpreted as BAR size 1497255eff3bSPedro F. Giffuni * (in 64 kB units) plus 64kB, so subtract 0x10000 149859c993d1SWarner Losh * form value passed to register to get correct value. 149959c993d1SWarner Losh */ 150059c993d1SWarner Losh size -= 0x10000; 150159c993d1SWarner Losh pcie_bar_cr_write(base, 1, size | 1); 150259c993d1SWarner Losh pcie_bar_br_write(base, 1, ddrbase | 150359c993d1SWarner Losh MV_PCIE_BAR_64BIT | MV_PCIE_BAR_PREFETCH_EN); 150459c993d1SWarner Losh pcie_bar_br_write(base, 0, fdt_immr_pa | 150559c993d1SWarner Losh MV_PCIE_BAR_64BIT | MV_PCIE_BAR_PREFETCH_EN); 150659c993d1SWarner Losh } 150759c993d1SWarner Losh 150859c993d1SWarner Losh static int 150959c993d1SWarner Losh decode_win_pcie_valid(void) 151059c993d1SWarner Losh { 151159c993d1SWarner Losh 151259c993d1SWarner Losh return (decode_win_can_cover_ddr(MV_WIN_PCIE_MAX)); 151359c993d1SWarner Losh } 151459c993d1SWarner Losh 151559c993d1SWarner Losh /************************************************************************** 151659c993d1SWarner Losh * IDMA windows routines 151759c993d1SWarner Losh **************************************************************************/ 151859c993d1SWarner Losh #if defined(SOC_MV_ORION) || defined(SOC_MV_DISCOVERY) 151959c993d1SWarner Losh static int 152059c993d1SWarner Losh idma_bare_read(u_long base, int i) 152159c993d1SWarner Losh { 152259c993d1SWarner Losh uint32_t v; 152359c993d1SWarner Losh 152459c993d1SWarner Losh v = win_idma_bare_read(base); 152559c993d1SWarner Losh v &= (1 << i); 152659c993d1SWarner Losh 152759c993d1SWarner Losh return (v >> i); 152859c993d1SWarner Losh } 152959c993d1SWarner Losh 153059c993d1SWarner Losh static void 153159c993d1SWarner Losh idma_bare_write(u_long base, int i, int val) 153259c993d1SWarner Losh { 153359c993d1SWarner Losh uint32_t v; 153459c993d1SWarner Losh 153559c993d1SWarner Losh v = win_idma_bare_read(base); 153659c993d1SWarner Losh v &= ~(1 << i); 153759c993d1SWarner Losh v |= (val << i); 153859c993d1SWarner Losh win_idma_bare_write(base, v); 153959c993d1SWarner Losh } 154059c993d1SWarner Losh 154159c993d1SWarner Losh /* 154259c993d1SWarner Losh * Sets channel protection 'val' for window 'w' on channel 'c' 154359c993d1SWarner Losh */ 154459c993d1SWarner Losh static void 154559c993d1SWarner Losh idma_cap_write(u_long base, int c, int w, int val) 154659c993d1SWarner Losh { 154759c993d1SWarner Losh uint32_t v; 154859c993d1SWarner Losh 154959c993d1SWarner Losh v = win_idma_cap_read(base, c); 155059c993d1SWarner Losh v &= ~(0x3 << (w * 2)); 155159c993d1SWarner Losh v |= (val << (w * 2)); 155259c993d1SWarner Losh win_idma_cap_write(base, c, v); 155359c993d1SWarner Losh } 155459c993d1SWarner Losh 155559c993d1SWarner Losh /* 155659c993d1SWarner Losh * Set protection 'val' on all channels for window 'w' 155759c993d1SWarner Losh */ 155859c993d1SWarner Losh static void 155959c993d1SWarner Losh idma_set_prot(u_long base, int w, int val) 156059c993d1SWarner Losh { 156159c993d1SWarner Losh int c; 156259c993d1SWarner Losh 156359c993d1SWarner Losh for (c = 0; c < MV_IDMA_CHAN_MAX; c++) 156459c993d1SWarner Losh idma_cap_write(base, c, w, val); 156559c993d1SWarner Losh } 156659c993d1SWarner Losh 156759c993d1SWarner Losh static int 156859c993d1SWarner Losh win_idma_can_remap(int i) 156959c993d1SWarner Losh { 157059c993d1SWarner Losh 157159c993d1SWarner Losh /* IDMA decode windows 0-3 have remap capability */ 157259c993d1SWarner Losh if (i < 4) 157359c993d1SWarner Losh return (1); 157459c993d1SWarner Losh 157559c993d1SWarner Losh return (0); 157659c993d1SWarner Losh } 157759c993d1SWarner Losh 157859c993d1SWarner Losh void 157959c993d1SWarner Losh decode_win_idma_setup(u_long base) 158059c993d1SWarner Losh { 158159c993d1SWarner Losh uint32_t br, sz; 158259c993d1SWarner Losh int i, j; 158359c993d1SWarner Losh 158459c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_IDMA)) 158559c993d1SWarner Losh return; 158659c993d1SWarner Losh /* 158759c993d1SWarner Losh * Disable and clear all IDMA windows, revoke protection for all channels 158859c993d1SWarner Losh */ 158959c993d1SWarner Losh for (i = 0; i < MV_WIN_IDMA_MAX; i++) { 159059c993d1SWarner Losh 159159c993d1SWarner Losh idma_bare_write(base, i, 1); 159259c993d1SWarner Losh win_idma_br_write(base, i, 0); 159359c993d1SWarner Losh win_idma_sz_write(base, i, 0); 159459c993d1SWarner Losh if (win_idma_can_remap(i) == 1) 159559c993d1SWarner Losh win_idma_har_write(base, i, 0); 159659c993d1SWarner Losh } 159759c993d1SWarner Losh for (i = 0; i < MV_IDMA_CHAN_MAX; i++) 159859c993d1SWarner Losh win_idma_cap_write(base, i, 0); 159959c993d1SWarner Losh 160059c993d1SWarner Losh /* 160159c993d1SWarner Losh * Set up access to all active DRAM banks 160259c993d1SWarner Losh */ 160359c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) 160459c993d1SWarner Losh if (ddr_is_active(i)) { 160559c993d1SWarner Losh br = ddr_base(i) | (ddr_attr(i) << 8) | ddr_target(i); 160659c993d1SWarner Losh sz = ((ddr_size(i) - 1) & 0xffff0000); 160759c993d1SWarner Losh 160859c993d1SWarner Losh /* Place DDR entries in non-remapped windows */ 160959c993d1SWarner Losh for (j = 0; j < MV_WIN_IDMA_MAX; j++) 161059c993d1SWarner Losh if (win_idma_can_remap(j) != 1 && 161159c993d1SWarner Losh idma_bare_read(base, j) == 1) { 161259c993d1SWarner Losh 161359c993d1SWarner Losh /* Configure window */ 161459c993d1SWarner Losh win_idma_br_write(base, j, br); 161559c993d1SWarner Losh win_idma_sz_write(base, j, sz); 161659c993d1SWarner Losh 161759c993d1SWarner Losh /* Set protection RW on all channels */ 161859c993d1SWarner Losh idma_set_prot(base, j, 0x3); 161959c993d1SWarner Losh 162059c993d1SWarner Losh /* Enable window */ 162159c993d1SWarner Losh idma_bare_write(base, j, 0); 162259c993d1SWarner Losh break; 162359c993d1SWarner Losh } 162459c993d1SWarner Losh } 162559c993d1SWarner Losh 162659c993d1SWarner Losh /* 162759c993d1SWarner Losh * Remaining targets -- from statically defined table 162859c993d1SWarner Losh */ 162959c993d1SWarner Losh for (i = 0; i < idma_wins_no; i++) 163059c993d1SWarner Losh if (idma_wins[i].target > 0) { 163159c993d1SWarner Losh br = (idma_wins[i].base & 0xffff0000) | 163259c993d1SWarner Losh (idma_wins[i].attr << 8) | idma_wins[i].target; 163359c993d1SWarner Losh sz = ((idma_wins[i].size - 1) & 0xffff0000); 163459c993d1SWarner Losh 163559c993d1SWarner Losh /* Set the first free IDMA window */ 163659c993d1SWarner Losh for (j = 0; j < MV_WIN_IDMA_MAX; j++) { 163759c993d1SWarner Losh if (idma_bare_read(base, j) == 0) 163859c993d1SWarner Losh continue; 163959c993d1SWarner Losh 164059c993d1SWarner Losh /* Configure window */ 164159c993d1SWarner Losh win_idma_br_write(base, j, br); 164259c993d1SWarner Losh win_idma_sz_write(base, j, sz); 164359c993d1SWarner Losh if (win_idma_can_remap(j) && 164459c993d1SWarner Losh idma_wins[j].remap >= 0) 164559c993d1SWarner Losh win_idma_har_write(base, j, 164659c993d1SWarner Losh idma_wins[j].remap); 164759c993d1SWarner Losh 164859c993d1SWarner Losh /* Set protection RW on all channels */ 164959c993d1SWarner Losh idma_set_prot(base, j, 0x3); 165059c993d1SWarner Losh 165159c993d1SWarner Losh /* Enable window */ 165259c993d1SWarner Losh idma_bare_write(base, j, 0); 165359c993d1SWarner Losh break; 165459c993d1SWarner Losh } 165559c993d1SWarner Losh } 165659c993d1SWarner Losh } 165759c993d1SWarner Losh 165859c993d1SWarner Losh int 165959c993d1SWarner Losh decode_win_idma_valid(void) 166059c993d1SWarner Losh { 166159c993d1SWarner Losh const struct decode_win *wintab; 166259c993d1SWarner Losh int c, i, j, rv; 166359c993d1SWarner Losh uint32_t b, e, s; 166459c993d1SWarner Losh 166559c993d1SWarner Losh if (idma_wins_no > MV_WIN_IDMA_MAX) { 166659c993d1SWarner Losh printf("IDMA windows: too many entries: %d\n", idma_wins_no); 166759c993d1SWarner Losh return (0); 166859c993d1SWarner Losh } 166959c993d1SWarner Losh for (i = 0, c = 0; i < MV_WIN_DDR_MAX; i++) 167059c993d1SWarner Losh if (ddr_is_active(i)) 167159c993d1SWarner Losh c++; 167259c993d1SWarner Losh 167359c993d1SWarner Losh if (idma_wins_no > (MV_WIN_IDMA_MAX - c)) { 167459c993d1SWarner Losh printf("IDMA windows: too many entries: %d, available: %d\n", 167559c993d1SWarner Losh idma_wins_no, MV_WIN_IDMA_MAX - c); 167659c993d1SWarner Losh return (0); 167759c993d1SWarner Losh } 167859c993d1SWarner Losh 167959c993d1SWarner Losh wintab = idma_wins; 168059c993d1SWarner Losh rv = 1; 168159c993d1SWarner Losh for (i = 0; i < idma_wins_no; i++, wintab++) { 168259c993d1SWarner Losh 168359c993d1SWarner Losh if (wintab->target == 0) { 168459c993d1SWarner Losh printf("IDMA window#%d: DDR target window is not " 168559c993d1SWarner Losh "supposed to be reprogrammed!\n", i); 168659c993d1SWarner Losh rv = 0; 168759c993d1SWarner Losh } 168859c993d1SWarner Losh 168959c993d1SWarner Losh if (wintab->remap >= 0 && win_cpu_can_remap(i) != 1) { 169059c993d1SWarner Losh printf("IDMA window#%d: not capable of remapping, but " 169159c993d1SWarner Losh "val 0x%08x defined\n", i, wintab->remap); 169259c993d1SWarner Losh rv = 0; 169359c993d1SWarner Losh } 169459c993d1SWarner Losh 169559c993d1SWarner Losh s = wintab->size; 169659c993d1SWarner Losh b = wintab->base; 169759c993d1SWarner Losh e = b + s - 1; 169859c993d1SWarner Losh if (s > (0xFFFFFFFF - b + 1)) { 169959c993d1SWarner Losh /* XXX this boundary check should account for 64bit and 170059c993d1SWarner Losh * remapping.. */ 170159c993d1SWarner Losh printf("IDMA window#%d: no space for size 0x%08x at " 170259c993d1SWarner Losh "0x%08x\n", i, s, b); 170359c993d1SWarner Losh rv = 0; 170459c993d1SWarner Losh continue; 170559c993d1SWarner Losh } 170659c993d1SWarner Losh 170759c993d1SWarner Losh j = decode_win_overlap(i, idma_wins_no, &idma_wins[0]); 170859c993d1SWarner Losh if (j >= 0) { 170959c993d1SWarner Losh printf("IDMA window#%d: (0x%08x - 0x%08x) overlaps " 171059c993d1SWarner Losh "with #%d (0x%08x - 0x%08x)\n", i, b, e, j, 171159c993d1SWarner Losh idma_wins[j].base, 171259c993d1SWarner Losh idma_wins[j].base + idma_wins[j].size - 1); 171359c993d1SWarner Losh rv = 0; 171459c993d1SWarner Losh } 171559c993d1SWarner Losh } 171659c993d1SWarner Losh 171759c993d1SWarner Losh return (rv); 171859c993d1SWarner Losh } 171959c993d1SWarner Losh 172059c993d1SWarner Losh void 172159c993d1SWarner Losh decode_win_idma_dump(u_long base) 172259c993d1SWarner Losh { 172359c993d1SWarner Losh int i; 172459c993d1SWarner Losh 172559c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_IDMA)) 172659c993d1SWarner Losh return; 172759c993d1SWarner Losh 172859c993d1SWarner Losh for (i = 0; i < MV_WIN_IDMA_MAX; i++) { 172959c993d1SWarner Losh printf("IDMA window#%d: b 0x%08x, s 0x%08x", i, 173059c993d1SWarner Losh win_idma_br_read(base, i), win_idma_sz_read(base, i)); 173159c993d1SWarner Losh 173259c993d1SWarner Losh if (win_idma_can_remap(i)) 173359c993d1SWarner Losh printf(", ha 0x%08x", win_idma_har_read(base, i)); 173459c993d1SWarner Losh 173559c993d1SWarner Losh printf("\n"); 173659c993d1SWarner Losh } 173759c993d1SWarner Losh for (i = 0; i < MV_IDMA_CHAN_MAX; i++) 173859c993d1SWarner Losh printf("IDMA channel#%d: ap 0x%08x\n", i, 173959c993d1SWarner Losh win_idma_cap_read(base, i)); 174059c993d1SWarner Losh printf("IDMA windows: bare 0x%08x\n", win_idma_bare_read(base)); 174159c993d1SWarner Losh } 174259c993d1SWarner Losh #else 174359c993d1SWarner Losh 174459c993d1SWarner Losh /* Provide dummy functions to satisfy the build for SoCs not equipped with IDMA */ 174559c993d1SWarner Losh int 174659c993d1SWarner Losh decode_win_idma_valid(void) 174759c993d1SWarner Losh { 174859c993d1SWarner Losh 174959c993d1SWarner Losh return (1); 175059c993d1SWarner Losh } 175159c993d1SWarner Losh 175259c993d1SWarner Losh void 175359c993d1SWarner Losh decode_win_idma_setup(u_long base) 175459c993d1SWarner Losh { 175559c993d1SWarner Losh } 175659c993d1SWarner Losh 175759c993d1SWarner Losh void 175859c993d1SWarner Losh decode_win_idma_dump(u_long base) 175959c993d1SWarner Losh { 176059c993d1SWarner Losh } 176159c993d1SWarner Losh #endif 176259c993d1SWarner Losh 176359c993d1SWarner Losh /************************************************************************** 176459c993d1SWarner Losh * XOR windows routines 176559c993d1SWarner Losh **************************************************************************/ 176659c993d1SWarner Losh #if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY) 176759c993d1SWarner Losh static int 176859c993d1SWarner Losh xor_ctrl_read(u_long base, int i, int c, int e) 176959c993d1SWarner Losh { 177059c993d1SWarner Losh uint32_t v; 177159c993d1SWarner Losh v = win_xor_ctrl_read(base, c, e); 177259c993d1SWarner Losh v &= (1 << i); 177359c993d1SWarner Losh 177459c993d1SWarner Losh return (v >> i); 177559c993d1SWarner Losh } 177659c993d1SWarner Losh 177759c993d1SWarner Losh static void 177859c993d1SWarner Losh xor_ctrl_write(u_long base, int i, int c, int e, int val) 177959c993d1SWarner Losh { 178059c993d1SWarner Losh uint32_t v; 178159c993d1SWarner Losh 178259c993d1SWarner Losh v = win_xor_ctrl_read(base, c, e); 178359c993d1SWarner Losh v &= ~(1 << i); 178459c993d1SWarner Losh v |= (val << i); 178559c993d1SWarner Losh win_xor_ctrl_write(base, c, e, v); 178659c993d1SWarner Losh } 178759c993d1SWarner Losh 178859c993d1SWarner Losh /* 178959c993d1SWarner Losh * Set channel protection 'val' for window 'w' on channel 'c' 179059c993d1SWarner Losh */ 179159c993d1SWarner Losh static void 179259c993d1SWarner Losh xor_chan_write(u_long base, int c, int e, int w, int val) 179359c993d1SWarner Losh { 179459c993d1SWarner Losh uint32_t v; 179559c993d1SWarner Losh 179659c993d1SWarner Losh v = win_xor_ctrl_read(base, c, e); 179759c993d1SWarner Losh v &= ~(0x3 << (w * 2 + 16)); 179859c993d1SWarner Losh v |= (val << (w * 2 + 16)); 179959c993d1SWarner Losh win_xor_ctrl_write(base, c, e, v); 180059c993d1SWarner Losh } 180159c993d1SWarner Losh 180259c993d1SWarner Losh /* 180359c993d1SWarner Losh * Set protection 'val' on all channels for window 'w' on engine 'e' 180459c993d1SWarner Losh */ 180559c993d1SWarner Losh static void 180659c993d1SWarner Losh xor_set_prot(u_long base, int w, int e, int val) 180759c993d1SWarner Losh { 180859c993d1SWarner Losh int c; 180959c993d1SWarner Losh 181059c993d1SWarner Losh for (c = 0; c < MV_XOR_CHAN_MAX; c++) 181159c993d1SWarner Losh xor_chan_write(base, c, e, w, val); 181259c993d1SWarner Losh } 181359c993d1SWarner Losh 181459c993d1SWarner Losh static int 181559c993d1SWarner Losh win_xor_can_remap(int i) 181659c993d1SWarner Losh { 181759c993d1SWarner Losh 181859c993d1SWarner Losh /* XOR decode windows 0-3 have remap capability */ 181959c993d1SWarner Losh if (i < 4) 182059c993d1SWarner Losh return (1); 182159c993d1SWarner Losh 182259c993d1SWarner Losh return (0); 182359c993d1SWarner Losh } 182459c993d1SWarner Losh 182559c993d1SWarner Losh static int 182659c993d1SWarner Losh xor_max_eng(void) 182759c993d1SWarner Losh { 182859c993d1SWarner Losh uint32_t dev, rev; 182959c993d1SWarner Losh 183059c993d1SWarner Losh soc_id(&dev, &rev); 183159c993d1SWarner Losh switch (dev) { 183259c993d1SWarner Losh case MV_DEV_88F6281: 183359c993d1SWarner Losh case MV_DEV_88F6282: 183459c993d1SWarner Losh case MV_DEV_MV78130: 183559c993d1SWarner Losh case MV_DEV_MV78160: 183659c993d1SWarner Losh case MV_DEV_MV78230: 183759c993d1SWarner Losh case MV_DEV_MV78260: 183859c993d1SWarner Losh case MV_DEV_MV78460: 183959c993d1SWarner Losh return (2); 184059c993d1SWarner Losh case MV_DEV_MV78100: 184159c993d1SWarner Losh case MV_DEV_MV78100_Z0: 184259c993d1SWarner Losh return (1); 184359c993d1SWarner Losh default: 184459c993d1SWarner Losh return (0); 184559c993d1SWarner Losh } 184659c993d1SWarner Losh } 184759c993d1SWarner Losh 184859c993d1SWarner Losh static void 184959c993d1SWarner Losh xor_active_dram(u_long base, int c, int e, int *window) 185059c993d1SWarner Losh { 185159c993d1SWarner Losh uint32_t br, sz; 185259c993d1SWarner Losh int i, m, w; 185359c993d1SWarner Losh 185459c993d1SWarner Losh /* 185559c993d1SWarner Losh * Set up access to all active DRAM banks 185659c993d1SWarner Losh */ 185759c993d1SWarner Losh m = xor_max_eng(); 185859c993d1SWarner Losh for (i = 0; i < m; i++) 185959c993d1SWarner Losh if (ddr_is_active(i)) { 186059c993d1SWarner Losh br = ddr_base(i) | (ddr_attr(i) << 8) | 186159c993d1SWarner Losh ddr_target(i); 186259c993d1SWarner Losh sz = ((ddr_size(i) - 1) & 0xffff0000); 186359c993d1SWarner Losh 186459c993d1SWarner Losh /* Place DDR entries in non-remapped windows */ 186559c993d1SWarner Losh for (w = 0; w < MV_WIN_XOR_MAX; w++) 186659c993d1SWarner Losh if (win_xor_can_remap(w) != 1 && 186759c993d1SWarner Losh (xor_ctrl_read(base, w, c, e) == 0) && 186859c993d1SWarner Losh w > *window) { 186959c993d1SWarner Losh /* Configure window */ 187059c993d1SWarner Losh win_xor_br_write(base, w, e, br); 187159c993d1SWarner Losh win_xor_sz_write(base, w, e, sz); 187259c993d1SWarner Losh 187359c993d1SWarner Losh /* Set protection RW on all channels */ 187459c993d1SWarner Losh xor_set_prot(base, w, e, 0x3); 187559c993d1SWarner Losh 187659c993d1SWarner Losh /* Enable window */ 187759c993d1SWarner Losh xor_ctrl_write(base, w, c, e, 1); 187859c993d1SWarner Losh (*window)++; 187959c993d1SWarner Losh break; 188059c993d1SWarner Losh } 188159c993d1SWarner Losh } 188259c993d1SWarner Losh } 188359c993d1SWarner Losh 188459c993d1SWarner Losh void 188559c993d1SWarner Losh decode_win_xor_setup(u_long base) 188659c993d1SWarner Losh { 188759c993d1SWarner Losh uint32_t br, sz; 188859c993d1SWarner Losh int i, j, z, e = 1, m, window; 188959c993d1SWarner Losh 189059c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_XOR)) 189159c993d1SWarner Losh return; 189259c993d1SWarner Losh 189359c993d1SWarner Losh /* 189459c993d1SWarner Losh * Disable and clear all XOR windows, revoke protection for all 189559c993d1SWarner Losh * channels 189659c993d1SWarner Losh */ 189759c993d1SWarner Losh m = xor_max_eng(); 189859c993d1SWarner Losh for (j = 0; j < m; j++, e--) { 189959c993d1SWarner Losh 190059c993d1SWarner Losh /* Number of non-remaped windows */ 190159c993d1SWarner Losh window = MV_XOR_NON_REMAP - 1; 190259c993d1SWarner Losh 190359c993d1SWarner Losh for (i = 0; i < MV_WIN_XOR_MAX; i++) { 190459c993d1SWarner Losh win_xor_br_write(base, i, e, 0); 190559c993d1SWarner Losh win_xor_sz_write(base, i, e, 0); 190659c993d1SWarner Losh } 190759c993d1SWarner Losh 190859c993d1SWarner Losh if (win_xor_can_remap(i) == 1) 190959c993d1SWarner Losh win_xor_har_write(base, i, e, 0); 191059c993d1SWarner Losh 191159c993d1SWarner Losh for (i = 0; i < MV_XOR_CHAN_MAX; i++) { 191259c993d1SWarner Losh win_xor_ctrl_write(base, i, e, 0); 191359c993d1SWarner Losh xor_active_dram(base, i, e, &window); 191459c993d1SWarner Losh } 191559c993d1SWarner Losh 191659c993d1SWarner Losh /* 191759c993d1SWarner Losh * Remaining targets -- from a statically defined table 191859c993d1SWarner Losh */ 191959c993d1SWarner Losh for (i = 0; i < xor_wins_no; i++) 192059c993d1SWarner Losh if (xor_wins[i].target > 0) { 192159c993d1SWarner Losh br = (xor_wins[i].base & 0xffff0000) | 192259c993d1SWarner Losh (xor_wins[i].attr << 8) | 192359c993d1SWarner Losh xor_wins[i].target; 192459c993d1SWarner Losh sz = ((xor_wins[i].size - 1) & 0xffff0000); 192559c993d1SWarner Losh 192659c993d1SWarner Losh /* Set the first free XOR window */ 192759c993d1SWarner Losh for (z = 0; z < MV_WIN_XOR_MAX; z++) { 192859c993d1SWarner Losh if (xor_ctrl_read(base, z, 0, e) && 192959c993d1SWarner Losh xor_ctrl_read(base, z, 1, e)) 193059c993d1SWarner Losh continue; 193159c993d1SWarner Losh 193259c993d1SWarner Losh /* Configure window */ 193359c993d1SWarner Losh win_xor_br_write(base, z, e, br); 193459c993d1SWarner Losh win_xor_sz_write(base, z, e, sz); 193559c993d1SWarner Losh if (win_xor_can_remap(z) && 193659c993d1SWarner Losh xor_wins[z].remap >= 0) 193759c993d1SWarner Losh win_xor_har_write(base, z, e, 193859c993d1SWarner Losh xor_wins[z].remap); 193959c993d1SWarner Losh 194059c993d1SWarner Losh /* Set protection RW on all channels */ 194159c993d1SWarner Losh xor_set_prot(base, z, e, 0x3); 194259c993d1SWarner Losh 194359c993d1SWarner Losh /* Enable window */ 194459c993d1SWarner Losh xor_ctrl_write(base, z, 0, e, 1); 194559c993d1SWarner Losh xor_ctrl_write(base, z, 1, e, 1); 194659c993d1SWarner Losh break; 194759c993d1SWarner Losh } 194859c993d1SWarner Losh } 194959c993d1SWarner Losh } 195059c993d1SWarner Losh } 195159c993d1SWarner Losh 195259c993d1SWarner Losh int 195359c993d1SWarner Losh decode_win_xor_valid(void) 195459c993d1SWarner Losh { 195559c993d1SWarner Losh const struct decode_win *wintab; 195659c993d1SWarner Losh int c, i, j, rv; 195759c993d1SWarner Losh uint32_t b, e, s; 195859c993d1SWarner Losh 195959c993d1SWarner Losh if (xor_wins_no > MV_WIN_XOR_MAX) { 196059c993d1SWarner Losh printf("XOR windows: too many entries: %d\n", xor_wins_no); 196159c993d1SWarner Losh return (0); 196259c993d1SWarner Losh } 196359c993d1SWarner Losh for (i = 0, c = 0; i < MV_WIN_DDR_MAX; i++) 196459c993d1SWarner Losh if (ddr_is_active(i)) 196559c993d1SWarner Losh c++; 196659c993d1SWarner Losh 196759c993d1SWarner Losh if (xor_wins_no > (MV_WIN_XOR_MAX - c)) { 196859c993d1SWarner Losh printf("XOR windows: too many entries: %d, available: %d\n", 196959c993d1SWarner Losh xor_wins_no, MV_WIN_IDMA_MAX - c); 197059c993d1SWarner Losh return (0); 197159c993d1SWarner Losh } 197259c993d1SWarner Losh 197359c993d1SWarner Losh wintab = xor_wins; 197459c993d1SWarner Losh rv = 1; 197559c993d1SWarner Losh for (i = 0; i < xor_wins_no; i++, wintab++) { 197659c993d1SWarner Losh 197759c993d1SWarner Losh if (wintab->target == 0) { 197859c993d1SWarner Losh printf("XOR window#%d: DDR target window is not " 197959c993d1SWarner Losh "supposed to be reprogrammed!\n", i); 198059c993d1SWarner Losh rv = 0; 198159c993d1SWarner Losh } 198259c993d1SWarner Losh 198359c993d1SWarner Losh if (wintab->remap >= 0 && win_cpu_can_remap(i) != 1) { 198459c993d1SWarner Losh printf("XOR window#%d: not capable of remapping, but " 198559c993d1SWarner Losh "val 0x%08x defined\n", i, wintab->remap); 198659c993d1SWarner Losh rv = 0; 198759c993d1SWarner Losh } 198859c993d1SWarner Losh 198959c993d1SWarner Losh s = wintab->size; 199059c993d1SWarner Losh b = wintab->base; 199159c993d1SWarner Losh e = b + s - 1; 199259c993d1SWarner Losh if (s > (0xFFFFFFFF - b + 1)) { 199359c993d1SWarner Losh /* 199459c993d1SWarner Losh * XXX this boundary check should account for 64bit 199559c993d1SWarner Losh * and remapping.. 199659c993d1SWarner Losh */ 199759c993d1SWarner Losh printf("XOR window#%d: no space for size 0x%08x at " 199859c993d1SWarner Losh "0x%08x\n", i, s, b); 199959c993d1SWarner Losh rv = 0; 200059c993d1SWarner Losh continue; 200159c993d1SWarner Losh } 200259c993d1SWarner Losh 200359c993d1SWarner Losh j = decode_win_overlap(i, xor_wins_no, &xor_wins[0]); 200459c993d1SWarner Losh if (j >= 0) { 200559c993d1SWarner Losh printf("XOR window#%d: (0x%08x - 0x%08x) overlaps " 200659c993d1SWarner Losh "with #%d (0x%08x - 0x%08x)\n", i, b, e, j, 200759c993d1SWarner Losh xor_wins[j].base, 200859c993d1SWarner Losh xor_wins[j].base + xor_wins[j].size - 1); 200959c993d1SWarner Losh rv = 0; 201059c993d1SWarner Losh } 201159c993d1SWarner Losh } 201259c993d1SWarner Losh 201359c993d1SWarner Losh return (rv); 201459c993d1SWarner Losh } 201559c993d1SWarner Losh 201659c993d1SWarner Losh void 201759c993d1SWarner Losh decode_win_xor_dump(u_long base) 201859c993d1SWarner Losh { 201959c993d1SWarner Losh int i, j; 202059c993d1SWarner Losh int e = 1; 202159c993d1SWarner Losh 202259c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_XOR)) 202359c993d1SWarner Losh return; 202459c993d1SWarner Losh 202559c993d1SWarner Losh for (j = 0; j < xor_max_eng(); j++, e--) { 202659c993d1SWarner Losh for (i = 0; i < MV_WIN_XOR_MAX; i++) { 202759c993d1SWarner Losh printf("XOR window#%d: b 0x%08x, s 0x%08x", i, 202859c993d1SWarner Losh win_xor_br_read(base, i, e), win_xor_sz_read(base, i, e)); 202959c993d1SWarner Losh 203059c993d1SWarner Losh if (win_xor_can_remap(i)) 203159c993d1SWarner Losh printf(", ha 0x%08x", win_xor_har_read(base, i, e)); 203259c993d1SWarner Losh 203359c993d1SWarner Losh printf("\n"); 203459c993d1SWarner Losh } 203559c993d1SWarner Losh for (i = 0; i < MV_XOR_CHAN_MAX; i++) 203659c993d1SWarner Losh printf("XOR control#%d: 0x%08x\n", i, 203759c993d1SWarner Losh win_xor_ctrl_read(base, i, e)); 203859c993d1SWarner Losh } 203959c993d1SWarner Losh } 204059c993d1SWarner Losh 204159c993d1SWarner Losh #else 204259c993d1SWarner Losh /* Provide dummy functions to satisfy the build for SoCs not equipped with XOR */ 204359c993d1SWarner Losh static int 204459c993d1SWarner Losh decode_win_xor_valid(void) 204559c993d1SWarner Losh { 204659c993d1SWarner Losh 204759c993d1SWarner Losh return (1); 204859c993d1SWarner Losh } 204959c993d1SWarner Losh 205059c993d1SWarner Losh static void 205159c993d1SWarner Losh decode_win_xor_setup(u_long base) 205259c993d1SWarner Losh { 205359c993d1SWarner Losh } 205459c993d1SWarner Losh 205559c993d1SWarner Losh static void 205659c993d1SWarner Losh decode_win_xor_dump(u_long base) 205759c993d1SWarner Losh { 205859c993d1SWarner Losh } 205959c993d1SWarner Losh #endif 206059c993d1SWarner Losh 206159c993d1SWarner Losh /************************************************************************** 206259c993d1SWarner Losh * SATA windows routines 206359c993d1SWarner Losh **************************************************************************/ 206459c993d1SWarner Losh static void 206559c993d1SWarner Losh decode_win_sata_setup(u_long base) 206659c993d1SWarner Losh { 206759c993d1SWarner Losh uint32_t cr, br; 206859c993d1SWarner Losh int i, j; 206959c993d1SWarner Losh 207059c993d1SWarner Losh if (pm_is_disabled(CPU_PM_CTRL_SATA)) 207159c993d1SWarner Losh return; 207259c993d1SWarner Losh 207359c993d1SWarner Losh for (i = 0; i < MV_WIN_SATA_MAX; i++) { 207459c993d1SWarner Losh win_sata_cr_write(base, i, 0); 207559c993d1SWarner Losh win_sata_br_write(base, i, 0); 207659c993d1SWarner Losh } 207759c993d1SWarner Losh 207859c993d1SWarner Losh for (i = 0; i < MV_WIN_DDR_MAX; i++) 207959c993d1SWarner Losh if (ddr_is_active(i)) { 208059c993d1SWarner Losh cr = ((ddr_size(i) - 1) & 0xffff0000) | 208159c993d1SWarner Losh (ddr_attr(i) << 8) | (ddr_target(i) << 4) | 1; 208259c993d1SWarner Losh br = ddr_base(i); 208359c993d1SWarner Losh 208459c993d1SWarner Losh /* Use the first available SATA window */ 208559c993d1SWarner Losh for (j = 0; j < MV_WIN_SATA_MAX; j++) { 208659c993d1SWarner Losh if ((win_sata_cr_read(base, j) & 1) != 0) 208759c993d1SWarner Losh continue; 208859c993d1SWarner Losh 208959c993d1SWarner Losh win_sata_br_write(base, j, br); 209059c993d1SWarner Losh win_sata_cr_write(base, j, cr); 209159c993d1SWarner Losh break; 209259c993d1SWarner Losh } 209359c993d1SWarner Losh } 209459c993d1SWarner Losh } 209559c993d1SWarner Losh 2096518a87d7SWojciech Macek #ifdef SOC_MV_ARMADA38X 2097518a87d7SWojciech Macek /* 2098518a87d7SWojciech Macek * Configure AHCI decoding windows 2099518a87d7SWojciech Macek */ 2100ccd5b1b0SWojciech Macek static void 2101ccd5b1b0SWojciech Macek decode_win_ahci_setup(u_long base) 2102ccd5b1b0SWojciech Macek { 2103ccd5b1b0SWojciech Macek uint32_t br, cr, sz; 2104ccd5b1b0SWojciech Macek int i, j; 2105ccd5b1b0SWojciech Macek 2106ccd5b1b0SWojciech Macek for (i = 0; i < MV_WIN_SATA_MAX; i++) { 2107ccd5b1b0SWojciech Macek win_sata_cr_write(base, i, 0); 2108ccd5b1b0SWojciech Macek win_sata_br_write(base, i, 0); 2109ccd5b1b0SWojciech Macek win_sata_sz_write(base, i, 0); 2110ccd5b1b0SWojciech Macek } 2111ccd5b1b0SWojciech Macek 2112ccd5b1b0SWojciech Macek for (i = 0; i < MV_WIN_DDR_MAX; i++) { 2113ccd5b1b0SWojciech Macek if (ddr_is_active(i)) { 2114ccd5b1b0SWojciech Macek cr = (ddr_attr(i) << IO_WIN_ATTR_SHIFT) | 2115ccd5b1b0SWojciech Macek (ddr_target(i) << IO_WIN_TGT_SHIFT) | 2116ccd5b1b0SWojciech Macek IO_WIN_ENA_MASK; 2117ccd5b1b0SWojciech Macek br = ddr_base(i); 2118ccd5b1b0SWojciech Macek sz = (ddr_size(i) - 1) & 2119ccd5b1b0SWojciech Macek (IO_WIN_SIZE_MASK << IO_WIN_SIZE_SHIFT); 2120ccd5b1b0SWojciech Macek 2121ccd5b1b0SWojciech Macek /* Use first available SATA window */ 2122ccd5b1b0SWojciech Macek for (j = 0; j < MV_WIN_SATA_MAX; j++) { 2123ccd5b1b0SWojciech Macek if (win_sata_cr_read(base, j) & IO_WIN_ENA_MASK) 2124ccd5b1b0SWojciech Macek continue; 2125ccd5b1b0SWojciech Macek 2126ccd5b1b0SWojciech Macek /* BASE is set to DRAM base (0x00000000) */ 2127ccd5b1b0SWojciech Macek win_sata_br_write(base, j, br); 2128ccd5b1b0SWojciech Macek /* CTRL targets DRAM ctrl with 0x0E or 0x0D */ 2129ccd5b1b0SWojciech Macek win_sata_cr_write(base, j, cr); 2130ccd5b1b0SWojciech Macek /* SIZE is set to 16MB - max value */ 2131ccd5b1b0SWojciech Macek win_sata_sz_write(base, j, sz); 2132ccd5b1b0SWojciech Macek break; 2133ccd5b1b0SWojciech Macek } 2134ccd5b1b0SWojciech Macek } 2135ccd5b1b0SWojciech Macek } 2136ccd5b1b0SWojciech Macek } 2137ccd5b1b0SWojciech Macek 2138ccd5b1b0SWojciech Macek static void 2139518a87d7SWojciech Macek decode_win_ahci_dump(u_long base) 2140ccd5b1b0SWojciech Macek { 2141ccd5b1b0SWojciech Macek int i; 2142ccd5b1b0SWojciech Macek 2143ccd5b1b0SWojciech Macek for (i = 0; i < MV_WIN_SATA_MAX; i++) 2144ccd5b1b0SWojciech Macek printf("SATA window#%d: cr 0x%08x, br 0x%08x, sz 0x%08x\n", i, 2145ccd5b1b0SWojciech Macek win_sata_cr_read(base, i), win_sata_br_read(base, i), 2146ccd5b1b0SWojciech Macek win_sata_sz_read(base,i)); 2147ccd5b1b0SWojciech Macek } 2148ccd5b1b0SWojciech Macek 2149518a87d7SWojciech Macek #else 2150518a87d7SWojciech Macek /* 2151518a87d7SWojciech Macek * Provide dummy functions to satisfy the build 2152518a87d7SWojciech Macek * for SoC's not equipped with AHCI controller 2153518a87d7SWojciech Macek */ 2154518a87d7SWojciech Macek static void 2155518a87d7SWojciech Macek decode_win_ahci_setup(u_long base) 2156518a87d7SWojciech Macek { 2157518a87d7SWojciech Macek } 2158518a87d7SWojciech Macek 2159518a87d7SWojciech Macek static void 2160518a87d7SWojciech Macek decode_win_ahci_dump(u_long base) 2161518a87d7SWojciech Macek { 2162518a87d7SWojciech Macek } 2163518a87d7SWojciech Macek #endif 2164518a87d7SWojciech Macek 216559c993d1SWarner Losh static int 216659c993d1SWarner Losh decode_win_sata_valid(void) 216759c993d1SWarner Losh { 216859c993d1SWarner Losh uint32_t dev, rev; 216959c993d1SWarner Losh 217059c993d1SWarner Losh soc_id(&dev, &rev); 217159c993d1SWarner Losh if (dev == MV_DEV_88F5281) 217259c993d1SWarner Losh return (1); 217359c993d1SWarner Losh 217459c993d1SWarner Losh return (decode_win_can_cover_ddr(MV_WIN_SATA_MAX)); 217559c993d1SWarner Losh } 217659c993d1SWarner Losh 217798a2d78dSLuiz Otavio O Souza static void 217898a2d78dSLuiz Otavio O Souza decode_win_sdhci_setup(u_long base) 217998a2d78dSLuiz Otavio O Souza { 218098a2d78dSLuiz Otavio O Souza uint32_t cr, br; 218198a2d78dSLuiz Otavio O Souza int i, j; 218298a2d78dSLuiz Otavio O Souza 218398a2d78dSLuiz Otavio O Souza for (i = 0; i < MV_WIN_SDHCI_MAX; i++) { 218498a2d78dSLuiz Otavio O Souza win_sdhci_cr_write(base, i, 0); 218598a2d78dSLuiz Otavio O Souza win_sdhci_br_write(base, i, 0); 218698a2d78dSLuiz Otavio O Souza } 218798a2d78dSLuiz Otavio O Souza 218898a2d78dSLuiz Otavio O Souza for (i = 0; i < MV_WIN_DDR_MAX; i++) 218998a2d78dSLuiz Otavio O Souza if (ddr_is_active(i)) { 219098a2d78dSLuiz Otavio O Souza br = ddr_base(i); 219198a2d78dSLuiz Otavio O Souza cr = (((ddr_size(i) - 1) & 219298a2d78dSLuiz Otavio O Souza (IO_WIN_SIZE_MASK << IO_WIN_SIZE_SHIFT)) | 219398a2d78dSLuiz Otavio O Souza (ddr_attr(i) << IO_WIN_ATTR_SHIFT) | 219498a2d78dSLuiz Otavio O Souza (ddr_target(i) << IO_WIN_TGT_SHIFT) | 219598a2d78dSLuiz Otavio O Souza IO_WIN_ENA_MASK); 219698a2d78dSLuiz Otavio O Souza 219798a2d78dSLuiz Otavio O Souza /* Use the first available SDHCI window */ 219898a2d78dSLuiz Otavio O Souza for (j = 0; j < MV_WIN_SDHCI_MAX; j++) { 219998a2d78dSLuiz Otavio O Souza if (win_sdhci_cr_read(base, j) & IO_WIN_ENA_MASK) 220098a2d78dSLuiz Otavio O Souza continue; 220198a2d78dSLuiz Otavio O Souza 220298a2d78dSLuiz Otavio O Souza win_sdhci_cr_write(base, j, cr); 220398a2d78dSLuiz Otavio O Souza win_sdhci_br_write(base, j, br); 220498a2d78dSLuiz Otavio O Souza break; 220598a2d78dSLuiz Otavio O Souza } 220698a2d78dSLuiz Otavio O Souza } 220798a2d78dSLuiz Otavio O Souza } 220898a2d78dSLuiz Otavio O Souza 220998a2d78dSLuiz Otavio O Souza static void 221098a2d78dSLuiz Otavio O Souza decode_win_sdhci_dump(u_long base) 221198a2d78dSLuiz Otavio O Souza { 221298a2d78dSLuiz Otavio O Souza int i; 221398a2d78dSLuiz Otavio O Souza 221498a2d78dSLuiz Otavio O Souza for (i = 0; i < MV_WIN_SDHCI_MAX; i++) 221598a2d78dSLuiz Otavio O Souza printf("SDHCI window#%d: c 0x%08x, b 0x%08x\n", i, 221698a2d78dSLuiz Otavio O Souza win_sdhci_cr_read(base, i), win_sdhci_br_read(base, i)); 221798a2d78dSLuiz Otavio O Souza } 221898a2d78dSLuiz Otavio O Souza 221998a2d78dSLuiz Otavio O Souza static int 222098a2d78dSLuiz Otavio O Souza decode_win_sdhci_valid(void) 222198a2d78dSLuiz Otavio O Souza { 222298a2d78dSLuiz Otavio O Souza 222398a2d78dSLuiz Otavio O Souza #ifdef SOC_MV_ARMADA38X 222498a2d78dSLuiz Otavio O Souza return (decode_win_can_cover_ddr(MV_WIN_SDHCI_MAX)); 222598a2d78dSLuiz Otavio O Souza #endif 222698a2d78dSLuiz Otavio O Souza 222798a2d78dSLuiz Otavio O Souza /* Satisfy platforms not equipped with this controller. */ 222898a2d78dSLuiz Otavio O Souza return (1); 222998a2d78dSLuiz Otavio O Souza } 223098a2d78dSLuiz Otavio O Souza 223159c993d1SWarner Losh /************************************************************************** 223259c993d1SWarner Losh * FDT parsing routines. 223359c993d1SWarner Losh **************************************************************************/ 223459c993d1SWarner Losh 223559c993d1SWarner Losh static int 223659c993d1SWarner Losh fdt_get_ranges(const char *nodename, void *buf, int size, int *tuples, 223759c993d1SWarner Losh int *tuplesize) 223859c993d1SWarner Losh { 223959c993d1SWarner Losh phandle_t node; 224059c993d1SWarner Losh pcell_t addr_cells, par_addr_cells, size_cells; 224159c993d1SWarner Losh int len, tuple_size, tuples_count; 224259c993d1SWarner Losh 224359c993d1SWarner Losh node = OF_finddevice(nodename); 224459c993d1SWarner Losh if (node == -1) 224559c993d1SWarner Losh return (EINVAL); 224659c993d1SWarner Losh 224759c993d1SWarner Losh if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0) 224859c993d1SWarner Losh return (ENXIO); 224959c993d1SWarner Losh 225059c993d1SWarner Losh par_addr_cells = fdt_parent_addr_cells(node); 225159c993d1SWarner Losh if (par_addr_cells > 2) 225259c993d1SWarner Losh return (ERANGE); 225359c993d1SWarner Losh 225459c993d1SWarner Losh tuple_size = sizeof(pcell_t) * (addr_cells + par_addr_cells + 225559c993d1SWarner Losh size_cells); 225659c993d1SWarner Losh 225759c993d1SWarner Losh /* Note the OF_getprop_alloc() cannot be used at this early stage. */ 225859c993d1SWarner Losh len = OF_getprop(node, "ranges", buf, size); 225959c993d1SWarner Losh 226059c993d1SWarner Losh /* 226159c993d1SWarner Losh * XXX this does not handle the empty 'ranges;' case, which is 226259c993d1SWarner Losh * legitimate and should be allowed. 226359c993d1SWarner Losh */ 226459c993d1SWarner Losh tuples_count = len / tuple_size; 226559c993d1SWarner Losh if (tuples_count <= 0) 226659c993d1SWarner Losh return (ERANGE); 226759c993d1SWarner Losh 22681f7f3314SRuslan Bukin if (par_addr_cells > 2 || addr_cells > 2 || size_cells > 2) 226959c993d1SWarner Losh return (ERANGE); 227059c993d1SWarner Losh 227159c993d1SWarner Losh *tuples = tuples_count; 227259c993d1SWarner Losh *tuplesize = tuple_size; 227359c993d1SWarner Losh return (0); 227459c993d1SWarner Losh } 227559c993d1SWarner Losh 227659c993d1SWarner Losh static int 227759c993d1SWarner Losh win_cpu_from_dt(void) 227859c993d1SWarner Losh { 227959c993d1SWarner Losh pcell_t ranges[48]; 228059c993d1SWarner Losh phandle_t node; 228159c993d1SWarner Losh int i, entry_size, err, t, tuple_size, tuples; 228259c993d1SWarner Losh u_long sram_base, sram_size; 228359c993d1SWarner Losh 228459c993d1SWarner Losh t = 0; 228559c993d1SWarner Losh /* Retrieve 'ranges' property of '/localbus' node. */ 228659c993d1SWarner Losh if ((err = fdt_get_ranges("/localbus", ranges, sizeof(ranges), 228759c993d1SWarner Losh &tuples, &tuple_size)) == 0) { 228859c993d1SWarner Losh /* 228959c993d1SWarner Losh * Fill CPU decode windows table. 229059c993d1SWarner Losh */ 229159c993d1SWarner Losh bzero((void *)&cpu_win_tbl, sizeof(cpu_win_tbl)); 229259c993d1SWarner Losh 229359c993d1SWarner Losh entry_size = tuple_size / sizeof(pcell_t); 229459c993d1SWarner Losh cpu_wins_no = tuples; 229559c993d1SWarner Losh 229670d16332SZbigniew Bodek /* Check range */ 229770d16332SZbigniew Bodek if (tuples > nitems(cpu_win_tbl)) { 229870d16332SZbigniew Bodek debugf("too many tuples to fit into cpu_win_tbl\n"); 229970d16332SZbigniew Bodek return (ENOMEM); 230070d16332SZbigniew Bodek } 230170d16332SZbigniew Bodek 230259c993d1SWarner Losh for (i = 0, t = 0; t < tuples; i += entry_size, t++) { 230359c993d1SWarner Losh cpu_win_tbl[t].target = 1; 230459c993d1SWarner Losh cpu_win_tbl[t].attr = fdt32_to_cpu(ranges[i + 1]); 230559c993d1SWarner Losh cpu_win_tbl[t].base = fdt32_to_cpu(ranges[i + 2]); 230659c993d1SWarner Losh cpu_win_tbl[t].size = fdt32_to_cpu(ranges[i + 3]); 230759c993d1SWarner Losh cpu_win_tbl[t].remap = ~0; 230859c993d1SWarner Losh debugf("target = 0x%0x attr = 0x%0x base = 0x%0x " 230959c993d1SWarner Losh "size = 0x%0x remap = 0x%0x\n", 231059c993d1SWarner Losh cpu_win_tbl[t].target, 231159c993d1SWarner Losh cpu_win_tbl[t].attr, cpu_win_tbl[t].base, 231259c993d1SWarner Losh cpu_win_tbl[t].size, cpu_win_tbl[t].remap); 231359c993d1SWarner Losh } 231459c993d1SWarner Losh } 231559c993d1SWarner Losh 231659c993d1SWarner Losh /* 231759c993d1SWarner Losh * Retrieve CESA SRAM data. 231859c993d1SWarner Losh */ 231959c993d1SWarner Losh if ((node = OF_finddevice("sram")) != -1) 232087acb7f8SAndrew Turner if (ofw_bus_node_is_compatible(node, "mrvl,cesa-sram")) 232159c993d1SWarner Losh goto moveon; 232259c993d1SWarner Losh 232359c993d1SWarner Losh if ((node = OF_finddevice("/")) == 0) 232459c993d1SWarner Losh return (ENXIO); 232559c993d1SWarner Losh 232659c993d1SWarner Losh if ((node = fdt_find_compatible(node, "mrvl,cesa-sram", 0)) == 0) 232759c993d1SWarner Losh /* SRAM block is not always present. */ 232859c993d1SWarner Losh return (0); 232959c993d1SWarner Losh moveon: 233059c993d1SWarner Losh sram_base = sram_size = 0; 233159c993d1SWarner Losh if (fdt_regsize(node, &sram_base, &sram_size) != 0) 233259c993d1SWarner Losh return (EINVAL); 233359c993d1SWarner Losh 233470d16332SZbigniew Bodek /* Check range */ 233570d16332SZbigniew Bodek if (t >= nitems(cpu_win_tbl)) { 233670d16332SZbigniew Bodek debugf("cannot fit CESA tuple into cpu_win_tbl\n"); 233770d16332SZbigniew Bodek return (ENOMEM); 233870d16332SZbigniew Bodek } 233970d16332SZbigniew Bodek 234059c993d1SWarner Losh cpu_win_tbl[t].target = MV_WIN_CESA_TARGET; 23415d7cb9a8SZbigniew Bodek #ifdef SOC_MV_ARMADA38X 23425d7cb9a8SZbigniew Bodek cpu_win_tbl[t].attr = MV_WIN_CESA_ATTR(0); 23435d7cb9a8SZbigniew Bodek #else 23445d7cb9a8SZbigniew Bodek cpu_win_tbl[t].attr = MV_WIN_CESA_ATTR(1); 23455d7cb9a8SZbigniew Bodek #endif 23465d7cb9a8SZbigniew Bodek cpu_win_tbl[t].base = sram_base; 23475d7cb9a8SZbigniew Bodek cpu_win_tbl[t].size = sram_size; 23485d7cb9a8SZbigniew Bodek cpu_win_tbl[t].remap = ~0; 23495d7cb9a8SZbigniew Bodek cpu_wins_no++; 23505d7cb9a8SZbigniew Bodek debugf("sram: base = 0x%0lx size = 0x%0lx\n", sram_base, sram_size); 23515d7cb9a8SZbigniew Bodek 23525d7cb9a8SZbigniew Bodek /* Check if there is a second CESA node */ 23535d7cb9a8SZbigniew Bodek while ((node = OF_peer(node)) != 0) { 235487acb7f8SAndrew Turner if (ofw_bus_node_is_compatible(node, "mrvl,cesa-sram")) { 23555d7cb9a8SZbigniew Bodek if (fdt_regsize(node, &sram_base, &sram_size) != 0) 23565d7cb9a8SZbigniew Bodek return (EINVAL); 23575d7cb9a8SZbigniew Bodek break; 23585d7cb9a8SZbigniew Bodek } 23595d7cb9a8SZbigniew Bodek } 23605d7cb9a8SZbigniew Bodek 23615d7cb9a8SZbigniew Bodek if (node == 0) 23625d7cb9a8SZbigniew Bodek return (0); 23635d7cb9a8SZbigniew Bodek 23645d7cb9a8SZbigniew Bodek t++; 236585bf4227SZbigniew Bodek if (t >= nitems(cpu_win_tbl)) { 23665d7cb9a8SZbigniew Bodek debugf("cannot fit CESA tuple into cpu_win_tbl\n"); 23675d7cb9a8SZbigniew Bodek return (ENOMEM); 23685d7cb9a8SZbigniew Bodek } 23695d7cb9a8SZbigniew Bodek 23705d7cb9a8SZbigniew Bodek /* Configure window for CESA1 */ 23715d7cb9a8SZbigniew Bodek cpu_win_tbl[t].target = MV_WIN_CESA_TARGET; 237259c993d1SWarner Losh cpu_win_tbl[t].attr = MV_WIN_CESA_ATTR(1); 237359c993d1SWarner Losh cpu_win_tbl[t].base = sram_base; 237459c993d1SWarner Losh cpu_win_tbl[t].size = sram_size; 237559c993d1SWarner Losh cpu_win_tbl[t].remap = ~0; 237659c993d1SWarner Losh cpu_wins_no++; 237759c993d1SWarner Losh debugf("sram: base = 0x%0lx size = 0x%0lx\n", sram_base, sram_size); 237859c993d1SWarner Losh 237959c993d1SWarner Losh return (0); 238059c993d1SWarner Losh } 238159c993d1SWarner Losh 238259c993d1SWarner Losh static int 238359c993d1SWarner Losh fdt_win_setup(void) 238459c993d1SWarner Losh { 238549b5f559SZbigniew Bodek phandle_t node, child, sb; 238659c993d1SWarner Losh struct soc_node_spec *soc_node; 238759c993d1SWarner Losh u_long size, base; 238859c993d1SWarner Losh int err, i; 238959c993d1SWarner Losh 239049b5f559SZbigniew Bodek sb = 0; 239159c993d1SWarner Losh node = OF_finddevice("/"); 239259c993d1SWarner Losh if (node == -1) 239359c993d1SWarner Losh panic("fdt_win_setup: no root node"); 239459c993d1SWarner Losh 239559c993d1SWarner Losh /* 239659c993d1SWarner Losh * Traverse through all children of root and simple-bus nodes. 239759c993d1SWarner Losh * For each found device retrieve decode windows data (if applicable). 239859c993d1SWarner Losh */ 239959c993d1SWarner Losh child = OF_child(node); 240059c993d1SWarner Losh while (child != 0) { 240159c993d1SWarner Losh for (i = 0; soc_nodes[i].compat != NULL; i++) { 240259c993d1SWarner Losh 240359c993d1SWarner Losh soc_node = &soc_nodes[i]; 240459c993d1SWarner Losh 2405228042ceSWojciech Macek /* Setup only for enabled devices */ 2406228042ceSWojciech Macek if (ofw_bus_node_status_okay(child) == 0) 2407228042ceSWojciech Macek continue; 2408228042ceSWojciech Macek 240987acb7f8SAndrew Turner if (!ofw_bus_node_is_compatible(child,soc_node->compat)) 241059c993d1SWarner Losh continue; 241159c993d1SWarner Losh 241259c993d1SWarner Losh err = fdt_regsize(child, &base, &size); 241359c993d1SWarner Losh if (err != 0) 241459c993d1SWarner Losh return (err); 241559c993d1SWarner Losh 241659c993d1SWarner Losh base = (base & 0x000fffff) | fdt_immr_va; 241759c993d1SWarner Losh if (soc_node->decode_handler != NULL) 241859c993d1SWarner Losh soc_node->decode_handler(base); 241959c993d1SWarner Losh else 242059c993d1SWarner Losh return (ENXIO); 242159c993d1SWarner Losh 242259c993d1SWarner Losh if (MV_DUMP_WIN && (soc_node->dump_handler != NULL)) 242359c993d1SWarner Losh soc_node->dump_handler(base); 242459c993d1SWarner Losh } 242559c993d1SWarner Losh 242659c993d1SWarner Losh /* 242759c993d1SWarner Losh * Once done with root-level children let's move down to 242859c993d1SWarner Losh * simple-bus and its children. 242959c993d1SWarner Losh */ 243059c993d1SWarner Losh child = OF_peer(child); 243159c993d1SWarner Losh if ((child == 0) && (node == OF_finddevice("/"))) { 243249b5f559SZbigniew Bodek sb = node = fdt_find_compatible(node, "simple-bus", 0); 243359c993d1SWarner Losh if (node == 0) 243459c993d1SWarner Losh return (ENXIO); 243559c993d1SWarner Losh child = OF_child(node); 243659c993d1SWarner Losh } 243734a3d2c6SWojciech Macek /* 243834a3d2c6SWojciech Macek * Next, move one more level down to internal-regs node (if 243934a3d2c6SWojciech Macek * it is present) and its children. This node also have 244034a3d2c6SWojciech Macek * "simple-bus" compatible. 244134a3d2c6SWojciech Macek */ 244249b5f559SZbigniew Bodek if ((child == 0) && (node == sb)) { 244334a3d2c6SWojciech Macek node = fdt_find_compatible(node, "simple-bus", 0); 244434a3d2c6SWojciech Macek if (node == 0) 244534a3d2c6SWojciech Macek return (0); 244634a3d2c6SWojciech Macek child = OF_child(node); 244734a3d2c6SWojciech Macek } 244859c993d1SWarner Losh } 244959c993d1SWarner Losh 245059c993d1SWarner Losh return (0); 245159c993d1SWarner Losh } 245259c993d1SWarner Losh 245359c993d1SWarner Losh static void 245459c993d1SWarner Losh fdt_fixup_busfreq(phandle_t root) 245559c993d1SWarner Losh { 245659c993d1SWarner Losh phandle_t sb; 245759c993d1SWarner Losh pcell_t freq; 245859c993d1SWarner Losh 245959c993d1SWarner Losh freq = cpu_to_fdt32(get_tclk()); 246059c993d1SWarner Losh 246159c993d1SWarner Losh /* 246259c993d1SWarner Losh * Fix bus speed in cpu node 246359c993d1SWarner Losh */ 246459c993d1SWarner Losh if ((sb = OF_finddevice("cpu")) != 0) 246559c993d1SWarner Losh if (fdt_is_compatible_strict(sb, "ARM,88VS584")) 246659c993d1SWarner Losh OF_setprop(sb, "bus-frequency", (void *)&freq, 246759c993d1SWarner Losh sizeof(freq)); 246859c993d1SWarner Losh 246959c993d1SWarner Losh /* 247059c993d1SWarner Losh * This fixup sets the simple-bus bus-frequency property. 247159c993d1SWarner Losh */ 247259c993d1SWarner Losh if ((sb = fdt_find_compatible(root, "simple-bus", 1)) != 0) 247359c993d1SWarner Losh OF_setprop(sb, "bus-frequency", (void *)&freq, sizeof(freq)); 247459c993d1SWarner Losh } 247559c993d1SWarner Losh 247659c993d1SWarner Losh static void 247759c993d1SWarner Losh fdt_fixup_ranges(phandle_t root) 247859c993d1SWarner Losh { 247959c993d1SWarner Losh phandle_t node; 248059c993d1SWarner Losh pcell_t par_addr_cells, addr_cells, size_cells; 248159c993d1SWarner Losh pcell_t ranges[3], reg[2], *rangesptr; 248259c993d1SWarner Losh int len, tuple_size, tuples_count; 248359c993d1SWarner Losh uint32_t base; 248459c993d1SWarner Losh 248559c993d1SWarner Losh /* Fix-up SoC ranges according to real fdt_immr_pa */ 248659c993d1SWarner Losh if ((node = fdt_find_compatible(root, "simple-bus", 1)) != 0) { 248759c993d1SWarner Losh if (fdt_addrsize_cells(node, &addr_cells, &size_cells) == 0 && 248859c993d1SWarner Losh (par_addr_cells = fdt_parent_addr_cells(node) <= 2)) { 248959c993d1SWarner Losh tuple_size = sizeof(pcell_t) * (par_addr_cells + 249059c993d1SWarner Losh addr_cells + size_cells); 249159c993d1SWarner Losh len = OF_getprop(node, "ranges", ranges, 249259c993d1SWarner Losh sizeof(ranges)); 249359c993d1SWarner Losh tuples_count = len / tuple_size; 249459c993d1SWarner Losh /* Unexpected settings are not supported */ 249559c993d1SWarner Losh if (tuples_count != 1) 249659c993d1SWarner Losh goto fixup_failed; 249759c993d1SWarner Losh 249859c993d1SWarner Losh rangesptr = &ranges[0]; 249959c993d1SWarner Losh rangesptr += par_addr_cells; 250059c993d1SWarner Losh base = fdt_data_get((void *)rangesptr, addr_cells); 250159c993d1SWarner Losh *rangesptr = cpu_to_fdt32(fdt_immr_pa); 250259c993d1SWarner Losh if (OF_setprop(node, "ranges", (void *)&ranges[0], 250359c993d1SWarner Losh sizeof(ranges)) < 0) 250459c993d1SWarner Losh goto fixup_failed; 250559c993d1SWarner Losh } 250659c993d1SWarner Losh } 250759c993d1SWarner Losh 250859c993d1SWarner Losh /* Fix-up PCIe reg according to real PCIe registers' PA */ 250959c993d1SWarner Losh if ((node = fdt_find_compatible(root, "mrvl,pcie", 1)) != 0) { 251059c993d1SWarner Losh if (fdt_addrsize_cells(OF_parent(node), &par_addr_cells, 251159c993d1SWarner Losh &size_cells) == 0) { 251259c993d1SWarner Losh tuple_size = sizeof(pcell_t) * (par_addr_cells + 251359c993d1SWarner Losh size_cells); 251459c993d1SWarner Losh len = OF_getprop(node, "reg", reg, sizeof(reg)); 251559c993d1SWarner Losh tuples_count = len / tuple_size; 251659c993d1SWarner Losh /* Unexpected settings are not supported */ 251759c993d1SWarner Losh if (tuples_count != 1) 251859c993d1SWarner Losh goto fixup_failed; 251959c993d1SWarner Losh 252059c993d1SWarner Losh base = fdt_data_get((void *)®[0], par_addr_cells); 252159c993d1SWarner Losh base &= ~0xFF000000; 252259c993d1SWarner Losh base |= fdt_immr_pa; 252359c993d1SWarner Losh reg[0] = cpu_to_fdt32(base); 252459c993d1SWarner Losh if (OF_setprop(node, "reg", (void *)®[0], 252559c993d1SWarner Losh sizeof(reg)) < 0) 252659c993d1SWarner Losh goto fixup_failed; 252759c993d1SWarner Losh } 252859c993d1SWarner Losh } 252959c993d1SWarner Losh /* Fix-up succeeded. May return and continue */ 253059c993d1SWarner Losh return; 253159c993d1SWarner Losh 253259c993d1SWarner Losh fixup_failed: 253359c993d1SWarner Losh while (1) { 253459c993d1SWarner Losh /* 253559c993d1SWarner Losh * In case of any error while fixing ranges just hang. 253659c993d1SWarner Losh * 1. No message can be displayed yet since console 253759c993d1SWarner Losh * is not initialized. 253859c993d1SWarner Losh * 2. Going further will cause failure on bus_space_map() 253959c993d1SWarner Losh * relying on the wrong ranges or data abort when 254059c993d1SWarner Losh * accessing PCIe registers. 254159c993d1SWarner Losh */ 254259c993d1SWarner Losh } 254359c993d1SWarner Losh } 254459c993d1SWarner Losh 254559c993d1SWarner Losh struct fdt_fixup_entry fdt_fixup_table[] = { 254659c993d1SWarner Losh { "mrvl,DB-88F6281", &fdt_fixup_busfreq }, 254759c993d1SWarner Losh { "mrvl,DB-78460", &fdt_fixup_busfreq }, 254859c993d1SWarner Losh { "mrvl,DB-78460", &fdt_fixup_ranges }, 254959c993d1SWarner Losh { NULL, NULL } 255059c993d1SWarner Losh }; 255159c993d1SWarner Losh 255259c3cb81SAndrew Turner #ifndef INTRNG 255359c993d1SWarner Losh static int 255459c993d1SWarner Losh fdt_pic_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig, 255559c993d1SWarner Losh int *pol) 255659c993d1SWarner Losh { 255759c993d1SWarner Losh 255887acb7f8SAndrew Turner if (!ofw_bus_node_is_compatible(node, "mrvl,pic") && 255987acb7f8SAndrew Turner !ofw_bus_node_is_compatible(node, "mrvl,mpic")) 256059c993d1SWarner Losh return (ENXIO); 256159c993d1SWarner Losh 256259c993d1SWarner Losh *interrupt = fdt32_to_cpu(intr[0]); 256359c993d1SWarner Losh *trig = INTR_TRIGGER_CONFORM; 256459c993d1SWarner Losh *pol = INTR_POLARITY_CONFORM; 256559c993d1SWarner Losh 256659c993d1SWarner Losh return (0); 256759c993d1SWarner Losh } 256859c993d1SWarner Losh 256959c993d1SWarner Losh fdt_pic_decode_t fdt_pic_table[] = { 257081c8a263SZbigniew Bodek #ifdef SOC_MV_ARMADA38X 257181c8a263SZbigniew Bodek &gic_decode_fdt, 257281c8a263SZbigniew Bodek #endif 257359c993d1SWarner Losh &fdt_pic_decode_ic, 257459c993d1SWarner Losh NULL 257559c993d1SWarner Losh }; 2576647a3bacSAndrew Turner #endif 257759c993d1SWarner Losh 257859c993d1SWarner Losh uint64_t 257959c993d1SWarner Losh get_sar_value(void) 258059c993d1SWarner Losh { 258159c993d1SWarner Losh uint32_t sar_low, sar_high; 258259c993d1SWarner Losh 258359c993d1SWarner Losh #if defined(SOC_MV_ARMADAXP) 258459c993d1SWarner Losh sar_high = bus_space_read_4(fdtbus_bs_tag, MV_MISC_BASE, 258559c993d1SWarner Losh SAMPLE_AT_RESET_HI); 258659c993d1SWarner Losh sar_low = bus_space_read_4(fdtbus_bs_tag, MV_MISC_BASE, 258759c993d1SWarner Losh SAMPLE_AT_RESET_LO); 2588f8742b0dSZbigniew Bodek #elif defined(SOC_MV_ARMADA38X) 2589f8742b0dSZbigniew Bodek sar_high = 0; 2590f8742b0dSZbigniew Bodek sar_low = bus_space_read_4(fdtbus_bs_tag, MV_MISC_BASE, 2591f8742b0dSZbigniew Bodek SAMPLE_AT_RESET); 259259c993d1SWarner Losh #else 259359c993d1SWarner Losh /* 259459c993d1SWarner Losh * TODO: Add getting proper values for other SoC configurations 259559c993d1SWarner Losh */ 259659c993d1SWarner Losh sar_high = 0; 259759c993d1SWarner Losh sar_low = 0; 259859c993d1SWarner Losh #endif 259959c993d1SWarner Losh 260059c993d1SWarner Losh return (((uint64_t)sar_high << 32) | sar_low); 260159c993d1SWarner Losh } 2602