1/* 2 * linux/arch/arm/mach-integrator/core.c 3 * 4 * Copyright (C) 2000-2003 Deep Blue Solutions Ltd 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2, as 8 * published by the Free Software Foundation. 9 */ 10#include <linux/types.h> 11#include <linux/kernel.h> 12#include <linux/init.h> 13#include <linux/device.h> 14#include <linux/export.h> 15#include <linux/spinlock.h> 16#include <linux/interrupt.h> 17#include <linux/irq.h> 18#include <linux/memblock.h> 19#include <linux/sched.h> 20#include <linux/smp.h> 21#include <linux/amba/bus.h> 22#include <linux/amba/serial.h> 23#include <linux/io.h> 24#include <linux/stat.h> 25#include <linux/of.h> 26#include <linux/of_address.h> 27 28#include <asm/mach-types.h> 29#include <asm/mach/time.h> 30#include <asm/pgtable.h> 31 32#include "hardware.h" 33#include "cm.h" 34#include "common.h" 35 36static DEFINE_RAW_SPINLOCK(cm_lock); 37static void __iomem *cm_base; 38 39/** 40 * cm_get - get the value from the CM_CTRL register 41 */ 42u32 cm_get(void) 43{ 44 return readl(cm_base + INTEGRATOR_HDR_CTRL_OFFSET); 45} 46 47/** 48 * cm_control - update the CM_CTRL register. 49 * @mask: bits to change 50 * @set: bits to set 51 */ 52void cm_control(u32 mask, u32 set) 53{ 54 unsigned long flags; 55 u32 val; 56 57 raw_spin_lock_irqsave(&cm_lock, flags); 58 val = readl(cm_base + INTEGRATOR_HDR_CTRL_OFFSET) & ~mask; 59 writel(val | set, cm_base + INTEGRATOR_HDR_CTRL_OFFSET); 60 raw_spin_unlock_irqrestore(&cm_lock, flags); 61} 62 63static const char *integrator_arch_str(u32 id) 64{ 65 switch ((id >> 16) & 0xff) { 66 case 0x00: 67 return "ASB little-endian"; 68 case 0x01: 69 return "AHB little-endian"; 70 case 0x03: 71 return "AHB-Lite system bus, bi-endian"; 72 case 0x04: 73 return "AHB"; 74 case 0x08: 75 return "AHB system bus, ASB processor bus"; 76 default: 77 return "Unknown"; 78 } 79} 80 81static const char *integrator_fpga_str(u32 id) 82{ 83 switch ((id >> 12) & 0xf) { 84 case 0x01: 85 return "XC4062"; 86 case 0x02: 87 return "XC4085"; 88 case 0x03: 89 return "XVC600"; 90 case 0x04: 91 return "EPM7256AE (Altera PLD)"; 92 default: 93 return "Unknown"; 94 } 95} 96 97void cm_clear_irqs(void) 98{ 99 /* disable core module IRQs */ 100 writel(0xffffffffU, cm_base + INTEGRATOR_HDR_IC_OFFSET + 101 IRQ_ENABLE_CLEAR); 102} 103 104static const struct of_device_id cm_match[] = { 105 { .compatible = "arm,core-module-integrator"}, 106 { }, 107}; 108 109void cm_init(void) 110{ 111 struct device_node *cm = of_find_matching_node(NULL, cm_match); 112 u32 val; 113 114 if (!cm) { 115 pr_crit("no core module node found in device tree\n"); 116 return; 117 } 118 cm_base = of_iomap(cm, 0); 119 if (!cm_base) { 120 pr_crit("could not remap core module\n"); 121 return; 122 } 123 cm_clear_irqs(); 124 val = readl(cm_base + INTEGRATOR_HDR_ID_OFFSET); 125 pr_info("Detected ARM core module:\n"); 126 pr_info(" Manufacturer: %02x\n", (val >> 24)); 127 pr_info(" Architecture: %s\n", integrator_arch_str(val)); 128 pr_info(" FPGA: %s\n", integrator_fpga_str(val)); 129 pr_info(" Build: %02x\n", (val >> 4) & 0xFF); 130 pr_info(" Rev: %c\n", ('A' + (val & 0x03))); 131} 132 133/* 134 * We need to stop things allocating the low memory; ideally we need a 135 * better implementation of GFP_DMA which does not assume that DMA-able 136 * memory starts at zero. 137 */ 138void __init integrator_reserve(void) 139{ 140 memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET); 141} 142 143/* 144 * To reset, we hit the on-board reset register in the system FPGA 145 */ 146void integrator_restart(enum reboot_mode mode, const char *cmd) 147{ 148 cm_control(CM_CTRL_RESET, CM_CTRL_RESET); 149} 150 151static u32 integrator_id; 152 153static ssize_t intcp_get_manf(struct device *dev, 154 struct device_attribute *attr, 155 char *buf) 156{ 157 return sprintf(buf, "%02x\n", integrator_id >> 24); 158} 159 160static struct device_attribute intcp_manf_attr = 161 __ATTR(manufacturer, S_IRUGO, intcp_get_manf, NULL); 162 163static ssize_t intcp_get_arch(struct device *dev, 164 struct device_attribute *attr, 165 char *buf) 166{ 167 return sprintf(buf, "%s\n", integrator_arch_str(integrator_id)); 168} 169 170static struct device_attribute intcp_arch_attr = 171 __ATTR(architecture, S_IRUGO, intcp_get_arch, NULL); 172 173static ssize_t intcp_get_fpga(struct device *dev, 174 struct device_attribute *attr, 175 char *buf) 176{ 177 return sprintf(buf, "%s\n", integrator_fpga_str(integrator_id)); 178} 179 180static struct device_attribute intcp_fpga_attr = 181 __ATTR(fpga, S_IRUGO, intcp_get_fpga, NULL); 182 183static ssize_t intcp_get_build(struct device *dev, 184 struct device_attribute *attr, 185 char *buf) 186{ 187 return sprintf(buf, "%02x\n", (integrator_id >> 4) & 0xFF); 188} 189 190static struct device_attribute intcp_build_attr = 191 __ATTR(build, S_IRUGO, intcp_get_build, NULL); 192 193 194 195void integrator_init_sysfs(struct device *parent, u32 id) 196{ 197 integrator_id = id; 198 device_create_file(parent, &intcp_manf_attr); 199 device_create_file(parent, &intcp_arch_attr); 200 device_create_file(parent, &intcp_fpga_attr); 201 device_create_file(parent, &intcp_build_attr); 202} 203