linux/arch/arm/mach-versatile/versatile_dt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Versatile board support using the device tree
   4 *
   5 *  Copyright (C) 2010 Secret Lab Technologies Ltd.
   6 *  Copyright (C) 2009 Jeremy Kerr <jeremy.kerr@canonical.com>
   7 *  Copyright (C) 2004 ARM Limited
   8 *  Copyright (C) 2000 Deep Blue Solutions Ltd
   9 */
  10
  11#include <linux/init.h>
  12#include <linux/io.h>
  13#include <linux/of.h>
  14#include <linux/of_address.h>
  15#include <linux/of_irq.h>
  16#include <linux/of_platform.h>
  17#include <linux/slab.h>
  18#include <linux/amba/bus.h>
  19#include <linux/amba/mmci.h>
  20#include <asm/mach-types.h>
  21#include <asm/mach/arch.h>
  22#include <asm/mach/map.h>
  23
  24/* macro to get at MMIO space when running virtually */
  25#define IO_ADDRESS(x)           (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000)
  26#define __io_address(n)         ((void __iomem __force *)IO_ADDRESS(n))
  27
  28/*
  29 * ------------------------------------------------------------------------
  30 *  Versatile Registers
  31 * ------------------------------------------------------------------------
  32 */
  33#define VERSATILE_SYS_PCICTL_OFFSET           0x44
  34#define VERSATILE_SYS_MCI_OFFSET              0x48
  35
  36/*
  37 * VERSATILE peripheral addresses
  38 */
  39#define VERSATILE_MMCI0_BASE           0x10005000       /* MMC interface */
  40#define VERSATILE_MMCI1_BASE           0x1000B000       /* MMC Interface */
  41#define VERSATILE_SCTL_BASE            0x101E0000       /* System controller */
  42
  43/*
  44 * System controller bit assignment
  45 */
  46#define VERSATILE_REFCLK        0
  47#define VERSATILE_TIMCLK        1
  48
  49#define VERSATILE_TIMER1_EnSel  15
  50#define VERSATILE_TIMER2_EnSel  17
  51#define VERSATILE_TIMER3_EnSel  19
  52#define VERSATILE_TIMER4_EnSel  21
  53
  54static void __iomem *versatile_sys_base;
  55
  56unsigned int mmc_status(struct device *dev)
  57{
  58        struct amba_device *adev = container_of(dev, struct amba_device, dev);
  59        u32 mask;
  60
  61        if (adev->res.start == VERSATILE_MMCI0_BASE)
  62                mask = 1;
  63        else
  64                mask = 2;
  65
  66        return readl(versatile_sys_base + VERSATILE_SYS_MCI_OFFSET) & mask;
  67}
  68
  69static struct mmci_platform_data mmc0_plat_data = {
  70        .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
  71        .status         = mmc_status,
  72};
  73
  74static struct mmci_platform_data mmc1_plat_data = {
  75        .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
  76        .status         = mmc_status,
  77};
  78
  79/*
  80 * Lookup table for attaching a specific name and platform_data pointer to
  81 * devices as they get created by of_platform_populate().  Ideally this table
  82 * would not exist, but the current clock implementation depends on some devices
  83 * having a specific name.
  84 */
  85struct of_dev_auxdata versatile_auxdata_lookup[] __initdata = {
  86        OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI0_BASE, "fpga:05", &mmc0_plat_data),
  87        OF_DEV_AUXDATA("arm,primecell", VERSATILE_MMCI1_BASE, "fpga:0b", &mmc1_plat_data),
  88        {}
  89};
  90
  91static struct map_desc versatile_io_desc[] __initdata __maybe_unused = {
  92        {
  93                .virtual        =  IO_ADDRESS(VERSATILE_SCTL_BASE),
  94                .pfn            = __phys_to_pfn(VERSATILE_SCTL_BASE),
  95                .length         = SZ_4K * 9,
  96                .type           = MT_DEVICE
  97        }
  98};
  99
 100static void __init versatile_map_io(void)
 101{
 102        debug_ll_io_init();
 103        iotable_init(versatile_io_desc, ARRAY_SIZE(versatile_io_desc));
 104}
 105
 106static void __init versatile_init_early(void)
 107{
 108        u32 val;
 109
 110        /*
 111         * set clock frequency:
 112         *      VERSATILE_REFCLK is 32KHz
 113         *      VERSATILE_TIMCLK is 1MHz
 114         */
 115        val = readl(__io_address(VERSATILE_SCTL_BASE));
 116        writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) |
 117               (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) |
 118               (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) |
 119               (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val,
 120               __io_address(VERSATILE_SCTL_BASE));
 121}
 122
 123static void __init versatile_dt_pci_init(void)
 124{
 125        u32 val;
 126        struct device_node *np;
 127        struct property *newprop;
 128
 129        np = of_find_compatible_node(NULL, NULL, "arm,versatile-pci");
 130        if (!np)
 131                return;
 132
 133        /* Check if PCI backplane is detected */
 134        val = readl(versatile_sys_base + VERSATILE_SYS_PCICTL_OFFSET);
 135        if (val & 1) {
 136                /*
 137                 * Enable PCI accesses. Note that the documentaton is
 138                 * inconsistent whether or not this is needed, but the old
 139                 * driver had it so we will keep it.
 140                 */
 141                writel(1, versatile_sys_base + VERSATILE_SYS_PCICTL_OFFSET);
 142                goto out_put_node;
 143        }
 144
 145        newprop = kzalloc(sizeof(*newprop), GFP_KERNEL);
 146        if (!newprop)
 147                goto out_put_node;
 148
 149        newprop->name = kstrdup("status", GFP_KERNEL);
 150        newprop->value = kstrdup("disabled", GFP_KERNEL);
 151        newprop->length = sizeof("disabled");
 152        of_update_property(np, newprop);
 153
 154        pr_info("Not plugged into PCI backplane!\n");
 155
 156out_put_node:
 157        of_node_put(np);
 158}
 159
 160static void __init versatile_dt_init(void)
 161{
 162        struct device_node *np;
 163
 164        np = of_find_compatible_node(NULL, NULL, "arm,core-module-versatile");
 165        if (np)
 166                versatile_sys_base = of_iomap(np, 0);
 167        WARN_ON(!versatile_sys_base);
 168
 169        versatile_dt_pci_init();
 170
 171        of_platform_default_populate(NULL, versatile_auxdata_lookup, NULL);
 172}
 173
 174static const char *const versatile_dt_match[] __initconst = {
 175        "arm,versatile-ab",
 176        "arm,versatile-pb",
 177        NULL,
 178};
 179
 180DT_MACHINE_START(VERSATILE_PB, "ARM-Versatile (Device Tree Support)")
 181        .map_io         = versatile_map_io,
 182        .init_early     = versatile_init_early,
 183        .init_machine   = versatile_dt_init,
 184        .dt_compat      = versatile_dt_match,
 185MACHINE_END
 186