Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2016 Imagination Technologies
0004  * Author: Paul Burton <paul.burton@mips.com>
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  * Maximum 384MB RAM at physical address 0, preceding any I/O.
0028  */
0029 static struct yamon_mem_region mem_regions[] __initdata = {
0030     /* start    size */
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     /* leave the GIC node intact if a GIC is present */
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     /* if this isn't SEAD3, something went wrong */
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;           /* get original sample */
0190     /* wait for transition */
0191     while ((readl(status_reg) & 0x2) == orig)
0192         ;
0193     orig = orig ^ 0x2;                /* flip the bit */
0194 
0195     write_c0_count(0);
0196 
0197     /* wait 1 second (the sampling clock transitions every 10ms) */
0198     while (tick < 100) {
0199         /* wait for transition */
0200         while ((readl(status_reg) & 0x2) == orig)
0201             ;
0202         orig = orig ^ 0x2;                /* flip the bit */
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 };