linux/arch/arc/plat-hsdk/platform.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * ARC HSDK Platform support code
   4 *
   5 * Copyright (C) 2017 Synopsys, Inc. (www.synopsys.com)
   6 */
   7
   8#include <linux/init.h>
   9#include <linux/of_fdt.h>
  10#include <linux/libfdt.h>
  11#include <linux/smp.h>
  12#include <asm/arcregs.h>
  13#include <asm/io.h>
  14#include <asm/mach_desc.h>
  15
  16int arc_hsdk_axi_dmac_coherent __section(".data") = 0;
  17
  18#define ARC_CCM_UNUSED_ADDR     0x60000000
  19
  20
  21#define ARC_PERIPHERAL_BASE     0xf0000000
  22#define CREG_BASE               (ARC_PERIPHERAL_BASE + 0x1000)
  23
  24#define SDIO_BASE               (ARC_PERIPHERAL_BASE + 0xA000)
  25#define SDIO_UHS_REG_EXT        (SDIO_BASE + 0x108)
  26#define SDIO_UHS_REG_EXT_DIV_2  (2 << 30)
  27
  28#define HSDK_GPIO_INTC          (ARC_PERIPHERAL_BASE + 0x3000)
  29
  30static void __init hsdk_enable_gpio_intc_wire(void)
  31{
  32        /*
  33         * Peripherals on CPU Card are wired to cpu intc via intermediate
  34         * DW APB GPIO blocks (mainly for debouncing)
  35         *
  36         *         ---------------------
  37         *        |  snps,archs-intc  |
  38         *        ---------------------
  39         *                  |
  40         *        ----------------------
  41         *        | snps,archs-idu-intc |
  42         *        ----------------------
  43         *         |   |     |   |    |
  44         *         | [eth] [USB]    [... other peripherals]
  45         *         |
  46         * -------------------
  47         * | snps,dw-apb-intc |
  48         * -------------------
  49         *  |      |   |   |
  50         * [Bt] [HAPS]   [... other peripherals]
  51         *
  52         * Current implementation of "irq-dw-apb-ictl" driver doesn't work well
  53         * with stacked INTCs. In particular problem happens if its master INTC
  54         * not yet instantiated. See discussion here -
  55         * https://lkml.org/lkml/2015/3/4/755
  56         *
  57         * So setup the first gpio block as a passive pass thru and hide it from
  58         * DT hardware topology - connect intc directly to cpu intc
  59         * The GPIO "wire" needs to be init nevertheless (here)
  60         *
  61         * One side adv is that peripheral interrupt handling avoids one nested
  62         * intc ISR hop
  63         *
  64         * According to HSDK User's Manual [1], "Table 2 Interrupt Mapping"
  65         * we have the following GPIO input lines used as sources of interrupt:
  66         * - GPIO[0] - Bluetooth interrupt of RS9113 module
  67         * - GPIO[2] - HAPS interrupt (on HapsTrak 3 connector)
  68         * - GPIO[3] - Audio codec (MAX9880A) interrupt
  69         * - GPIO[8-23] - Available on Arduino and PMOD_x headers
  70         * For now there's no use of Arduino and PMOD_x headers in Linux
  71         * use-case so we only enable lines 0, 2 and 3.
  72         *
  73         * [1] https://github.com/foss-for-synopsys-dwc-arc-processors/ARC-Development-Systems-Forum/wiki/docs/ARC_HSDK_User_Guide.pdf
  74         */
  75#define GPIO_INTEN              (HSDK_GPIO_INTC + 0x30)
  76#define GPIO_INTMASK            (HSDK_GPIO_INTC + 0x34)
  77#define GPIO_INTTYPE_LEVEL      (HSDK_GPIO_INTC + 0x38)
  78#define GPIO_INT_POLARITY       (HSDK_GPIO_INTC + 0x3c)
  79#define GPIO_INT_CONNECTED_MASK 0x0d
  80
  81        iowrite32(0xffffffff, (void __iomem *) GPIO_INTMASK);
  82        iowrite32(~GPIO_INT_CONNECTED_MASK, (void __iomem *) GPIO_INTMASK);
  83        iowrite32(0x00000000, (void __iomem *) GPIO_INTTYPE_LEVEL);
  84        iowrite32(0xffffffff, (void __iomem *) GPIO_INT_POLARITY);
  85        iowrite32(GPIO_INT_CONNECTED_MASK, (void __iomem *) GPIO_INTEN);
  86}
  87
  88static int __init hsdk_tweak_node_coherency(const char *path, bool coherent)
  89{
  90        void *fdt = initial_boot_params;
  91        const void *prop;
  92        int node, ret;
  93        bool dt_coh_set;
  94
  95        node = fdt_path_offset(fdt, path);
  96        if (node < 0)
  97                goto tweak_fail;
  98
  99        prop = fdt_getprop(fdt, node, "dma-coherent", &ret);
 100        if (!prop && ret != -FDT_ERR_NOTFOUND)
 101                goto tweak_fail;
 102
 103        dt_coh_set = ret != -FDT_ERR_NOTFOUND;
 104        ret = 0;
 105
 106        /* need to remove "dma-coherent" property */
 107        if (dt_coh_set && !coherent)
 108                ret = fdt_delprop(fdt, node, "dma-coherent");
 109
 110        /* need to set "dma-coherent" property */
 111        if (!dt_coh_set && coherent)
 112                ret = fdt_setprop(fdt, node, "dma-coherent", NULL, 0);
 113
 114        if (ret < 0)
 115                goto tweak_fail;
 116
 117        return 0;
 118
 119tweak_fail:
 120        pr_err("failed to tweak %s to %scoherent\n", path, coherent ? "" : "non");
 121        return -EFAULT;
 122}
 123
 124enum hsdk_axi_masters {
 125        M_HS_CORE = 0,
 126        M_HS_RTT,
 127        M_AXI_TUN,
 128        M_HDMI_VIDEO,
 129        M_HDMI_AUDIO,
 130        M_USB_HOST,
 131        M_ETHERNET,
 132        M_SDIO,
 133        M_GPU,
 134        M_DMAC_0,
 135        M_DMAC_1,
 136        M_DVFS
 137};
 138
 139#define UPDATE_VAL      1
 140
 141/*
 142 * This is modified configuration of AXI bridge. Default settings
 143 * are specified in "Table 111 CREG Address Decoder register reset values".
 144 *
 145 * AXI_M_m_SLV{0|1} - Slave Select register for master 'm'.
 146 * Possible slaves are:
 147 *  - 0  => no slave selected
 148 *  - 1  => DDR controller port #1
 149 *  - 2  => SRAM controller
 150 *  - 3  => AXI tunnel
 151 *  - 4  => EBI controller
 152 *  - 5  => ROM controller
 153 *  - 6  => AXI2APB bridge
 154 *  - 7  => DDR controller port #2
 155 *  - 8  => DDR controller port #3
 156 *  - 9  => HS38x4 IOC
 157 *  - 10 => HS38x4 DMI
 158 * AXI_M_m_OFFSET{0|1} - Addr Offset register for master 'm'
 159 *
 160 * Please read ARC HS Development IC Specification, section 17.2 for more
 161 * information about apertures configuration.
 162 *
 163 * m    master          AXI_M_m_SLV0    AXI_M_m_SLV1    AXI_M_m_OFFSET0 AXI_M_m_OFFSET1
 164 * 0    HS (CBU)        0x11111111      0x63111111      0xFEDCBA98      0x0E543210
 165 * 1    HS (RTT)        0x77777777      0x77777777      0xFEDCBA98      0x76543210
 166 * 2    AXI Tunnel      0x88888888      0x88888888      0xFEDCBA98      0x76543210
 167 * 3    HDMI-VIDEO      0x77777777      0x77777777      0xFEDCBA98      0x76543210
 168 * 4    HDMI-ADUIO      0x77777777      0x77777777      0xFEDCBA98      0x76543210
 169 * 5    USB-HOST        0x77777777      0x77999999      0xFEDCBA98      0x76DCBA98
 170 * 6    ETHERNET        0x77777777      0x77999999      0xFEDCBA98      0x76DCBA98
 171 * 7    SDIO            0x77777777      0x77999999      0xFEDCBA98      0x76DCBA98
 172 * 8    GPU             0x77777777      0x77777777      0xFEDCBA98      0x76543210
 173 * 9    DMAC (port #1)  0x77777777      0x77777777      0xFEDCBA98      0x76543210
 174 * 10   DMAC (port #2)  0x77777777      0x77777777      0xFEDCBA98      0x76543210
 175 * 11   DVFS            0x00000000      0x60000000      0x00000000      0x00000000
 176 */
 177
 178#define CREG_AXI_M_SLV0(m)  ((void __iomem *)(CREG_BASE + 0x20 * (m)))
 179#define CREG_AXI_M_SLV1(m)  ((void __iomem *)(CREG_BASE + 0x20 * (m) + 0x04))
 180#define CREG_AXI_M_OFT0(m)  ((void __iomem *)(CREG_BASE + 0x20 * (m) + 0x08))
 181#define CREG_AXI_M_OFT1(m)  ((void __iomem *)(CREG_BASE + 0x20 * (m) + 0x0C))
 182#define CREG_AXI_M_UPDT(m)  ((void __iomem *)(CREG_BASE + 0x20 * (m) + 0x14))
 183
 184#define CREG_AXI_M_HS_CORE_BOOT ((void __iomem *)(CREG_BASE + 0x010))
 185
 186#define CREG_PAE                ((void __iomem *)(CREG_BASE + 0x180))
 187#define CREG_PAE_UPDT           ((void __iomem *)(CREG_BASE + 0x194))
 188
 189static void __init hsdk_init_memory_bridge_axi_dmac(void)
 190{
 191        bool coherent = !!arc_hsdk_axi_dmac_coherent;
 192        u32 axi_m_slv1, axi_m_oft1;
 193
 194        /*
 195         * Don't tweak memory bridge configuration if we failed to tweak DTB
 196         * as we will end up in a inconsistent state.
 197         */
 198        if (hsdk_tweak_node_coherency("/soc/dmac@80000", coherent))
 199                return;
 200
 201        if (coherent) {
 202                axi_m_slv1 = 0x77999999;
 203                axi_m_oft1 = 0x76DCBA98;
 204        } else {
 205                axi_m_slv1 = 0x77777777;
 206                axi_m_oft1 = 0x76543210;
 207        }
 208
 209        writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_0));
 210        writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_0));
 211        writel(axi_m_slv1, CREG_AXI_M_SLV1(M_DMAC_0));
 212        writel(axi_m_oft1, CREG_AXI_M_OFT1(M_DMAC_0));
 213        writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_0));
 214
 215        writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_1));
 216        writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_1));
 217        writel(axi_m_slv1, CREG_AXI_M_SLV1(M_DMAC_1));
 218        writel(axi_m_oft1, CREG_AXI_M_OFT1(M_DMAC_1));
 219        writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_1));
 220}
 221
 222static void __init hsdk_init_memory_bridge(void)
 223{
 224        u32 reg;
 225
 226        /*
 227         * M_HS_CORE has one unique register - BOOT.
 228         * We need to clean boot mirror (BOOT[1:0]) bits in them to avoid first
 229         * aperture to be masked by 'boot mirror'.
 230         */
 231        reg = readl(CREG_AXI_M_HS_CORE_BOOT) & (~0x3);
 232        writel(reg, CREG_AXI_M_HS_CORE_BOOT);
 233        writel(0x11111111, CREG_AXI_M_SLV0(M_HS_CORE));
 234        writel(0x63111111, CREG_AXI_M_SLV1(M_HS_CORE));
 235        writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HS_CORE));
 236        writel(0x0E543210, CREG_AXI_M_OFT1(M_HS_CORE));
 237        writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HS_CORE));
 238
 239        writel(0x77777777, CREG_AXI_M_SLV0(M_HS_RTT));
 240        writel(0x77777777, CREG_AXI_M_SLV1(M_HS_RTT));
 241        writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HS_RTT));
 242        writel(0x76543210, CREG_AXI_M_OFT1(M_HS_RTT));
 243        writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HS_RTT));
 244
 245        writel(0x88888888, CREG_AXI_M_SLV0(M_AXI_TUN));
 246        writel(0x88888888, CREG_AXI_M_SLV1(M_AXI_TUN));
 247        writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_AXI_TUN));
 248        writel(0x76543210, CREG_AXI_M_OFT1(M_AXI_TUN));
 249        writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_AXI_TUN));
 250
 251        writel(0x77777777, CREG_AXI_M_SLV0(M_HDMI_VIDEO));
 252        writel(0x77777777, CREG_AXI_M_SLV1(M_HDMI_VIDEO));
 253        writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HDMI_VIDEO));
 254        writel(0x76543210, CREG_AXI_M_OFT1(M_HDMI_VIDEO));
 255        writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HDMI_VIDEO));
 256
 257        writel(0x77777777, CREG_AXI_M_SLV0(M_HDMI_AUDIO));
 258        writel(0x77777777, CREG_AXI_M_SLV1(M_HDMI_AUDIO));
 259        writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HDMI_AUDIO));
 260        writel(0x76543210, CREG_AXI_M_OFT1(M_HDMI_AUDIO));
 261        writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HDMI_AUDIO));
 262
 263        writel(0x77777777, CREG_AXI_M_SLV0(M_USB_HOST));
 264        writel(0x77999999, CREG_AXI_M_SLV1(M_USB_HOST));
 265        writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_USB_HOST));
 266        writel(0x76DCBA98, CREG_AXI_M_OFT1(M_USB_HOST));
 267        writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_USB_HOST));
 268
 269        writel(0x77777777, CREG_AXI_M_SLV0(M_ETHERNET));
 270        writel(0x77999999, CREG_AXI_M_SLV1(M_ETHERNET));
 271        writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_ETHERNET));
 272        writel(0x76DCBA98, CREG_AXI_M_OFT1(M_ETHERNET));
 273        writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_ETHERNET));
 274
 275        writel(0x77777777, CREG_AXI_M_SLV0(M_SDIO));
 276        writel(0x77999999, CREG_AXI_M_SLV1(M_SDIO));
 277        writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_SDIO));
 278        writel(0x76DCBA98, CREG_AXI_M_OFT1(M_SDIO));
 279        writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_SDIO));
 280
 281        writel(0x77777777, CREG_AXI_M_SLV0(M_GPU));
 282        writel(0x77777777, CREG_AXI_M_SLV1(M_GPU));
 283        writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_GPU));
 284        writel(0x76543210, CREG_AXI_M_OFT1(M_GPU));
 285        writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_GPU));
 286
 287        writel(0x00000000, CREG_AXI_M_SLV0(M_DVFS));
 288        writel(0x60000000, CREG_AXI_M_SLV1(M_DVFS));
 289        writel(0x00000000, CREG_AXI_M_OFT0(M_DVFS));
 290        writel(0x00000000, CREG_AXI_M_OFT1(M_DVFS));
 291        writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DVFS));
 292
 293        hsdk_init_memory_bridge_axi_dmac();
 294
 295        /*
 296         * PAE remapping for DMA clients does not work due to an RTL bug, so
 297         * CREG_PAE register must be programmed to all zeroes, otherwise it
 298         * will cause problems with DMA to/from peripherals even if PAE40 is
 299         * not used.
 300         */
 301        writel(0x00000000, CREG_PAE);
 302        writel(UPDATE_VAL, CREG_PAE_UPDT);
 303}
 304
 305static void __init hsdk_init_early(void)
 306{
 307        hsdk_init_memory_bridge();
 308
 309        /*
 310         * Switch SDIO external ciu clock divider from default div-by-8 to
 311         * minimum possible div-by-2.
 312         */
 313        iowrite32(SDIO_UHS_REG_EXT_DIV_2, (void __iomem *) SDIO_UHS_REG_EXT);
 314
 315        hsdk_enable_gpio_intc_wire();
 316}
 317
 318static const char *hsdk_compat[] __initconst = {
 319        "snps,hsdk",
 320        NULL,
 321};
 322
 323MACHINE_START(SIMULATION, "hsdk")
 324        .dt_compat      = hsdk_compat,
 325        .init_early     = hsdk_init_early,
 326MACHINE_END
 327