linux/arch/arm/mach-highbank/highbank.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright 2010-2011 Calxeda, Inc.
   4 */
   5#include <linux/clk.h>
   6#include <linux/clkdev.h>
   7#include <linux/clocksource.h>
   8#include <linux/dma-map-ops.h>
   9#include <linux/input.h>
  10#include <linux/io.h>
  11#include <linux/irqchip.h>
  12#include <linux/pl320-ipc.h>
  13#include <linux/of.h>
  14#include <linux/of_irq.h>
  15#include <linux/of_address.h>
  16#include <linux/reboot.h>
  17#include <linux/amba/bus.h>
  18#include <linux/platform_device.h>
  19#include <linux/psci.h>
  20
  21#include <asm/hardware/cache-l2x0.h>
  22#include <asm/mach/arch.h>
  23#include <asm/mach/map.h>
  24
  25#include "core.h"
  26#include "sysregs.h"
  27
  28void __iomem *sregs_base;
  29void __iomem *scu_base_addr;
  30
  31static void __init highbank_scu_map_io(void)
  32{
  33        unsigned long base;
  34
  35        /* Get SCU base */
  36        asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base));
  37
  38        scu_base_addr = ioremap(base, SZ_4K);
  39}
  40
  41
  42static void highbank_l2c310_write_sec(unsigned long val, unsigned reg)
  43{
  44        if (reg == L2X0_CTRL)
  45                highbank_smc1(0x102, val);
  46        else
  47                WARN_ONCE(1, "Highbank L2C310: ignoring write to reg 0x%x\n",
  48                          reg);
  49}
  50
  51static void __init highbank_init_irq(void)
  52{
  53        irqchip_init();
  54
  55        if (of_find_compatible_node(NULL, NULL, "arm,cortex-a9"))
  56                highbank_scu_map_io();
  57}
  58
  59static void highbank_power_off(void)
  60{
  61        highbank_set_pwr_shutdown();
  62
  63        while (1)
  64                cpu_do_idle();
  65}
  66
  67static int highbank_platform_notifier(struct notifier_block *nb,
  68                                  unsigned long event, void *__dev)
  69{
  70        struct resource *res;
  71        int reg = -1;
  72        u32 val;
  73        struct device *dev = __dev;
  74
  75        if (event != BUS_NOTIFY_ADD_DEVICE)
  76                return NOTIFY_DONE;
  77
  78        if (of_device_is_compatible(dev->of_node, "calxeda,hb-ahci"))
  79                reg = 0xc;
  80        else if (of_device_is_compatible(dev->of_node, "calxeda,hb-sdhci"))
  81                reg = 0x18;
  82        else if (of_device_is_compatible(dev->of_node, "arm,pl330"))
  83                reg = 0x20;
  84        else if (of_device_is_compatible(dev->of_node, "calxeda,hb-xgmac")) {
  85                res = platform_get_resource(to_platform_device(dev),
  86                                            IORESOURCE_MEM, 0);
  87                if (res) {
  88                        if (res->start == 0xfff50000)
  89                                reg = 0;
  90                        else if (res->start == 0xfff51000)
  91                                reg = 4;
  92                }
  93        }
  94
  95        if (reg < 0)
  96                return NOTIFY_DONE;
  97
  98        if (of_property_read_bool(dev->of_node, "dma-coherent")) {
  99                val = readl(sregs_base + reg);
 100                writel(val | 0xff01, sregs_base + reg);
 101                set_dma_ops(dev, &arm_coherent_dma_ops);
 102        }
 103
 104        return NOTIFY_OK;
 105}
 106
 107static struct notifier_block highbank_amba_nb = {
 108        .notifier_call = highbank_platform_notifier,
 109};
 110
 111static struct notifier_block highbank_platform_nb = {
 112        .notifier_call = highbank_platform_notifier,
 113};
 114
 115static struct platform_device highbank_cpuidle_device = {
 116        .name = "cpuidle-calxeda",
 117};
 118
 119static int hb_keys_notifier(struct notifier_block *nb, unsigned long event, void *data)
 120{
 121        u32 key = *(u32 *)data;
 122
 123        if (event != 0x1000)
 124                return 0;
 125
 126        if (key == KEY_POWER)
 127                orderly_poweroff(false);
 128        else if (key == 0xffff)
 129                ctrl_alt_del();
 130
 131        return 0;
 132}
 133static struct notifier_block hb_keys_nb = {
 134        .notifier_call = hb_keys_notifier,
 135};
 136
 137static void __init highbank_init(void)
 138{
 139        struct device_node *np;
 140
 141        /* Map system registers */
 142        np = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs");
 143        sregs_base = of_iomap(np, 0);
 144        WARN_ON(!sregs_base);
 145
 146        pm_power_off = highbank_power_off;
 147        highbank_pm_init();
 148
 149        bus_register_notifier(&platform_bus_type, &highbank_platform_nb);
 150        bus_register_notifier(&amba_bustype, &highbank_amba_nb);
 151
 152        pl320_ipc_register_notifier(&hb_keys_nb);
 153
 154        if (psci_ops.cpu_suspend)
 155                platform_device_register(&highbank_cpuidle_device);
 156}
 157
 158static const char *const highbank_match[] __initconst = {
 159        "calxeda,highbank",
 160        "calxeda,ecx-2000",
 161        NULL,
 162};
 163
 164DT_MACHINE_START(HIGHBANK, "Highbank")
 165#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE)
 166        .dma_zone_size  = (4ULL * SZ_1G),
 167#endif
 168        .l2c_aux_val    = 0,
 169        .l2c_aux_mask   = ~0,
 170        .l2c_write_sec  = highbank_l2c310_write_sec,
 171        .init_irq       = highbank_init_irq,
 172        .init_machine   = highbank_init,
 173        .dt_compat      = highbank_match,
 174        .restart        = highbank_restart,
 175MACHINE_END
 176