0001
0002
0003
0004
0005
0006
0007 #define pr_fmt(fmt) "sead3: " fmt
0008
0009 #include <linux/errno.h>
0010 #include <linux/libfdt.h>
0011 #include <linux/printk.h>
0012 #include <linux/sizes.h>
0013
0014 #include <asm/fw/fw.h>
0015 #include <asm/io.h>
0016 #include <asm/machine.h>
0017 #include <asm/yamon-dt.h>
0018
0019 #define SEAD_CONFIG CKSEG1ADDR(0x1b100110)
0020 #define SEAD_CONFIG_GIC_PRESENT BIT(1)
0021
0022 #define MIPS_REVISION CKSEG1ADDR(0x1fc00010)
0023 #define MIPS_REVISION_MACHINE (0xf << 4)
0024 #define MIPS_REVISION_MACHINE_SEAD3 (0x4 << 4)
0025
0026
0027
0028
0029 static struct yamon_mem_region mem_regions[] __initdata = {
0030
0031 { 0, SZ_256M + SZ_128M },
0032 {}
0033 };
0034
0035 static __init bool sead3_detect(void)
0036 {
0037 uint32_t rev;
0038
0039 rev = __raw_readl((void *)MIPS_REVISION);
0040 return (rev & MIPS_REVISION_MACHINE) == MIPS_REVISION_MACHINE_SEAD3;
0041 }
0042
0043 static __init int append_memory(void *fdt)
0044 {
0045 return yamon_dt_append_memory(fdt, mem_regions);
0046 }
0047
0048 static __init int remove_gic(void *fdt)
0049 {
0050 const unsigned int cpu_ehci_int = 2;
0051 const unsigned int cpu_uart_int = 4;
0052 const unsigned int cpu_eth_int = 6;
0053 int gic_off, cpu_off, uart_off, eth_off, ehci_off, err;
0054 uint32_t cfg, cpu_phandle;
0055
0056
0057 cfg = __raw_readl((uint32_t *)SEAD_CONFIG);
0058 if (cfg & SEAD_CONFIG_GIC_PRESENT)
0059 return 0;
0060
0061 gic_off = fdt_node_offset_by_compatible(fdt, -1, "mti,gic");
0062 if (gic_off < 0) {
0063 pr_err("unable to find DT GIC node: %d\n", gic_off);
0064 return gic_off;
0065 }
0066
0067 err = fdt_nop_node(fdt, gic_off);
0068 if (err) {
0069 pr_err("unable to nop GIC node\n");
0070 return err;
0071 }
0072
0073 cpu_off = fdt_node_offset_by_compatible(fdt, -1,
0074 "mti,cpu-interrupt-controller");
0075 if (cpu_off < 0) {
0076 pr_err("unable to find CPU intc node: %d\n", cpu_off);
0077 return cpu_off;
0078 }
0079
0080 cpu_phandle = fdt_get_phandle(fdt, cpu_off);
0081 if (!cpu_phandle) {
0082 pr_err("unable to get CPU intc phandle\n");
0083 return -EINVAL;
0084 }
0085
0086 uart_off = fdt_node_offset_by_compatible(fdt, -1, "ns16550a");
0087 while (uart_off >= 0) {
0088 err = fdt_setprop_u32(fdt, uart_off, "interrupt-parent",
0089 cpu_phandle);
0090 if (err) {
0091 pr_warn("unable to set UART interrupt-parent: %d\n",
0092 err);
0093 return err;
0094 }
0095
0096 err = fdt_setprop_u32(fdt, uart_off, "interrupts",
0097 cpu_uart_int);
0098 if (err) {
0099 pr_err("unable to set UART interrupts property: %d\n",
0100 err);
0101 return err;
0102 }
0103
0104 uart_off = fdt_node_offset_by_compatible(fdt, uart_off,
0105 "ns16550a");
0106 }
0107 if (uart_off != -FDT_ERR_NOTFOUND) {
0108 pr_err("error searching for UART DT node: %d\n", uart_off);
0109 return uart_off;
0110 }
0111
0112 eth_off = fdt_node_offset_by_compatible(fdt, -1, "smsc,lan9115");
0113 if (eth_off < 0) {
0114 pr_err("unable to find ethernet DT node: %d\n", eth_off);
0115 return eth_off;
0116 }
0117
0118 err = fdt_setprop_u32(fdt, eth_off, "interrupt-parent", cpu_phandle);
0119 if (err) {
0120 pr_err("unable to set ethernet interrupt-parent: %d\n", err);
0121 return err;
0122 }
0123
0124 err = fdt_setprop_u32(fdt, eth_off, "interrupts", cpu_eth_int);
0125 if (err) {
0126 pr_err("unable to set ethernet interrupts property: %d\n", err);
0127 return err;
0128 }
0129
0130 ehci_off = fdt_node_offset_by_compatible(fdt, -1, "generic-ehci");
0131 if (ehci_off < 0) {
0132 pr_err("unable to find EHCI DT node: %d\n", ehci_off);
0133 return ehci_off;
0134 }
0135
0136 err = fdt_setprop_u32(fdt, ehci_off, "interrupt-parent", cpu_phandle);
0137 if (err) {
0138 pr_err("unable to set EHCI interrupt-parent: %d\n", err);
0139 return err;
0140 }
0141
0142 err = fdt_setprop_u32(fdt, ehci_off, "interrupts", cpu_ehci_int);
0143 if (err) {
0144 pr_err("unable to set EHCI interrupts property: %d\n", err);
0145 return err;
0146 }
0147
0148 return 0;
0149 }
0150
0151 static const struct mips_fdt_fixup sead3_fdt_fixups[] __initconst = {
0152 { yamon_dt_append_cmdline, "append command line" },
0153 { append_memory, "append memory" },
0154 { remove_gic, "remove GIC when not present" },
0155 { yamon_dt_serial_config, "append serial configuration" },
0156 { },
0157 };
0158
0159 static __init const void *sead3_fixup_fdt(const void *fdt,
0160 const void *match_data)
0161 {
0162 static unsigned char fdt_buf[16 << 10] __initdata;
0163 int err;
0164
0165 if (fdt_check_header(fdt))
0166 panic("Corrupt DT");
0167
0168
0169 BUG_ON(fdt_node_check_compatible(fdt, 0, "mti,sead-3"));
0170
0171 fw_init_cmdline();
0172
0173 err = apply_mips_fdt_fixups(fdt_buf, sizeof(fdt_buf),
0174 fdt, sead3_fdt_fixups);
0175 if (err)
0176 panic("Unable to fixup FDT: %d", err);
0177
0178 return fdt_buf;
0179 }
0180
0181 static __init unsigned int sead3_measure_hpt_freq(void)
0182 {
0183 void __iomem *status_reg = (void __iomem *)0xbf000410;
0184 unsigned int freq, orig, tick = 0;
0185 unsigned long flags;
0186
0187 local_irq_save(flags);
0188
0189 orig = readl(status_reg) & 0x2;
0190
0191 while ((readl(status_reg) & 0x2) == orig)
0192 ;
0193 orig = orig ^ 0x2;
0194
0195 write_c0_count(0);
0196
0197
0198 while (tick < 100) {
0199
0200 while ((readl(status_reg) & 0x2) == orig)
0201 ;
0202 orig = orig ^ 0x2;
0203 tick++;
0204 }
0205
0206 freq = read_c0_count();
0207
0208 local_irq_restore(flags);
0209
0210 return freq;
0211 }
0212
0213 extern char __dtb_sead3_begin[];
0214
0215 MIPS_MACHINE(sead3) = {
0216 .fdt = __dtb_sead3_begin,
0217 .detect = sead3_detect,
0218 .fixup_fdt = sead3_fixup_fdt,
0219 .measure_hpt_freq = sead3_measure_hpt_freq,
0220 };