diff options
57 files changed, 2115 insertions, 180 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 21066f0fda..097ad587c1 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -26,6 +26,8 @@ config TARGET_MALTA select DM select DM_SERIAL select DYNAMIC_IO_PORT_BASE + select MIPS_CM + select MIPS_L2_CACHE select OF_CONTROL select OF_ISA_BUS select SUPPORTS_BIG_ENDIAN @@ -73,10 +75,43 @@ config MACH_PIC32 select OF_CONTROL select DM +config TARGET_BOSTON + bool "Support Boston" + select DM + select DM_SERIAL + select OF_CONTROL + select MIPS_CM + select MIPS_L1_CACHE_SHIFT_6 + select MIPS_L2_CACHE + select SUPPORTS_BIG_ENDIAN + select SUPPORTS_LITTLE_ENDIAN + select SUPPORTS_CPU_MIPS32_R1 + select SUPPORTS_CPU_MIPS32_R2 + select SUPPORTS_CPU_MIPS32_R6 + select SUPPORTS_CPU_MIPS64_R1 + select SUPPORTS_CPU_MIPS64_R2 + select SUPPORTS_CPU_MIPS64_R6 + +config TARGET_XILFPGA + bool "Support Imagination Xilfpga" + select OF_CONTROL + select DM + select DM_SERIAL + select DM_GPIO + select DM_ETH + select SUPPORTS_LITTLE_ENDIAN + select SUPPORTS_CPU_MIPS32_R1 + select SUPPORTS_CPU_MIPS32_R2 + select MIPS_L1_CACHE_SHIFT_4 + help + This supports IMGTEC MIPSfpga platform + endchoice source "board/dbau1x00/Kconfig" +source "board/imgtec/boston/Kconfig" source "board/imgtec/malta/Kconfig" +source "board/imgtec/xilfpga/Kconfig" source "board/micronas/vct/Kconfig" source "board/pb1x00/Kconfig" source "board/qemu-mips/Kconfig" @@ -300,9 +335,31 @@ config MIPS_L1_CACHE_SHIFT default "4" if MIPS_L1_CACHE_SHIFT_4 default "5" +config MIPS_L2_CACHE + bool + help + Select this if your system includes an L2 cache and you want U-Boot + to initialise & maintain it. + config DYNAMIC_IO_PORT_BASE bool +config MIPS_CM + bool + help + Select this if your system contains a MIPS Coherence Manager and you + wish U-Boot to configure it or make use of it to retrieve system + information such as cache configuration. + +config MIPS_CM_BASE + hex + default 0x1fbf8000 + help + The physical base address at which to map the MIPS Coherence Manager + Global Configuration Registers (GCRs). This should be set such that + the GCRs occupy a region of the physical address space which is + otherwise unused, or at minimum that software doesn't need to access. + endif endmenu diff --git a/arch/mips/cpu/Makefile b/arch/mips/cpu/Makefile index fc6b455c68..429fd3a50c 100644 --- a/arch/mips/cpu/Makefile +++ b/arch/mips/cpu/Makefile @@ -7,3 +7,5 @@ extra-y = start.o obj-y += time.o obj-y += interrupts.o obj-y += cpu.o + +obj-$(CONFIG_MIPS_CM) += cm_init.o diff --git a/arch/mips/cpu/cm_init.S b/arch/mips/cpu/cm_init.S new file mode 100644 index 0000000000..ddcaa4947f --- /dev/null +++ b/arch/mips/cpu/cm_init.S @@ -0,0 +1,45 @@ +/* + * MIPS Coherence Manager (CM) Initialisation + * + * Copyright (c) 2016 Imagination Technologies Ltd. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <asm/addrspace.h> +#include <asm/asm.h> +#include <asm/cm.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> + +LEAF(mips_cm_map) + /* Config3 must exist for a CM to be present */ + mfc0 t0, CP0_CONFIG, 1 + bgez t0, 2f + mfc0 t0, CP0_CONFIG, 2 + bgez t0, 2f + + /* Check Config3.CMGCR to determine CM presence */ + mfc0 t0, CP0_CONFIG, 3 + and t0, t0, MIPS_CONF3_CMGCR + beqz t0, 2f + + /* Find the current physical GCR base address */ +1: MFC0 t0, CP0_CMGCRBASE + PTR_SLL t0, t0, 4 + + /* If the GCRs are where we want, we're done */ + PTR_LI t1, CONFIG_MIPS_CM_BASE + beq t0, t1, 2f + + /* Move the GCRs to our configured base address */ + PTR_LI t2, CKSEG1 + PTR_ADDU t0, t0, t2 + sw zero, GCR_BASE_UPPER(t0) + sw t1, GCR_BASE(t0) + + /* Re-check the GCR base */ + b 1b + +2: jr ra + END(mips_cm_map) diff --git a/arch/mips/cpu/cpu.c b/arch/mips/cpu/cpu.c index 391feb3250..1b919ed822 100644 --- a/arch/mips/cpu/cpu.c +++ b/arch/mips/cpu/cpu.c @@ -8,6 +8,7 @@ #include <common.h> #include <command.h> #include <linux/compiler.h> +#include <asm/cache.h> #include <asm/mipsregs.h> #include <asm/reboot.h> @@ -35,3 +36,9 @@ void write_one_tlb(int index, u32 pagemask, u32 hi, u32 low0, u32 low1) write_c0_index(index); tlb_write_indexed(); } + +int arch_cpu_init(void) +{ + mips_cache_probe(); + return 0; +} diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S index fc6dd66aa6..3f0fc12547 100644 --- a/arch/mips/cpu/start.S +++ b/arch/mips/cpu/start.S @@ -12,10 +12,6 @@ #include <asm/regdef.h> #include <asm/mipsregs.h> -#ifndef CONFIG_SYS_MIPS_CACHE_MODE -#define CONFIG_SYS_MIPS_CACHE_MODE CONF_CM_CACHABLE_NONCOHERENT -#endif - #ifndef CONFIG_SYS_INIT_SP_ADDR #define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + \ CONFIG_SYS_INIT_SP_OFFSET) @@ -112,9 +108,28 @@ ENTRY(_start) .align 4 reset: +#if __mips_isa_rev >= 6 + mfc0 t0, CP0_CONFIG, 5 + and t0, t0, MIPS_CONF5_VP + beqz t0, 1f + nop + + b 2f + mfc0 t0, CP0_GLOBALNUMBER +#endif + +1: mfc0 t0, CP0_EBASE + and t0, t0, EBASE_CPUNUM + + /* Hang if this isn't the first CPU in the system */ +2: beqz t0, 4f + nop +3: wait + b 3b + nop /* Clear watch registers */ - MTC0 zero, CP0_WATCHLO +4: MTC0 zero, CP0_WATCHLO mtc0 zero, CP0_WATCHHI /* WP(Watch Pending), SW0/1 should be cleared */ @@ -127,9 +142,11 @@ reset: mtc0 zero, CP0_COMPARE #ifndef CONFIG_SKIP_LOWLEVEL_INIT - /* CONFIG0 register */ - li t0, CONF_CM_UNCACHED + mfc0 t0, CP0_CONFIG + and t0, t0, MIPS_CONF_IMPL + or t0, t0, CONF_CM_UNCACHED mtc0 t0, CP0_CONFIG + ehb #endif /* @@ -144,20 +161,31 @@ reset: 1: PTR_L gp, 0(ra) +#ifdef CONFIG_MIPS_CM + PTR_LA t9, mips_cm_map + jalr t9 + nop +#endif + #ifndef CONFIG_SKIP_LOWLEVEL_INIT +# ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD /* Initialize any external memory */ PTR_LA t9, lowlevel_init jalr t9 nop +# endif /* Initialize caches... */ PTR_LA t9, mips_cache_reset jalr t9 nop - /* ... and enable them */ - li t0, CONFIG_SYS_MIPS_CACHE_MODE - mtc0 t0, CP0_CONFIG +# ifndef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD + /* Initialize any external memory */ + PTR_LA t9, lowlevel_init + jalr t9 + nop +# endif #endif /* Set up temporary stack */ @@ -214,12 +242,9 @@ ENTRY(relocate_code) PTR_LI t0, CONFIG_SYS_MONITOR_BASE PTR_SUB s1, s2, t0 # s1 <-- relocation offset - PTR_LA t3, in_ram - PTR_L t2, -(3 * PTRSIZE)(t3) # t2 <-- __image_copy_end + PTR_LA t2, __image_copy_end move t1, a2 - PTR_ADD gp, s1 # adjust gp - /* * t0 = source address * t1 = target address @@ -232,32 +257,14 @@ ENTRY(relocate_code) blt t0, t2, 1b PTR_ADDU t1, PTRSIZE - /* If caches were enabled, we would have to flush them here. */ - PTR_SUB a1, t1, s2 # a1 <-- size - PTR_LA t9, flush_cache - jalr t9 - move a0, s2 # a0 <-- destination address - - /* Jump to where we've relocated ourselves */ - PTR_ADDIU t0, s2, in_ram - _start - jr t0 - nop - - PTR __rel_dyn_end - PTR __rel_dyn_start - PTR __image_copy_end - PTR _GLOBAL_OFFSET_TABLE_ - PTR num_got_entries - -in_ram: /* * Now we want to update GOT. * * GOT[0] is reserved. GOT[1] is also reserved for the dynamic object * generated by GNU ld. Skip these reserved entries from relocation. */ - PTR_L t3, -(1 * PTRSIZE)(t0) # t3 <-- num_got_entries - PTR_L t8, -(2 * PTRSIZE)(t0) # t8 <-- _GLOBAL_OFFSET_TABLE_ + PTR_LA t3, num_got_entries + PTR_LA t8, _GLOBAL_OFFSET_TABLE_ PTR_ADD t8, s1 # t8 now holds relocated _G_O_T_ PTR_ADDIU t8, t8, 2 * PTRSIZE # skipping first two entries PTR_LI t2, 2 @@ -272,8 +279,8 @@ in_ram: PTR_ADDIU t8, PTRSIZE /* Update dynamic relocations */ - PTR_L t1, -(4 * PTRSIZE)(t0) # t1 <-- __rel_dyn_start - PTR_L t2, -(5 * PTRSIZE)(t0) # t2 <-- __rel_dyn_end + PTR_LA t1, __rel_dyn_start + PTR_LA t2, __rel_dyn_end b 2f # skip first reserved entry PTR_ADDIU t1, 2 * PTRSIZE @@ -298,6 +305,20 @@ in_ram: PTR_ADDIU t1, 2 * PTRSIZE # each rel.dyn entry is 2*PTRSIZE bytes /* + * Flush caches to ensure our newly modified instructions are visible + * to the instruction cache. We're still running with the old GOT, so + * apply the reloc offset to the start address. + */ + PTR_LA a0, __text_start + PTR_LA a1, __text_end + PTR_SUB a1, a1, a0 + PTR_LA t9, flush_cache + jalr t9 + PTR_ADD a0, s1 + + PTR_ADD gp, s1 # adjust gp + + /* * Clear BSS * * GOT is now relocated. Thus __bss_start and __bss_end can be diff --git a/arch/mips/cpu/u-boot.lds b/arch/mips/cpu/u-boot.lds index 7d71c11ae4..0129c99611 100644 --- a/arch/mips/cpu/u-boot.lds +++ b/arch/mips/cpu/u-boot.lds @@ -19,7 +19,9 @@ SECTIONS . = ALIGN(4); .text : { + __text_start = .; *(.text*) + __text_end = .; } . = ALIGN(4); diff --git a/arch/mips/dts/Makefile b/arch/mips/dts/Makefile index 2f04d73b83..30fcc2b91e 100644 --- a/arch/mips/dts/Makefile +++ b/arch/mips/dts/Makefile @@ -4,8 +4,10 @@ dtb-$(CONFIG_TARGET_AP121) += ap121.dtb dtb-$(CONFIG_TARGET_AP143) += ap143.dtb +dtb-$(CONFIG_TARGET_BOSTON) += img,boston.dtb dtb-$(CONFIG_TARGET_MALTA) += mti,malta.dtb dtb-$(CONFIG_TARGET_PIC32MZDASK) += pic32mzda_sk.dtb +dtb-$(CONFIG_TARGET_XILFPGA) += nexys4ddr.dtb dtb-$(CONFIG_BOARD_TPLINK_WDR4300) += tplink_wdr4300.dtb targets += $(dtb-y) diff --git a/arch/mips/dts/img,boston.dts b/arch/mips/dts/img,boston.dts new file mode 100644 index 0000000000..1d4eeda4e8 --- /dev/null +++ b/arch/mips/dts/img,boston.dts @@ -0,0 +1,222 @@ +/dts-v1/; + +#include <dt-bindings/clock/boston-clock.h> +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/interrupt-controller/irq.h> +#include <dt-bindings/interrupt-controller/mips-gic.h> + +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "img,boston"; + + chosen { + stdout-path = &uart0; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "img,mips"; + reg = <0>; + clocks = <&clk_boston BOSTON_CLK_CPU>; + }; + }; + + memory@0 { + device_type = "memory"; + reg = <0x00000000 0x10000000>; + }; + + gic: interrupt-controller { + compatible = "mti,gic"; + + interrupt-controller; + #interrupt-cells = <3>; + + timer { + compatible = "mti,gic-timer"; + interrupts = <GIC_LOCAL 1 IRQ_TYPE_NONE>; + clocks = <&clk_boston BOSTON_CLK_CPU>; + }; + }; + + pci0: pci@10000000 { + status = "disabled"; + compatible = "xlnx,axi-pcie-host-1.00.a"; + device_type = "pci"; + reg = <0x10000000 0x2000000>; + + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + interrupt-parent = <&gic>; + interrupts = <GIC_SHARED 2 IRQ_TYPE_LEVEL_HIGH>; + + ranges = <0x02000000 0 0x40000000 + 0x40000000 0 0x40000000>; + + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pci0_intc 0>, + <0 0 0 2 &pci0_intc 1>, + <0 0 0 3 &pci0_intc 2>, + <0 0 0 4 &pci0_intc 3>; + + pci0_intc: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + + pci1: pci@12000000 { + status = "disabled"; + compatible = "xlnx,axi-pcie-host-1.00.a"; + device_type = "pci"; + reg = <0x12000000 0x2000000>; + + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + interrupt-parent = <&gic>; + interrupts = <GIC_SHARED 1 IRQ_TYPE_LEVEL_HIGH>; + + ranges = <0x02000000 0 0x20000000 + 0x20000000 0 0x20000000>; + + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pci1_intc 0>, + <0 0 0 2 &pci1_intc 1>, + <0 0 0 3 &pci1_intc 2>, + <0 0 0 4 &pci1_intc 3>; + + pci1_intc: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + + pci2: pci@14000000 { + compatible = "xlnx,axi-pcie-host-1.00.a"; + device_type = "pci"; + reg = <0x14000000 0x2000000>; + + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + interrupt-parent = <&gic>; + interrupts = <GIC_SHARED 0 IRQ_TYPE_LEVEL_HIGH>; + + ranges = <0x02000000 0 0x16000000 + 0x16000000 0 0x100000>; + + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pci2_intc 0>, + <0 0 0 2 &pci2_intc 1>, + <0 0 0 3 &pci2_intc 2>, + <0 0 0 4 &pci2_intc 3>; + + pci2_intc: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + + pci2_root@0,0,0 { + compatible = "pci10ee,7021"; + reg = <0x00000000 0 0 0 0>; + + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + eg20t_bridge@1,0,0 { + compatible = "pci8086,8800"; + reg = <0x00010000 0 0 0 0>; + + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + eg20t_mac@2,0,1 { + compatible = "pci8086,8802"; + reg = <0x00020100 0 0 0 0>; + phy-reset-gpios = <&eg20t_gpio 6 GPIO_ACTIVE_LOW>; + }; + + eg20t_gpio: eg20t_gpio@2,0,2 { + compatible = "pci8086,8803"; + reg = <0x00020200 0 0 0 0>; + + gpio-controller; + #gpio-cells = <2>; + }; + + eg20t_i2c@2,12,2 { + compatible = "pci8086,8817"; + reg = <0x00026200 0 0 0 0>; + + #address-cells = <1>; + #size-cells = <0>; + + rtc@0x68 { + compatible = "st,m41t81s"; + reg = <0x68>; + }; + }; + }; + }; + }; + + plat_regs: system-controller@17ffd000 { + compatible = "img,boston-platform-regs", "syscon"; + reg = <0x17ffd000 0x1000>; + u-boot,dm-pre-reloc; + }; + + clk_boston: clock { + compatible = "img,boston-clock"; + #clock-cells = <1>; + regmap = <&plat_regs>; + u-boot,dm-pre-reloc; + }; + + reboot: syscon-reboot { + compatible = "syscon-reboot"; + regmap = <&plat_regs>; + offset = <0x10>; + mask = <0x10>; + }; + + uart0: uart@17ffe000 { + compatible = "ns16550a"; + reg = <0x17ffe000 0x1000>; + reg-shift = <2>; + reg-io-width = <4>; + + interrupt-parent = <&gic>; + interrupts = <GIC_SHARED 3 IRQ_TYPE_LEVEL_HIGH>; + + clocks = <&clk_boston BOSTON_CLK_SYS>; + + u-boot,dm-pre-reloc; + }; + + lcd: lcd@17fff000 { + compatible = "img,boston-lcd"; + reg = <0x17fff000 0x8>; + }; + + flash@18000000 { + compatible = "cfi-flash"; + reg = <0x18000000 0x8000000>; + bank-width = <2>; + }; +}; diff --git a/arch/mips/dts/microAptiv.dtsi b/arch/mips/dts/microAptiv.dtsi new file mode 100644 index 0000000000..81d518e757 --- /dev/null +++ b/arch/mips/dts/microAptiv.dtsi @@ -0,0 +1,21 @@ +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "img,xilfpga"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu@0 { + device_type = "cpu"; + compatible = "mips,m14Kc"; + clocks = <&ext>; + reg = <0>; + }; + }; + + ext: ext { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; +}; diff --git a/arch/mips/dts/nexys4ddr.dts b/arch/mips/dts/nexys4ddr.dts new file mode 100644 index 0000000000..e254ab1eaa --- /dev/null +++ b/arch/mips/dts/nexys4ddr.dts @@ -0,0 +1,62 @@ +/dts-v1/; + +#include "microAptiv.dtsi" + +/ { + compatible = "digilent,nexys4ddr"; + + memory { + device_type = "memory"; + reg = <0x0 0x08000000>; + }; + + cpuintc: interrupt-controller@0 { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + compatible = "mti,cpu-interrupt-controller"; + }; + + aliases { + console = &axi_uart16550; + }; + + axi_ethernetlite: ethernet@10e00000 { + compatible = "xlnx,xps-ethernetlite-1.00.a"; + device_type = "network"; + local-mac-address = [08 86 4C 0D F7 09]; + phy-handle = <&phy0>; + reg = <0x10e00000 0x10000>; + xlnx,duplex = <0x1>; + xlnx,include-global-buffers = <0x1>; + xlnx,include-internal-loopback = <0x0>; + xlnx,include-mdio = <0x1>; + xlnx,instance = "axi_ethernetlite_inst"; + xlnx,rx-ping-pong = <0x1>; + xlnx,s-axi-id-width = <0x1>; + xlnx,tx-ping-pong = <0x1>; + xlnx,use-internal = <0x0>; + mdio { + #address-cells = <1>; + #size-cells = <0>; + phy0: phy@1 { + compatible = <0x0007c0f0 0xfffffff0>; + device_type = "ethernet-phy"; + reg = <1>; + } ; + } ; + } ; + + + axi_uart16550: serial@10400000 { + compatible = "ns16550a"; + reg = <0x10400000 0x10000>; + + reg-shift = <2>; + reg-offset = <0x1000>; + + clock-frequency = <50000000>; + + }; +}; + diff --git a/arch/mips/include/asm/cache.h b/arch/mips/include/asm/cache.h index 0cea581e5d..669c362a52 100644 --- a/arch/mips/include/asm/cache.h +++ b/arch/mips/include/asm/cache.h @@ -19,4 +19,13 @@ */ #define CONFIG_SYS_CACHELINE_SIZE ARCH_DMA_MINALIGN +/** + * mips_cache_probe() - Probe the properties of the caches + * + * Call this to probe the properties such as line sizes of the caches + * present in the system, if any. This must be done before cache maintenance + * functions such as flush_cache may be called. + */ +void mips_cache_probe(void); + #endif /* __MIPS_CACHE_H__ */ diff --git a/arch/mips/include/asm/cm.h b/arch/mips/include/asm/cm.h new file mode 100644 index 0000000000..b9ab0c65e6 --- /dev/null +++ b/arch/mips/include/asm/cm.h @@ -0,0 +1,62 @@ +/* + * MIPS Coherence Manager (CM) Register Definitions + * + * Copyright (c) 2016 Imagination Technologies Ltd. + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef __MIPS_ASM_CM_H__ +#define __MIPS_ASM_CM_H__ + +/* Global Control Register (GCR) offsets */ +#define GCR_BASE 0x0008 +#define GCR_BASE_UPPER 0x000c +#define GCR_REV 0x0030 +#define GCR_L2_CONFIG 0x0130 +#define GCR_L2_TAG_ADDR 0x0600 +#define GCR_L2_TAG_ADDR_UPPER 0x0604 +#define GCR_L2_TAG_STATE 0x0608 +#define GCR_L2_TAG_STATE_UPPER 0x060c +#define GCR_L2_DATA 0x0610 +#define GCR_L2_DATA_UPPER 0x0614 +#define GCR_Cx_COHERENCE 0x2008 + +/* GCR_REV CM versions */ +#define GCR_REV_CM3 0x0800 + +/* GCR_L2_CONFIG fields */ +#define GCR_L2_CONFIG_ASSOC_SHIFT 0 +#define GCR_L2_CONFIG_ASSOC_BITS 8 +#define GCR_L2_CONFIG_LINESZ_SHIFT 8 +#define GCR_L2_CONFIG_LINESZ_BITS 4 +#define GCR_L2_CONFIG_SETSZ_SHIFT 12 +#define GCR_L2_CONFIG_SETSZ_BITS 4 +#define GCR_L2_CONFIG_BYPASS (1 << 20) + +/* GCR_Cx_COHERENCE */ +#define GCR_Cx_COHERENCE_DOM_EN (0xff << 0) +#define GCR_Cx_COHERENCE_EN (0x1 << 0) + +#ifndef __ASSEMBLY__ + +#include <asm/io.h> + +static inline void *mips_cm_base(void) +{ + return (void *)CKSEG1ADDR(CONFIG_MIPS_CM_BASE); +} + +static inline unsigned long mips_cm_l2_line_size(void) +{ + unsigned long l2conf, line_sz; + + l2conf = __raw_readl(mips_cm_base() + GCR_L2_CONFIG); + + line_sz = l2conf >> GCR_L2_CONFIG_LINESZ_SHIFT; + line_sz &= GENMASK(GCR_L2_CONFIG_LINESZ_BITS - 1, 0); + return line_sz ? (2 << line_sz) : 0; +} + +#endif /* !__ASSEMBLY__ */ + +#endif /* __MIPS_ASM_CM_H__ */ diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h index 37f8ed52e6..0078bbe1b8 100644 --- a/arch/mips/include/asm/global_data.h +++ b/arch/mips/include/asm/global_data.h @@ -21,6 +21,13 @@ struct arch_global_data { unsigned long rev; unsigned long ver; #endif +#ifdef CONFIG_SYS_CACHE_SIZE_AUTO + unsigned short l1i_line_size; + unsigned short l1d_line_size; +#endif +#ifdef CONFIG_MIPS_L2_CACHE + unsigned short l2_line_size; +#endif }; #include <asm-generic/global_data.h> diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 3185dc7abf..9ab506361e 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -39,6 +39,7 @@ #define CP0_ENTRYLO0 $2 #define CP0_ENTRYLO1 $3 #define CP0_CONF $3 +#define CP0_GLOBALNUMBER $3, 1 #define CP0_CONTEXT $4 #define CP0_PAGEMASK $5 #define CP0_WIRED $6 @@ -361,6 +362,11 @@ #define CAUSEF_BD (_ULCAST_(1) << 31) /* + * Bits in the coprocessor 0 EBase register. + */ +#define EBASE_CPUNUM 0x3ff + +/* * Bits in the coprocessor 0 config register. */ /* Generic bits. */ @@ -450,6 +456,7 @@ #define MIPS_CONF_MT_FTLB (_ULCAST_(4) << 7) #define MIPS_CONF_AR (_ULCAST_(7) << 10) #define MIPS_CONF_AT (_ULCAST_(3) << 13) +#define MIPS_CONF_IMPL (_ULCAST_(0x1ff) << 16) #define MIPS_CONF_M (_ULCAST_(1) << 31) /* @@ -484,9 +491,13 @@ #define MIPS_CONF1_TLBS_SIZE (6) #define MIPS_CONF1_TLBS (_ULCAST_(63) << MIPS_CONF1_TLBS_SHIFT) +#define MIPS_CONF2_SA_SHF 0 #define MIPS_CONF2_SA (_ULCAST_(15) << 0) +#define MIPS_CONF2_SL_SHF 4 #define MIPS_CONF2_SL (_ULCAST_(15) << 4) +#define MIPS_CONF2_SS_SHF 8 #define MIPS_CONF2_SS (_ULCAST_(15) << 8) +#define MIPS_CONF2_L2B (_ULCAST_(1) << 12) #define MIPS_CONF2_SU (_ULCAST_(15) << 12) #define MIPS_CONF2_TA (_ULCAST_(15) << 16) #define MIPS_CONF2_TL (_ULCAST_(15) << 20) @@ -548,8 +559,10 @@ #define MIPS_CONF5_MRP (_ULCAST_(1) << 3) #define MIPS_CONF5_LLB (_ULCAST_(1) << 4) #define MIPS_CONF5_MVH (_ULCAST_(1) << 5) +#define MIPS_CONF5_VP (_ULCAST_(1) << 7) #define MIPS_CONF5_FRE (_ULCAST_(1) << 8) #define MIPS_CONF5_UFE (_ULCAST_(1) << 9) +#define MIPS_CONF5_L2C (_ULCAST_(1) << 10) #define MIPS_CONF5_MSAEN (_ULCAST_(1) << 27) #define MIPS_CONF5_EVA (_ULCAST_(1) << 28) #define MIPS_CONF5_CV (_ULCAST_(1) << 29) diff --git a/arch/mips/lib/cache.c b/arch/mips/lib/cache.c index db81953f86..bd14ba6ea7 100644 --- a/arch/mips/lib/cache.c +++ b/arch/mips/lib/cache.c @@ -7,34 +7,85 @@ #include <common.h> #include <asm/cacheops.h> +#include <asm/cm.h> #include <asm/mipsregs.h> -static inline unsigned long icache_line_size(void) +DECLARE_GLOBAL_DATA_PTR; + +static void probe_l2(void) { - unsigned long conf1, il; +#ifdef CONFIG_MIPS_L2_CACHE + unsigned long conf2, sl; + bool l2c = false; + + if (!(read_c0_config1() & MIPS_CONF_M)) + return; - if (!config_enabled(CONFIG_SYS_CACHE_SIZE_AUTO)) - return CONFIG_SYS_ICACHE_LINE_SIZE; + conf2 = read_c0_config2(); + + if (__mips_isa_rev >= 6) { + l2c = conf2 & MIPS_CONF_M; + if (l2c) + l2c = read_c0_config3() & MIPS_CONF_M; + if (l2c) + l2c = read_c0_config4() & MIPS_CONF_M; + if (l2c) + l2c = read_c0_config5() & MIPS_CONF5_L2C; + } + + if (l2c && config_enabled(CONFIG_MIPS_CM)) { + gd->arch.l2_line_size = mips_cm_l2_line_size(); + } else if (l2c) { + /* We don't know how to retrieve L2 config on this system */ + BUG(); + } else { + sl = (conf2 & MIPS_CONF2_SL) >> MIPS_CONF2_SL_SHF; + gd->arch.l2_line_size = sl ? (2 << sl) : 0; + } +#endif +} + +void mips_cache_probe(void) +{ +#ifdef CONFIG_SYS_CACHE_SIZE_AUTO + unsigned long conf1, il, dl; conf1 = read_c0_config1(); + il = (conf1 & MIPS_CONF1_IL) >> MIPS_CONF1_IL_SHF; - if (!il) - return 0; - return 2 << il; + dl = (conf1 & MIPS_CONF1_DL) >> MIPS_CONF1_DL_SHF; + + gd->arch.l1i_line_size = il ? (2 << il) : 0; + gd->arch.l1d_line_size = dl ? (2 << dl) : 0; +#endif + probe_l2(); } -static inline unsigned long dcache_line_size(void) +static inline unsigned long icache_line_size(void) { - unsigned long conf1, dl; +#ifdef CONFIG_SYS_CACHE_SIZE_AUTO + return gd->arch.l1i_line_size; +#else + return CONFIG_SYS_ICACHE_LINE_SIZE; +#endif +} - if (!config_enabled(CONFIG_SYS_CACHE_SIZE_AUTO)) - return CONFIG_SYS_DCACHE_LINE_SIZE; +static inline unsigned long dcache_line_size(void) +{ +#ifdef CONFIG_SYS_CACHE_SIZE_AUTO + return gd->arch.l1d_line_size; +#else + return CONFIG_SYS_DCACHE_LINE_SIZE; +#endif +} - conf1 = read_c0_config1(); - dl = (conf1 & MIPS_CONF1_DL) >> MIPS_CONF1_DL_SHF; - if (!dl) - return 0; - return 2 << dl; +static inline unsigned long scache_line_size(void) +{ +#ifdef CONFIG_MIPS_L2_CACHE + return gd->arch.l2_line_size; +#else + return 0; +#endif } #define cache_loop(start, end, lsize, ops...) do { \ @@ -53,12 +104,13 @@ void flush_cache(ulong start_addr, ulong size) { unsigned long ilsize = icache_line_size(); unsigned long dlsize = dcache_line_size(); + unsigned long slsize = scache_line_size(); /* aend will be miscalculated when size is zero, so we return here */ if (size == 0) return; - if (ilsize == dlsize) { + if ((ilsize == dlsize) && !slsize) { /* flush I-cache & D-cache simultaneously */ cache_loop(start_addr, start_addr + size, ilsize, HIT_WRITEBACK_INV_D, HIT_INVALIDATE_I); @@ -68,6 +120,11 @@ void flush_cache(ulong start_addr, ulong size) /* flush D-cache */ cache_loop(start_addr, start_addr + size, dlsize, HIT_WRITEBACK_INV_D); + /* flush L2 cache */ + if (slsize) + cache_loop(start_addr, start_addr + size, slsize, + HIT_WRITEBACK_INV_SD); + /* flush I-cache */ cache_loop(start_addr, start_addr + size, ilsize, HIT_INVALIDATE_I); } @@ -75,21 +132,31 @@ void flush_cache(ulong start_addr, ulong size) void flush_dcache_range(ulong start_addr, ulong stop) { unsigned long lsize = dcache_line_size(); + unsigned long slsize = scache_line_size(); /* aend will be miscalculated when size is zero, so we return here */ if (start_addr == stop) return; cache_loop(start_addr, stop, lsize, HIT_WRITEBACK_INV_D); + + /* flush L2 cache */ + if (slsize) + cache_loop(start_addr, stop, slsize, HIT_WRITEBACK_INV_SD); } void invalidate_dcache_range(ulong start_addr, ulong stop) { unsigned long lsize = dcache_line_size(); + unsigned long slsize = scache_line_size(); /* aend will be miscalculated when size is zero, so we return here */ if (start_addr == stop) return; + /* invalidate L2 cache */ + if (slsize) + cache_loop(start_addr, stop, slsize, HIT_INVALIDATE_SD); + cache_loop(start_addr, stop, lsize, HIT_INVALIDATE_D); } diff --git a/arch/mips/lib/cache_init.S b/arch/mips/lib/cache_init.S index bc8ab27b58..698a5afdee 100644 --- a/arch/mips/lib/cache_init.S +++ b/arch/mips/lib/cache_init.S @@ -13,6 +13,7 @@ #include <asm/mipsregs.h> #include <asm/addrspace.h> #include <asm/cacheops.h> +#include <asm/cm.h> #ifndef CONFIG_SYS_MIPS_CACHE_MODE #define CONFIG_SYS_MIPS_CACHE_MODE CONF_CM_CACHABLE_NONCOHERENT @@ -95,22 +96,147 @@ * with good parity is available. This routine will initialise an area of * memory starting at location zero to be used as a source of parity. * + * Note that this function does not follow the standard calling convention & + * may clobber typically callee-saved registers. + * * RETURNS: N/A * */ +#define R_RETURN s0 +#define R_IC_SIZE s1 +#define R_IC_LINE s2 +#define R_DC_SIZE s3 +#define R_DC_LINE s4 +#define R_L2_SIZE s5 +#define R_L2_LINE s6 +#define R_L2_BYPASSED s7 +#define R_L2_L2C t8 LEAF(mips_cache_reset) + move R_RETURN, ra + +#ifdef CONFIG_MIPS_L2_CACHE + /* + * For there to be an L2 present, Config2 must be present. If it isn't + * then we proceed knowing there's no L2 cache. + */ + move R_L2_SIZE, zero + move R_L2_LINE, zero + move R_L2_BYPASSED, zero + move R_L2_L2C, zero + mfc0 t0, CP0_CONFIG, 1 + bgez t0, l2_probe_done + + /* + * From MIPSr6 onwards the L2 cache configuration might not be reported + * by Config2. The Config5.L2C bit indicates whether this is the case, + * and if it is then we need knowledge of where else to look. For cores + * from Imagination Technologies this is a CM GCR. + */ +# if __mips_isa_rev >= 6 + /* Check that Config5 exists */ + mfc0 t0, CP0_CONFIG, 2 + bgez t0, l2_probe_cop0 + mfc0 t0, CP0_CONFIG, 3 + bgez t0, l2_probe_cop0 + mfc0 t0, CP0_CONFIG, 4 + bgez t0, l2_probe_cop0 + + /* Check Config5.L2C is set */ + mfc0 t0, CP0_CONFIG, 5 + and R_L2_L2C, t0, MIPS_CONF5_L2C + beqz R_L2_L2C, l2_probe_cop0 + + /* Config5.L2C is set */ +# ifdef CONFIG_MIPS_CM + /* The CM will provide L2 configuration */ + PTR_LI t0, CKSEG1ADDR(CONFIG_MIPS_CM_BASE) + lw t1, GCR_L2_CONFIG(t0) + bgez t1, l2_probe_done + + ext R_L2_LINE, t1, \ + GCR_L2_CONFIG_LINESZ_SHIFT, GCR_L2_CONFIG_LINESZ_BITS + beqz R_L2_LINE, l2_probe_done + li t2, 2 + sllv R_L2_LINE, t2, R_L2_LINE + + ext t2, t1, GCR_L2_CONFIG_ASSOC_SHIFT, GCR_L2_CONFIG_ASSOC_BITS + addiu t2, t2, 1 + mul R_L2_SIZE, R_L2_LINE, t2 + + ext t2, t1, GCR_L2_CONFIG_SETSZ_SHIFT, GCR_L2_CONFIG_SETSZ_BITS + sllv R_L2_SIZE, R_L2_SIZE, t2 + li t2, 64 + mul R_L2_SIZE, R_L2_SIZE, t2 + + /* Bypass the L2 cache so that we can init the L1s early */ + or t1, t1, GCR_L2_CONFIG_BYPASS + sw t1, GCR_L2_CONFIG(t0) + sync + li R_L2_BYPASSED, 1 + + /* Zero the L2 tag registers */ + sw zero, GCR_L2_TAG_ADDR(t0) + sw zero, GCR_L2_TAG_ADDR_UPPER(t0) + sw zero, GCR_L2_TAG_STATE(t0) + sw zero, GCR_L2_TAG_STATE_UPPER(t0) + sw zero, GCR_L2_DATA(t0) + sw zero, GCR_L2_DATA_UPPER(t0) + sync +# else + /* We don't know how to retrieve L2 configuration on this system */ +# endif + b l2_probe_done +# endif + + /* + * For pre-r6 systems, or r6 systems with Config5.L2C==0, probe the L2 + * cache configuration from the cop0 Config2 register. + */ +l2_probe_cop0: + mfc0 t0, CP0_CONFIG, 2 + + srl R_L2_LINE, t0, MIPS_CONF2_SL_SHF + andi R_L2_LINE, R_L2_LINE, MIPS_CONF2_SL >> MIPS_CONF2_SL_SHF + beqz R_L2_LINE, l2_probe_done + li t1, 2 + sllv R_L2_LINE, t1, R_L2_LINE + + srl t1, t0, MIPS_CONF2_SA_SHF + andi t1, t1, MIPS_CONF2_SA >> MIPS_CONF2_SA_SHF + addiu t1, t1, 1 + mul R_L2_SIZE, R_L2_LINE, t1 + + srl t1, t0, MIPS_CONF2_SS_SHF + andi t1, t1, MIPS_CONF2_SS >> MIPS_CONF2_SS_SHF + sllv R_L2_SIZE, R_L2_SIZE, t1 + li t1, 64 + mul R_L2_SIZE, R_L2_SIZE, t1 + + /* Attempt to bypass the L2 so that we can init the L1s early */ + or t0, t0, MIPS_CONF2_L2B + mtc0 t0, CP0_CONFIG, 2 + ehb + mfc0 t0, CP0_CONFIG, 2 + and R_L2_BYPASSED, t0, MIPS_CONF2_L2B + + /* Zero the L2 tag registers */ + mtc0 zero, CP0_TAGLO, 4 + ehb +l2_probe_done: +#endif + #ifndef CONFIG_SYS_CACHE_SIZE_AUTO - li t2, CONFIG_SYS_ICACHE_SIZE - li t8, CONFIG_SYS_ICACHE_LINE_SIZE + li R_IC_SIZE, CONFIG_SYS_ICACHE_SIZE + li R_IC_LINE, CONFIG_SYS_ICACHE_LINE_SIZE #else - l1_info t2, t8, MIPS_CONF1_IA_SHF + l1_info R_IC_SIZE, R_IC_LINE, MIPS_CONF1_IA_SHF #endif #ifndef CONFIG_SYS_CACHE_SIZE_AUTO - li t3, CONFIG_SYS_DCACHE_SIZE - li t9, CONFIG_SYS_DCACHE_LINE_SIZE + li R_DC_SIZE, CONFIG_SYS_DCACHE_SIZE + li R_DC_LINE, CONFIG_SYS_DCACHE_LINE_SIZE #else - l1_info t3, t9, MIPS_CONF1_DA_SHF + l1_info R_DC_SIZE, R_DC_LINE, MIPS_CONF1_DA_SHF #endif #ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD @@ -123,9 +249,9 @@ LEAF(mips_cache_reset) li v0, CONFIG_SYS_DCACHE_SIZE #endif #else - move v0, t2 - sltu t1, t2, t3 - movn v0, t3, t1 + move v0, R_IC_SIZE + sltu t1, R_IC_SIZE, R_DC_SIZE + movn v0, R_DC_SIZE, t1 #endif /* * Now clear that much memory starting from zero. @@ -138,13 +264,36 @@ LEAF(mips_cache_reset) #endif /* CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD */ +#ifdef CONFIG_MIPS_L2_CACHE + /* + * If the L2 is bypassed, init the L1 first so that we can execute the + * rest of the cache initialisation using the L1 instruction cache. + */ + bnez R_L2_BYPASSED, l1_init + +l2_init: + PTR_LI t0, INDEX_BASE + PTR_ADDU t1, t0, R_L2_SIZE +1: cache INDEX_STORE_TAG_SD, 0(t0) + PTR_ADDU t0, t0, R_L2_LINE + bne t0, t1, 1b + + /* + * If the L2 was bypassed then we already initialised the L1s before + * the L2, so we are now done. + */ + bnez R_L2_BYPASSED, l2_unbypass +#endif + /* * The TagLo registers used depend upon the CPU implementation, but the * architecture requires that it is safe for software to write to both * TagLo selects 0 & 2 covering supported cases. */ +l1_init: mtc0 zero, CP0_TAGLO mtc0 zero, CP0_TAGLO, 2 + ehb /* * The caches are probably in an indeterminate state, so we force good @@ -158,40 +307,122 @@ LEAF(mips_cache_reset) /* * Initialize the I-cache first, */ - blez t2, 1f + blez R_IC_SIZE, 1f PTR_LI t0, INDEX_BASE - PTR_ADDU t1, t0, t2 + PTR_ADDU t1, t0, R_IC_SIZE /* clear tag to invalidate */ - cache_loop t0, t1, t8, INDEX_STORE_TAG_I + cache_loop t0, t1, R_IC_LINE, INDEX_STORE_TAG_I #ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD /* fill once, so data field parity is correct */ PTR_LI t0, INDEX_BASE - cache_loop t0, t1, t8, FILL + cache_loop t0, t1, R_IC_LINE, FILL /* invalidate again - prudent but not strictly neccessary */ PTR_LI t0, INDEX_BASE - cache_loop t0, t1, t8, INDEX_STORE_TAG_I + cache_loop t0, t1, R_IC_LINE, INDEX_STORE_TAG_I +#endif + + /* Enable use of the I-cache by setting Config.K0 */ + sync + mfc0 t0, CP0_CONFIG + li t1, CONFIG_SYS_MIPS_CACHE_MODE +#if __mips_isa_rev >= 2 + ins t0, t1, 0, 3 +#else + ori t0, t0, CONF_CM_CMASK + xori t0, t0, CONF_CM_CMASK + or t0, t0, t1 #endif + mtc0 t0, CP0_CONFIG /* * then initialize D-cache. */ -1: blez t3, 3f +1: blez R_DC_SIZE, 3f PTR_LI t0, INDEX_BASE - PTR_ADDU t1, t0, t3 + PTR_ADDU t1, t0, R_DC_SIZE /* clear all tags */ - cache_loop t0, t1, t9, INDEX_STORE_TAG_D + cache_loop t0, t1, R_DC_LINE, INDEX_STORE_TAG_D #ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD /* load from each line (in cached space) */ PTR_LI t0, INDEX_BASE 2: LONG_L zero, 0(t0) - PTR_ADDU t0, t9 + PTR_ADDU t0, R_DC_LINE bne t0, t1, 2b /* clear all tags */ PTR_LI t0, INDEX_BASE - cache_loop t0, t1, t9, INDEX_STORE_TAG_D + cache_loop t0, t1, R_DC_LINE, INDEX_STORE_TAG_D #endif +3: + +#ifdef CONFIG_MIPS_L2_CACHE + /* If the L2 isn't bypassed then we're done */ + beqz R_L2_BYPASSED, return + + /* The L2 is bypassed - go initialise it */ + b l2_init -3: jr ra +l2_unbypass: +# if __mips_isa_rev >= 6 + beqz R_L2_L2C, 1f + + li t0, CKSEG1ADDR(CONFIG_MIPS_CM_BASE) + lw t1, GCR_L2_CONFIG(t0) + xor t1, t1, GCR_L2_CONFIG_BYPASS + sw t1, GCR_L2_CONFIG(t0) + sync + ehb + b 2f +# endif +1: mfc0 t0, CP0_CONFIG, 2 + xor t0, t0, MIPS_CONF2_L2B + mtc0 t0, CP0_CONFIG, 2 + ehb + +2: +# ifdef CONFIG_MIPS_CM + /* Config3 must exist for a CM to be present */ + mfc0 t0, CP0_CONFIG, 1 + bgez t0, 2f + mfc0 t0, CP0_CONFIG, 2 + bgez t0, 2f + + /* Check Config3.CMGCR to determine CM presence */ + mfc0 t0, CP0_CONFIG, 3 + and t0, t0, MIPS_CONF3_CMGCR + beqz t0, 2f + + /* Change Config.K0 to a coherent CCA */ + mfc0 t0, CP0_CONFIG + li t1, CONF_CM_CACHABLE_COW +#if __mips_isa_rev >= 2 + ins t0, t1, 0, 3 +#else + ori t0, t0, CONF_CM_CMASK + xori t0, t0, CONF_CM_CMASK + or t0, t0, t1 +#endif + mtc0 t0, CP0_CONFIG + + /* + * Join the coherent domain such that the caches of this core are kept + * coherent with those of other cores. + */ + PTR_LI t0, CKSEG1ADDR(CONFIG_MIPS_CM_BASE) + lw t1, GCR_REV(t0) + li t2, GCR_REV_CM3 + li t3, GCR_Cx_COHERENCE_EN + bge t1, t2, 1f + li t3, GCR_Cx_COHERENCE_DOM_EN +1: sw t3, GCR_Cx_COHERENCE(t0) + ehb +2: +# endif +#endif + +return: + /* Ensure all cache operations complete before returning */ + sync + jr ra END(mips_cache_reset) /* diff --git a/arch/mips/mach-ath79/cpu.c b/arch/mips/mach-ath79/cpu.c index 5756a06d50..4ef5092478 100644 --- a/arch/mips/mach-ath79/cpu.c +++ b/arch/mips/mach-ath79/cpu.c @@ -46,7 +46,7 @@ static const struct ath79_soc_desc desc[] = { {ATH79_SOC_QCA9561, "9561", REV_ID_MAJOR_QCA9561, 0}, }; -int arch_cpu_init(void) +int mach_cpu_init(void) { void __iomem *base; enum ath79_soc_type soc = ATH79_SOC_UNKNOWN; diff --git a/board/imgtec/boston/Kconfig b/board/imgtec/boston/Kconfig new file mode 100644 index 0000000000..ab76a3c626 --- /dev/null +++ b/board/imgtec/boston/Kconfig @@ -0,0 +1,16 @@ +if TARGET_BOSTON + +config SYS_BOARD + default "boston" + +config SYS_VENDOR + default "imgtec" + +config SYS_CONFIG_NAME + default "boston" + +config SYS_TEXT_BASE + default 0x9fc00000 if 32BIT + default 0xffffffff9fc00000 if 64BIT + +endif diff --git a/board/imgtec/boston/MAINTAINERS b/board/imgtec/boston/MAINTAINERS new file mode 100644 index 0000000000..30dd481a26 --- /dev/null +++ b/board/imgtec/boston/MAINTAINERS @@ -0,0 +1,6 @@ +BOSTON BOARD +M: Paul Burton <paul.burton@imgtec.com> +S: Maintained +F: board/imgtec/boston/ +F: include/configs/boston.h +F: configs/boston_defconfig diff --git a/board/imgtec/boston/Makefile b/board/imgtec/boston/Makefile new file mode 100644 index 0000000000..deda457f3c --- /dev/null +++ b/board/imgtec/boston/Makefile @@ -0,0 +1,9 @@ +# +# Copyright (C) 2016 Imagination Technologies +# +# SPDX-License-Identifier: GPL-2.0 +# + +obj-y += checkboard.o +obj-y += ddr.o +obj-y += lowlevel_init.o diff --git a/board/imgtec/boston/boston-lcd.h b/board/imgtec/boston/boston-lcd.h new file mode 100644 index 0000000000..9f5c1b9005 --- /dev/null +++ b/board/imgtec/boston/boston-lcd.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __BOARD_BOSTON_LCD_H__ +#define __BOARD_BOSTON_LCD_H__ + +/** + * lowlevel_display() - Display a message on Boston's LCD + * @msg: The string to display + * + * Display the string @msg on the 7 character LCD display of the Boston board. + * This is typically used for debug or to present some form of status + * indication to the user, allowing faults to be identified when things go + * wrong early enough that the UART isn't up. + */ +void lowlevel_display(const char msg[static 8]); + +#endif /* __BOARD_BOSTON_LCD_H__ */ diff --git a/board/imgtec/boston/boston-regs.h b/board/imgtec/boston/boston-regs.h new file mode 100644 index 0000000000..b9dfbb4763 --- /dev/null +++ b/board/imgtec/boston/boston-regs.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __BOARD_BOSTON_REGS_H__ +#define __BOARD_BOSTON_REGS_H__ + +#include <asm/addrspace.h> + +#define BOSTON_PLAT_BASE CKSEG1ADDR(0x17ffd000) +#define BOSTON_LCD_BASE CKSEG1ADDR(0x17fff000) + +/* + * Platform Register Definitions + */ +#define BOSTON_PLAT_CORE_CL (BOSTON_PLAT_BASE + 0x04) + +#define BOSTON_PLAT_DDR3STAT (BOSTON_PLAT_BASE + 0x14) +# define BOSTON_PLAT_DDR3STAT_CALIB (1 << 2) + +#define BOSTON_PLAT_DDRCONF0 (BOSTON_PLAT_BASE + 0x38) +# define BOSTON_PLAT_DDRCONF0_SIZE (0xf << 0) + +#endif /* __BOARD_BOSTON_REGS_H__ */ diff --git a/board/imgtec/boston/checkboard.c b/board/imgtec/boston/checkboard.c new file mode 100644 index 0000000000..93eae7f603 --- /dev/null +++ b/board/imgtec/boston/checkboard.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> + +#include <asm/io.h> +#include <asm/mipsregs.h> + +#include "boston-lcd.h" +#include "boston-regs.h" + +int checkboard(void) +{ + u32 changelist; + + lowlevel_display("U-boot "); + + printf("Board: MIPS Boston\n"); + + printf("CPU: 0x%08x", read_c0_prid()); + changelist = __raw_readl((uint32_t *)BOSTON_PLAT_CORE_CL); + if (changelist > 1) + printf(" cl%x", changelist); + putc('\n'); + + return 0; +} diff --git a/board/imgtec/boston/ddr.c b/board/imgtec/boston/ddr.c new file mode 100644 index 0000000000..ceffef61ef --- /dev/null +++ b/board/imgtec/boston/ddr.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> + +#include <asm/io.h> + +#include "boston-regs.h" + +phys_size_t initdram(int board_type) +{ + u32 ddrconf0 = __raw_readl((uint32_t *)BOSTON_PLAT_DDRCONF0); + + return (phys_size_t)(ddrconf0 & BOSTON_PLAT_DDRCONF0_SIZE) << 30; +} + +ulong board_get_usable_ram_top(ulong total_size) +{ + DECLARE_GLOBAL_DATA_PTR; + + if (gd->ram_top < CONFIG_SYS_SDRAM_BASE) { + /* 2GB wrapped around to 0 */ + return CKSEG0ADDR(256 << 20); + } + + return min_t(unsigned long, gd->ram_top, CKSEG0ADDR(256 << 20)); +} diff --git a/board/imgtec/boston/lowlevel_init.S b/board/imgtec/boston/lowlevel_init.S new file mode 100644 index 0000000000..0c01aa981d --- /dev/null +++ b/board/imgtec/boston/lowlevel_init.S @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <config.h> + +#include <asm/addrspace.h> +#include <asm/asm.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> + +#include "boston-regs.h" + +.data + +msg_ddr_cal: .ascii "DDR Cal " +msg_ddr_ok: .ascii "DDR OK " + +.text + +LEAF(lowlevel_init) + move s0, ra + + PTR_LA a0, msg_ddr_cal + bal lowlevel_display + + PTR_LI t0, BOSTON_PLAT_DDR3STAT +1: lw t1, 0(t0) + andi t1, t1, BOSTON_PLAT_DDR3STAT_CALIB + beqz t1, 1b + + PTR_LA a0, msg_ddr_ok + bal lowlevel_display + + move v0, zero + jr s0 + END(lowlevel_init) + +LEAF(lowlevel_display) + .set push + .set noat + PTR_LI AT, BOSTON_LCD_BASE +#ifdef CONFIG_64BIT + ld k1, 0(a0) + sd k1, 0(AT) +#else + lw k1, 0(a0) + sw k1, 0(AT) + lw k1, 4(a0) + sw k1, 4(AT) +#endif + .set pop +1: jr ra + END(lowlevel_display) diff --git a/board/imgtec/malta/lowlevel_init.S b/board/imgtec/malta/lowlevel_init.S index 3d48cdc1f4..6df4d9f719 100644 --- a/board/imgtec/malta/lowlevel_init.S +++ b/board/imgtec/malta/lowlevel_init.S @@ -28,12 +28,6 @@ .globl lowlevel_init lowlevel_init: - /* disable any L2 cache for now */ - sync - mfc0 t0, CP0_CONFIG, 2 - ori t0, t0, 0x1 << 12 - mtc0 t0, CP0_CONFIG, 2 - /* detect the core card */ PTR_LI t0, CKSEG1ADDR(MALTA_REVISION) lw t0, 0(t0) diff --git a/board/imgtec/xilfpga/Kconfig b/board/imgtec/xilfpga/Kconfig new file mode 100644 index 0000000000..b0782780f6 --- /dev/null +++ b/board/imgtec/xilfpga/Kconfig @@ -0,0 +1,15 @@ +if TARGET_XILFPGA + +config SYS_BOARD + default "xilfpga" + +config SYS_VENDOR + default "imgtec" + +config SYS_CONFIG_NAME + default "imgtec_xilfpga" + +config SYS_TEXT_BASE + default 0x80C00000 + +endif diff --git a/board/imgtec/xilfpga/MAINTAINERS b/board/imgtec/xilfpga/MAINTAINERS new file mode 100644 index 0000000000..aa045325ea --- /dev/null +++ b/board/imgtec/xilfpga/MAINTAINERS @@ -0,0 +1,6 @@ +XILFPGA BOARD +M: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com> +S: Maintained +F: board/imgtec/xilfpga +F: include/configs/xilfpga.h +F: configs/imgtec_xilfpga_defconfig diff --git a/board/imgtec/xilfpga/Makefile b/board/imgtec/xilfpga/Makefile new file mode 100644 index 0000000000..9aaf9ce263 --- /dev/null +++ b/board/imgtec/xilfpga/Makefile @@ -0,0 +1,7 @@ +# +# Copyright (C) 2016, Imagination Technologies Ltd. +# Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com> +# +# SPDX-License-Identifier: GPL-2.0+ +# +obj-y := xilfpga.o diff --git a/board/imgtec/xilfpga/README b/board/imgtec/xilfpga/README new file mode 100644 index 0000000000..ac19d485d4 --- /dev/null +++ b/board/imgtec/xilfpga/README @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016, Imagination Technologies Ltd. + * + * Zubair Lutfullah Kakakhel, Zubair.Kakakhel@imgtec.com + */ + +MIPSfpga +======================================= + +MIPSfpga is an FPGA based development platform by Imagination Technologies +As we are dealing with a MIPS core instantiated on an FPGA, specifications +are fluid and can be varied in RTL. + +The example project provided by IMGTEC runs on the Nexys4DDR board by +Digilent powered by the ARTIX-7 FPGA by Xilinx. Relevant details about +the example project and the Nexys4DDR board: + +- microAptiv UP core m14Kc +- 50MHz clock speed +- 128Mbyte DDR RAM at 0x0000_0000 +- 8Kbyte RAM at 0x1000_0000 +- axi_intc at 0x1020_0000 +- axi_uart16550 at 0x1040_0000 +- axi_gpio at 0x1060_0000 +- axi_i2c at 0x10A0_0000 +- custom_gpio at 0x10C0_0000 +- axi_ethernetlite at 0x10E0_0000 +- 8Kbyte BootRAM at 0x1FC0_0000 +- 16Mbyte QPI at 0x1D00_0000 + +Boot protocol: +-------------- + +The BootRAM is a writeable "RAM" in FPGA at 0x1FC0_0000. +This is for easy reprogrammibility via JTAG. + +DDR initialization is already handled by a HW IP block. + +When the example project bitstream is loaded, the cpu_reset button +needs to be pressed. + +The bootram initializes the cache and axi_uart +Then checks if there is anything non 0xffff_ffff at location 0x1D40_0000 + +If there is, then that is considered as u-boot. u-boot is copied from +0x1D40_0000 to memory and the bootram jumps into u-boot code. + +At this point, the board is ready to load the Linux kernel + buildroot initramfs + +This can be done in multiple ways: + +1- JTAG load the binary and jump into it. +2- Load kernel stored in the QSPI flash at 0x1D80_0000 +3- Load uImage via tftp. Ethernet works in u-boot. + e.g. env set server ip 192.168.154.45; dhcp uImage; bootm diff --git a/board/imgtec/xilfpga/xilfpga.c b/board/imgtec/xilfpga/xilfpga.c new file mode 100644 index 0000000000..77a1952c93 --- /dev/null +++ b/board/imgtec/xilfpga/xilfpga.c @@ -0,0 +1,20 @@ +/* + * Imagination Technologies MIPSfpga platform code + * + * Copyright (C) 2016, Imagination Technologies Ltd. + * + * Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com> + * + * SPDX-License-Identifier: GPL-2.0+ + * + */ + +#include <common.h> + +/* initialize the DDR Controller and PHY */ +phys_size_t initdram(int board_type) +{ + /* MIG IP block is smart and doesn't need SW + * to do any init */ + return CONFIG_SYS_SDRAM_SIZE; /* in bytes */ +} diff --git a/common/board_f.c b/common/board_f.c index da381dbd93..9ef998f9ed 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -290,6 +290,11 @@ __weak int arch_cpu_init(void) return 0; } +__weak int mach_cpu_init(void) +{ + return 0; +} + #ifdef CONFIG_SANDBOX static int setup_ram_buf(void) { @@ -860,6 +865,7 @@ static init_fnc_t init_sequence_f[] = { x86_fsp_init, #endif arch_cpu_init, /* basic arch cpu dependent setup */ + mach_cpu_init, /* SoC/machine dependent CPU setup */ initf_dm, arch_cpu_init_dm, mark_bootstage, /* need timer, go after init dm */ diff --git a/configs/boston32r2_defconfig b/configs/boston32r2_defconfig new file mode 100644 index 0000000000..ca66248b5b --- /dev/null +++ b/configs/boston32r2_defconfig @@ -0,0 +1,41 @@ +CONFIG_MIPS=y +CONFIG_TARGET_BOSTON=y +CONFIG_SYS_TEXT_BASE=0x9fc00000 +# CONFIG_MIPS_BOOT_CMDLINE_LEGACY is not set +# CONFIG_MIPS_BOOT_ENV_LEGACY is not set +CONFIG_MIPS_BOOT_FDT=y +CONFIG_DEFAULT_DEVICE_TREE="img,boston" +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_FIT_BEST_MATCH=y +CONFIG_OF_STDOUT_VIA_ALIAS=y +CONFIG_HUSH_PARSER=y +CONFIG_SYS_PROMPT="boston # " +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_IMLS is not set +CONFIG_CMD_GREPENV=y +CONFIG_CMD_MEMTEST=y +# CONFIG_CMD_LOADB is not set +# CONFIG_CMD_LOADS is not set +# CONFIG_CMD_FPGA is not set +CONFIG_CMD_DHCP=y +CONFIG_CMD_PING=y +CONFIG_CMD_SNTP=y +CONFIG_CMD_DNS=y +CONFIG_CMD_LINK_LOCAL=y +CONFIG_CMD_TIME=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_OF_EMBED=y +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_CLK=y +CONFIG_MTD=y +CONFIG_CFI_FLASH=y +CONFIG_DM_ETH=y +CONFIG_PCH_GBE=y +CONFIG_DM_PCI=y +CONFIG_PCI_XILINX=y +CONFIG_SYS_NS16550=y +CONFIG_LZ4=y diff --git a/configs/boston32r2el_defconfig b/configs/boston32r2el_defconfig new file mode 100644 index 0000000000..67f54bff95 --- /dev/null +++ b/configs/boston32r2el_defconfig @@ -0,0 +1,42 @@ +CONFIG_MIPS=y +CONFIG_TARGET_BOSTON=y +CONFIG_SYS_TEXT_BASE=0x9fc00000 +CONFIG_SYS_LITTLE_ENDIAN=y +# CONFIG_MIPS_BOOT_CMDLINE_LEGACY is not set +# CONFIG_MIPS_BOOT_ENV_LEGACY is not set +CONFIG_MIPS_BOOT_FDT=y +CONFIG_DEFAULT_DEVICE_TREE="img,boston" +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_FIT_BEST_MATCH=y +CONFIG_OF_STDOUT_VIA_ALIAS=y +CONFIG_HUSH_PARSER=y +CONFIG_SYS_PROMPT="boston # " +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_IMLS is not set +CONFIG_CMD_GREPENV=y +CONFIG_CMD_MEMTEST=y +# CONFIG_CMD_LOADB is not set +# CONFIG_CMD_LOADS is not set +# CONFIG_CMD_FPGA is not set +CONFIG_CMD_DHCP=y +CONFIG_CMD_PING=y +CONFIG_CMD_SNTP=y +CONFIG_CMD_DNS=y +CONFIG_CMD_LINK_LOCAL=y +CONFIG_CMD_TIME=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_OF_EMBED=y +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_CLK=y +CONFIG_MTD=y +CONFIG_CFI_FLASH=y +CONFIG_DM_ETH=y +CONFIG_PCH_GBE=y +CONFIG_DM_PCI=y +CONFIG_PCI_XILINX=y +CONFIG_SYS_NS16550=y +CONFIG_LZ4=y diff --git a/configs/boston64r2_defconfig b/configs/boston64r2_defconfig new file mode 100644 index 0000000000..1245d1b4ec --- /dev/null +++ b/configs/boston64r2_defconfig @@ -0,0 +1,41 @@ +CONFIG_MIPS=y +CONFIG_TARGET_BOSTON=y +CONFIG_CPU_MIPS64_R2=y +# CONFIG_MIPS_BOOT_CMDLINE_LEGACY is not set +# CONFIG_MIPS_BOOT_ENV_LEGACY is not set +CONFIG_MIPS_BOOT_FDT=y +CONFIG_DEFAULT_DEVICE_TREE="img,boston" +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_FIT_BEST_MATCH=y +CONFIG_OF_STDOUT_VIA_ALIAS=y +CONFIG_HUSH_PARSER=y +CONFIG_SYS_PROMPT="boston # " +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_IMLS is not set +CONFIG_CMD_GREPENV=y +CONFIG_CMD_MEMTEST=y +# CONFIG_CMD_LOADB is not set +# CONFIG_CMD_LOADS is not set +# CONFIG_CMD_FPGA is not set +CONFIG_CMD_DHCP=y +CONFIG_CMD_PING=y +CONFIG_CMD_SNTP=y +CONFIG_CMD_DNS=y +CONFIG_CMD_LINK_LOCAL=y +CONFIG_CMD_TIME=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_OF_EMBED=y +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_CLK=y +CONFIG_MTD=y +CONFIG_CFI_FLASH=y +CONFIG_DM_ETH=y +CONFIG_PCH_GBE=y +CONFIG_DM_PCI=y +CONFIG_PCI_XILINX=y +CONFIG_SYS_NS16550=y +CONFIG_LZ4=y diff --git a/configs/boston64r2el_defconfig b/configs/boston64r2el_defconfig new file mode 100644 index 0000000000..9b5fa5aa48 --- /dev/null +++ b/configs/boston64r2el_defconfig @@ -0,0 +1,42 @@ +CONFIG_MIPS=y +CONFIG_TARGET_BOSTON=y +CONFIG_SYS_LITTLE_ENDIAN=y +CONFIG_CPU_MIPS64_R2=y +# CONFIG_MIPS_BOOT_CMDLINE_LEGACY is not set +# CONFIG_MIPS_BOOT_ENV_LEGACY is not set +CONFIG_MIPS_BOOT_FDT=y +CONFIG_DEFAULT_DEVICE_TREE="img,boston" +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_FIT_BEST_MATCH=y +CONFIG_OF_STDOUT_VIA_ALIAS=y +CONFIG_HUSH_PARSER=y +CONFIG_SYS_PROMPT="boston # " +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_IMLS is not set +CONFIG_CMD_GREPENV=y +CONFIG_CMD_MEMTEST=y +# CONFIG_CMD_LOADB is not set +# CONFIG_CMD_LOADS is not set +# CONFIG_CMD_FPGA is not set +CONFIG_CMD_DHCP=y +CONFIG_CMD_PING=y +CONFIG_CMD_SNTP=y +CONFIG_CMD_DNS=y +CONFIG_CMD_LINK_LOCAL=y +CONFIG_CMD_TIME=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_OF_EMBED=y +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_CLK=y +CONFIG_MTD=y +CONFIG_CFI_FLASH=y +CONFIG_DM_ETH=y +CONFIG_PCH_GBE=y +CONFIG_DM_PCI=y +CONFIG_PCI_XILINX=y +CONFIG_SYS_NS16550=y +CONFIG_LZ4=y diff --git a/configs/imgtec_xilfpga_defconfig b/configs/imgtec_xilfpga_defconfig new file mode 100644 index 0000000000..63f03cd642 --- /dev/null +++ b/configs/imgtec_xilfpga_defconfig @@ -0,0 +1,25 @@ +CONFIG_MIPS=y +CONFIG_SYS_MALLOC_F_LEN=0x600 +CONFIG_TARGET_XILFPGA=y +# CONFIG_MIPS_BOOT_ENV_LEGACY is not set +CONFIG_MIPS_BOOT_FDT=y +CONFIG_DEFAULT_DEVICE_TREE="nexys4ddr" +CONFIG_BOOTDELAY=5 +CONFIG_HUSH_PARSER=y +CONFIG_SYS_PROMPT="MIPSfpga # " +# CONFIG_CMD_IMLS is not set +# CONFIG_CMD_SAVEENV is not set +CONFIG_CMD_MEMINFO=y +# CONFIG_CMD_FLASH is not set +# CONFIG_CMD_FPGA is not set +CONFIG_CMD_DHCP=y +CONFIG_CMD_MII=y +CONFIG_CMD_PING=y +CONFIG_CMD_TIME=y +CONFIG_OF_EMBED=y +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_NETCONSOLE=y +CONFIG_CLK=y +CONFIG_XILINX_EMACLITE=y +CONFIG_SYS_NS16550=y +CONFIG_CMD_DHRYSTONE=y diff --git a/doc/README.boston b/doc/README.boston new file mode 100644 index 0000000000..38f6710e4a --- /dev/null +++ b/doc/README.boston @@ -0,0 +1,58 @@ +MIPS Boston Development Board + +--------- + About +--------- + +The MIPS Boston development board is built around an FPGA & 3 PCIe controllers, +one of which is connected to an Intel EG20T Platform Controller Hub which +provides most connectivity to the board. It is used during the development & +testing of both new CPUs and the software support for them. It is essentially +the successor of the older MIPS Malta board. + +-------- + QEMU +-------- + +U-Boot can be run on a currently out-of-tree branch of QEMU with support for +the Boston board added. This QEMU code can currently be found in the "boston" +branch of git://git.linux-mips.org/pub/scm/paul/qemu.git and used like so: + + $ git clone git://git.linux-mips.org/pub/scm/paul/qemu.git -b boston + $ cd qemu + $ ./configure --target-list=mips64el-softmmu + $ make + $ ./mips64el-softmmu/qemu-system-mips64el -M boston -m 2G \ + -bios u-boot.bin -serial stdio + +Please note that QEMU will default to emulating the I6400 CPU which implements +the MIPS64r6 ISA, and at the time of writing doesn't implement any earlier CPUs +with support for the CPS features the Boston board relies upon. You will +therefore need to configure U-Boot to build for MIPSr6 in order to obtain a +binary that will work in QEMU. + +------------- + Toolchain +------------- + +If building for MIPSr6 then you will need a toolchain including GCC 5.x or +newer, or the Codescape toolchain available for download from Imagination +Technologies: + + http://codescape-mips-sdk.imgtec.com/components/toolchain/2015.06-05/ + +The "IMG GNU Linux Toolchain" is capable of building for all current MIPS ISAs, +architecture revisions & both endiannesses. + +-------- + TODO +-------- + + - AHCI support + - CPU driver + - Exception handling (+UHI?) + - Flash support + - IOCU support + - L2 cache support + - More general LCD display driver + - Multi-arch-variant multi-endian fat binary diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 8f3b96a973..c05ce2a9ef 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -20,6 +20,14 @@ config SPL_CLK setting up clocks within SPL, and allows the same drivers to be used as U-Boot proper. +config CLK_BOSTON + def_bool y if TARGET_BOSTON + depends on CLK + select REGMAP + select SYSCON + help + Enable this to support the clocks + source "drivers/clk/tegra/Kconfig" source "drivers/clk/uniphier/Kconfig" source "drivers/clk/exynos/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 778d7486f0..40a5e8cae8 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -15,3 +15,4 @@ obj-y += tegra/ obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ obj-$(CONFIG_CLK_EXYNOS) += exynos/ obj-$(CONFIG_CLK_AT91) += at91/ +obj-$(CONFIG_CLK_BOSTON) += clk_boston.o diff --git a/drivers/clk/clk_boston.c b/drivers/clk/clk_boston.c new file mode 100644 index 0000000000..78f1b759d8 --- /dev/null +++ b/drivers/clk/clk_boston.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <dt-bindings/clock/boston-clock.h> +#include <regmap.h> +#include <syscon.h> + +struct clk_boston { + struct regmap *regmap; +}; + +#define BOSTON_PLAT_MMCMDIV 0x30 +# define BOSTON_PLAT_MMCMDIV_CLK0DIV (0xff << 0) +# define BOSTON_PLAT_MMCMDIV_INPUT (0xff << 8) +# define BOSTON_PLAT_MMCMDIV_MUL (0xff << 16) +# define BOSTON_PLAT_MMCMDIV_CLK1DIV (0xff << 24) + +static uint32_t ext_field(uint32_t val, uint32_t mask) +{ + return (val & mask) >> (ffs(mask) - 1); +} + +static ulong clk_boston_get_rate(struct clk *clk) +{ + struct clk_boston *state = dev_get_platdata(clk->dev); + uint32_t in_rate, mul, div; + uint mmcmdiv; + int err; + + err = regmap_read(state->regmap, BOSTON_PLAT_MMCMDIV, &mmcmdiv); + if (err) + return 0; + + in_rate = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_INPUT); + mul = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_MUL); + + switch (clk->id) { + case BOSTON_CLK_SYS: + div = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_CLK0DIV); + break; + case BOSTON_CLK_CPU: + div = ext_field(mmcmdiv, BOSTON_PLAT_MMCMDIV_CLK1DIV); + break; + default: + return 0; + } + + return (in_rate * mul * 1000000) / div; +} + +const struct clk_ops clk_boston_ops = { + .get_rate = clk_boston_get_rate, +}; + +static int clk_boston_ofdata_to_platdata(struct udevice *dev) +{ + struct clk_boston *state = dev_get_platdata(dev); + struct udevice *syscon; + int err; + + err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, + "regmap", &syscon); + if (err) { + error("unable to find syscon device\n"); + return err; + } + + state->regmap = syscon_get_regmap(syscon); + if (!state->regmap) { + error("unable to find regmap\n"); + return -ENODEV; + } + + return 0; +} + +static const struct udevice_id clk_boston_match[] = { + { + .compatible = "img,boston-clock", + }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(clk_boston) = { + .name = "boston_clock", + .id = UCLASS_CLK, + .of_match = clk_boston_match, + .ofdata_to_platdata = clk_boston_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct clk_boston), + .ops = &clk_boston_ops, +}; diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 6a634e6951..23b6ba78d3 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -101,36 +101,24 @@ int device_bind_driver_to_node(struct udevice *parent, const char *drv_name, #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) /** - * driver_check_compatible() - Check if a driver is compatible with this node + * driver_check_compatible() - Check if a driver matches a compatible string * - * @param blob: Device tree pointer - * @param offset: Offset of node in device tree * @param of_match: List of compatible strings to match * @param of_idp: Returns the match that was found - * @return 0 if there is a match, -ENOENT if no match, -ENODEV if the node - * does not have a compatible string, other error <0 if there is a device - * tree error + * @param compat: The compatible string to search for + * @return 0 if there is a match, -ENOENT if no match */ -static int driver_check_compatible(const void *blob, int offset, - const struct udevice_id *of_match, - const struct udevice_id **of_idp) +static int driver_check_compatible(const struct udevice_id *of_match, + const struct udevice_id **of_idp, + const char *compat) { - int ret; - - *of_idp = NULL; if (!of_match) return -ENOENT; while (of_match->compatible) { - ret = fdt_node_check_compatible(blob, offset, - of_match->compatible); - if (!ret) { + if (!strcmp(of_match->compatible, compat)) { *of_idp = of_match; return 0; - } else if (ret == -FDT_ERR_NOTFOUND) { - return -ENODEV; - } else if (ret < 0) { - return -EINVAL; } of_match++; } @@ -147,28 +135,46 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, struct driver *entry; struct udevice *dev; bool found = false; - const char *name; + const char *name, *compat_list, *compat; + int compat_length, i; int result = 0; int ret = 0; - dm_dbg("bind node %s\n", fdt_get_name(blob, offset, NULL)); + name = fdt_get_name(blob, offset, NULL); + dm_dbg("bind node %s\n", name); if (devp) *devp = NULL; - for (entry = driver; entry != driver + n_ents; entry++) { - ret = driver_check_compatible(blob, offset, entry->of_match, - &id); - name = fdt_get_name(blob, offset, NULL); - if (ret == -ENOENT) { - continue; - } else if (ret == -ENODEV) { + + compat_list = fdt_getprop(blob, offset, "compatible", &compat_length); + if (!compat_list) { + if (compat_length == -FDT_ERR_NOTFOUND) { dm_dbg("Device '%s' has no compatible string\n", name); - break; - } else if (ret) { - dm_warn("Device tree error at offset %d\n", offset); - result = ret; - break; + return 0; } + dm_warn("Device tree error at offset %d\n", offset); + return compat_length; + } + + /* + * Walk through the compatible string list, attempting to match each + * compatible string in order such that we match in order of priority + * from the first string to the last. + */ + for (i = 0; i < compat_length; i += strlen(compat) + 1) { + compat = compat_list + i; + dm_dbg(" - attempt to match compatible string '%s'\n", + compat); + + for (entry = driver; entry != driver + n_ents; entry++) { + ret = driver_check_compatible(entry->of_match, &id, + compat); + if (!ret) + break; + } + if (entry == driver + n_ents) + continue; + dm_dbg(" - found match at '%s'\n", entry->name); ret = device_bind_with_driver_data(parent, entry, name, id->data, offset, &dev); @@ -188,10 +194,8 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, break; } - if (!found && !result && ret != -ENODEV) { - dm_dbg("No match for node '%s'\n", - fdt_get_name(blob, offset, NULL)); - } + if (!found && !result && ret != -ENODEV) + dm_dbg("No match for node '%s'\n", name); return result; } diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index 0299ff0879..c68bcba54f 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -13,6 +13,8 @@ #include <mapmem.h> #include <regmap.h> +#include <asm/io.h> + DECLARE_GLOBAL_DATA_PTR; static struct regmap *regmap_alloc_count(int count) @@ -117,3 +119,21 @@ int regmap_uninit(struct regmap *map) return 0; } + +int regmap_read(struct regmap *map, uint offset, uint *valp) +{ + uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE); + + *valp = le32_to_cpu(readl(ptr)); + + return 0; +} + +int regmap_write(struct regmap *map, uint offset, uint val) +{ + uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE); + + writel(cpu_to_le32(val), ptr); + + return 0; +} diff --git a/drivers/core/syscon-uclass.c b/drivers/core/syscon-uclass.c index 01bd9683a7..2148469abc 100644 --- a/drivers/core/syscon-uclass.c +++ b/drivers/core/syscon-uclass.c @@ -95,3 +95,14 @@ UCLASS_DRIVER(syscon) = { .per_device_auto_alloc_size = sizeof(struct syscon_uc_info), .pre_probe = syscon_pre_probe, }; + +static const struct udevice_id generic_syscon_ids[] = { + { .compatible = "syscon" }, + { } +}; + +U_BOOT_DRIVER(generic_syscon) = { + .name = "syscon", + .id = UCLASS_SYSCON, + .of_match = generic_syscon_ids, +}; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index be3ed73e52..302c005aa1 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -175,7 +175,7 @@ config XILINX_AXIEMAC This MAC is present in Xilinx Microblaze, Zynq and ZynqMP SoCs. config XILINX_EMACLITE - depends on DM_ETH && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP) + depends on DM_ETH && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP || MIPS) select PHYLIB select MII bool "Xilinx Ethernetlite" diff --git a/drivers/net/pch_gbe.c b/drivers/net/pch_gbe.c index 137818b390..d40fff0e48 100644 --- a/drivers/net/pch_gbe.c +++ b/drivers/net/pch_gbe.c @@ -118,14 +118,14 @@ static void pch_gbe_rx_descs_init(struct udevice *dev) memset(rx_desc, 0, sizeof(struct pch_gbe_rx_desc) * PCH_GBE_DESC_NUM); for (i = 0; i < PCH_GBE_DESC_NUM; i++) rx_desc->buffer_addr = dm_pci_phys_to_mem(priv->dev, - (u32)(priv->rx_buff[i])); + (ulong)(priv->rx_buff[i])); - writel(dm_pci_phys_to_mem(priv->dev, (u32)rx_desc), + writel(dm_pci_phys_to_mem(priv->dev, (ulong)rx_desc), &mac_regs->rx_dsc_base); writel(sizeof(struct pch_gbe_rx_desc) * (PCH_GBE_DESC_NUM - 1), &mac_regs->rx_dsc_size); - writel(dm_pci_phys_to_mem(priv->dev, (u32)(rx_desc + 1)), + writel(dm_pci_phys_to_mem(priv->dev, (ulong)(rx_desc + 1)), &mac_regs->rx_dsc_sw_p); } @@ -137,11 +137,11 @@ static void pch_gbe_tx_descs_init(struct udevice *dev) memset(tx_desc, 0, sizeof(struct pch_gbe_tx_desc) * PCH_GBE_DESC_NUM); - writel(dm_pci_phys_to_mem(priv->dev, (u32)tx_desc), + writel(dm_pci_phys_to_mem(priv->dev, (ulong)tx_desc), &mac_regs->tx_dsc_base); writel(sizeof(struct pch_gbe_tx_desc) * (PCH_GBE_DESC_NUM - 1), &mac_regs->tx_dsc_size); - writel(dm_pci_phys_to_mem(priv->dev, (u32)(tx_desc + 1)), + writel(dm_pci_phys_to_mem(priv->dev, (ulong)(tx_desc + 1)), &mac_regs->tx_dsc_sw_p); } @@ -251,7 +251,7 @@ static int pch_gbe_send(struct udevice *dev, void *packet, int length) if (length < 64) frame_ctrl |= PCH_GBE_TXD_CTRL_APAD; - tx_desc->buffer_addr = dm_pci_phys_to_mem(priv->dev, (u32)packet); + tx_desc->buffer_addr = dm_pci_phys_to_mem(priv->dev, (ulong)packet); tx_desc->length = length; tx_desc->tx_words_eob = length + 3; tx_desc->tx_frame_ctrl = frame_ctrl; @@ -262,7 +262,7 @@ static int pch_gbe_send(struct udevice *dev, void *packet, int length) if (++priv->tx_idx >= PCH_GBE_DESC_NUM) priv->tx_idx = 0; - writel(dm_pci_phys_to_mem(priv->dev, (u32)(tx_head + priv->tx_idx)), + writel(dm_pci_phys_to_mem(priv->dev, (ulong)(tx_head + priv->tx_idx)), &mac_regs->tx_dsc_sw_p); start = get_timer(0); @@ -283,7 +283,7 @@ static int pch_gbe_recv(struct udevice *dev, int flags, uchar **packetp) struct pch_gbe_priv *priv = dev_get_priv(dev); struct pch_gbe_regs *mac_regs = priv->mac_regs; struct pch_gbe_rx_desc *rx_desc; - u32 hw_desc, buffer_addr, length; + ulong hw_desc, buffer_addr, length; rx_desc = &priv->rx_desc[priv->rx_idx]; @@ -291,7 +291,7 @@ static int pch_gbe_recv(struct udevice *dev, int flags, uchar **packetp) hw_desc = readl(&mac_regs->rx_dsc_hw_p_hld); /* Just return if not receiving any packet */ - if ((u32)rx_desc == hw_desc) + if ((ulong)rx_desc == hw_desc) return -EAGAIN; buffer_addr = dm_pci_mem_to_phys(priv->dev, rx_desc->buffer_addr); @@ -315,7 +315,7 @@ static int pch_gbe_free_pkt(struct udevice *dev, uchar *packet, int length) if (++rx_swp >= PCH_GBE_DESC_NUM) rx_swp = 0; - writel(dm_pci_phys_to_mem(priv->dev, (u32)(rx_head + rx_swp)), + writel(dm_pci_phys_to_mem(priv->dev, (ulong)(rx_head + rx_swp)), &mac_regs->rx_dsc_sw_p); return 0; @@ -421,7 +421,7 @@ int pch_gbe_probe(struct udevice *dev) { struct pch_gbe_priv *priv; struct eth_pdata *plat = dev_get_platdata(dev); - u32 iobase; + void *iobase; /* * The priv structure contains the descriptors and frame buffers which @@ -432,11 +432,9 @@ int pch_gbe_probe(struct udevice *dev) priv->dev = dev; - dm_pci_read_config32(dev, PCI_BASE_ADDRESS_1, &iobase); - iobase &= PCI_BASE_ADDRESS_MEM_MASK; - iobase = dm_pci_mem_to_phys(dev, iobase); + iobase = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_1, PCI_REGION_MEM); - plat->iobase = iobase; + plat->iobase = (ulong)iobase; priv->mac_regs = (struct pch_gbe_regs *)iobase; /* Read MAC address from SROM and initialize dev->enetaddr with it */ diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c index 7b85aa0463..d86e7a3954 100644 --- a/drivers/net/xilinx_emaclite.c +++ b/drivers/net/xilinx_emaclite.c @@ -19,6 +19,7 @@ #include <fdtdec.h> #include <asm-generic/errno.h> #include <linux/kernel.h> +#include <asm/io.h> DECLARE_GLOBAL_DATA_PTR; @@ -154,7 +155,7 @@ static int wait_for_bit(const char *func, u32 *reg, const u32 mask, unsigned long start = get_timer(0); while (1) { - val = readl(reg); + val = __raw_readl(reg); if (!set) val = ~val; @@ -193,16 +194,17 @@ static u32 phyread(struct xemaclite *emaclite, u32 phyaddress, u32 registernum, if (mdio_wait(regs)) return 1; - u32 ctrl_reg = in_be32(®s->mdioctrl); - out_be32(®s->mdioaddr, XEL_MDIOADDR_OP_MASK | - ((phyaddress << XEL_MDIOADDR_PHYADR_SHIFT) | registernum)); - out_be32(®s->mdioctrl, ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK); + u32 ctrl_reg = __raw_readl(®s->mdioctrl); + __raw_writel(XEL_MDIOADDR_OP_MASK + | ((phyaddress << XEL_MDIOADDR_PHYADR_SHIFT) + | registernum), ®s->mdioaddr); + __raw_writel(ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK, ®s->mdioctrl); if (mdio_wait(regs)) return 1; /* Read data */ - *data = in_be32(®s->mdiord); + *data = __raw_readl(®s->mdiord); return 0; } @@ -220,11 +222,12 @@ static u32 phywrite(struct xemaclite *emaclite, u32 phyaddress, u32 registernum, * Data register. Finally, set the Status bit in the MDIO Control * register to start a MDIO write transaction. */ - u32 ctrl_reg = in_be32(®s->mdioctrl); - out_be32(®s->mdioaddr, ~XEL_MDIOADDR_OP_MASK & - ((phyaddress << XEL_MDIOADDR_PHYADR_SHIFT) | registernum)); - out_be32(®s->mdiowr, data); - out_be32(®s->mdioctrl, ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK); + u32 ctrl_reg = __raw_readl(®s->mdioctrl); + __raw_writel(~XEL_MDIOADDR_OP_MASK + & ((phyaddress << XEL_MDIOADDR_PHYADR_SHIFT) + | registernum), ®s->mdioaddr); + __raw_writel(data, ®s->mdiowr); + __raw_writel(ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK, ®s->mdioctrl); if (mdio_wait(regs)) return 1; @@ -327,27 +330,27 @@ static int emaclite_start(struct udevice *dev) * TX - TX_PING & TX_PONG initialization */ /* Restart PING TX */ - out_be32(®s->tx_ping_tsr, 0); + __raw_writel(0, ®s->tx_ping_tsr); /* Copy MAC address */ xemaclite_alignedwrite(pdata->enetaddr, ®s->tx_ping, ENET_ADDR_LENGTH); /* Set the length */ - out_be32(®s->tx_ping_tplr, ENET_ADDR_LENGTH); + __raw_writel(ENET_ADDR_LENGTH, ®s->tx_ping_tplr); /* Update the MAC address in the EMAC Lite */ - out_be32(®s->tx_ping_tsr, XEL_TSR_PROG_MAC_ADDR); + __raw_writel(XEL_TSR_PROG_MAC_ADDR, ®s->tx_ping_tsr); /* Wait for EMAC Lite to finish with the MAC address update */ - while ((in_be32 (®s->tx_ping_tsr) & + while ((__raw_readl(®s->tx_ping_tsr) & XEL_TSR_PROG_MAC_ADDR) != 0) ; if (emaclite->txpp) { /* The same operation with PONG TX */ - out_be32(®s->tx_pong_tsr, 0); + __raw_writel(0, ®s->tx_pong_tsr); xemaclite_alignedwrite(pdata->enetaddr, ®s->tx_pong, ENET_ADDR_LENGTH); - out_be32(®s->tx_pong_tplr, ENET_ADDR_LENGTH); - out_be32(®s->tx_pong_tsr, XEL_TSR_PROG_MAC_ADDR); - while ((in_be32(®s->tx_pong_tsr) & + __raw_writel(ENET_ADDR_LENGTH, ®s->tx_pong_tplr); + __raw_writel(XEL_TSR_PROG_MAC_ADDR, ®s->tx_pong_tsr); + while ((__raw_readl(®s->tx_pong_tsr) & XEL_TSR_PROG_MAC_ADDR) != 0) ; } @@ -356,13 +359,13 @@ static int emaclite_start(struct udevice *dev) * RX - RX_PING & RX_PONG initialization */ /* Write out the value to flush the RX buffer */ - out_be32(®s->rx_ping_rsr, XEL_RSR_RECV_IE_MASK); + __raw_writel(XEL_RSR_RECV_IE_MASK, ®s->rx_ping_rsr); if (emaclite->rxpp) - out_be32(®s->rx_pong_rsr, XEL_RSR_RECV_IE_MASK); + __raw_writel(XEL_RSR_RECV_IE_MASK, ®s->rx_pong_rsr); - out_be32(®s->mdioctrl, XEL_MDIOCTRL_MDIOEN_MASK); - if (in_be32(®s->mdioctrl) & XEL_MDIOCTRL_MDIOEN_MASK) + __raw_writel(XEL_MDIOCTRL_MDIOEN_MASK, ®s->mdioctrl); + if (__raw_readl(®s->mdioctrl) & XEL_MDIOCTRL_MDIOEN_MASK) if (!setup_phy(dev)) return -1; @@ -379,9 +382,9 @@ static int xemaclite_txbufferavailable(struct xemaclite *emaclite) * Read the other buffer register * and determine if the other buffer is available */ - tmp = ~in_be32(®s->tx_ping_tsr); + tmp = ~__raw_readl(®s->tx_ping_tsr); if (emaclite->txpp) - tmp |= ~in_be32(®s->tx_pong_tsr); + tmp |= ~__raw_readl(®s->tx_pong_tsr); return !(tmp & XEL_TSR_XMIT_BUSY_MASK); } @@ -405,40 +408,42 @@ static int emaclite_send(struct udevice *dev, void *ptr, int len) if (!maxtry) { printf("Error: Timeout waiting for ethernet TX buffer\n"); /* Restart PING TX */ - out_be32(®s->tx_ping_tsr, 0); + __raw_writel(0, ®s->tx_ping_tsr); if (emaclite->txpp) { - out_be32(®s->tx_pong_tsr, 0); + __raw_writel(0, ®s->tx_pong_tsr); } return -1; } /* Determine if the expected buffer address is empty */ - reg = in_be32(®s->tx_ping_tsr); + reg = __raw_readl(®s->tx_ping_tsr); if ((reg & XEL_TSR_XMIT_BUSY_MASK) == 0) { debug("Send packet from tx_ping buffer\n"); /* Write the frame to the buffer */ xemaclite_alignedwrite(ptr, ®s->tx_ping, len); - out_be32(®s->tx_ping_tplr, len & - (XEL_TPLR_LENGTH_MASK_HI | XEL_TPLR_LENGTH_MASK_LO)); - reg = in_be32(®s->tx_ping_tsr); + __raw_writel(len + & (XEL_TPLR_LENGTH_MASK_HI | XEL_TPLR_LENGTH_MASK_LO), + ®s->tx_ping_tplr); + reg = __raw_readl(®s->tx_ping_tsr); reg |= XEL_TSR_XMIT_BUSY_MASK; - out_be32(®s->tx_ping_tsr, reg); + __raw_writel(reg, ®s->tx_ping_tsr); return 0; } if (emaclite->txpp) { /* Determine if the expected buffer address is empty */ - reg = in_be32(®s->tx_pong_tsr); + reg = __raw_readl(®s->tx_pong_tsr); if ((reg & XEL_TSR_XMIT_BUSY_MASK) == 0) { debug("Send packet from tx_pong buffer\n"); /* Write the frame to the buffer */ xemaclite_alignedwrite(ptr, ®s->tx_pong, len); - out_be32(®s->tx_pong_tplr, len & + __raw_writel(len & (XEL_TPLR_LENGTH_MASK_HI | - XEL_TPLR_LENGTH_MASK_LO)); - reg = in_be32(®s->tx_pong_tsr); + XEL_TPLR_LENGTH_MASK_LO), + ®s->tx_pong_tplr); + reg = __raw_readl(®s->tx_pong_tsr); reg |= XEL_TSR_XMIT_BUSY_MASK; - out_be32(®s->tx_pong_tsr, reg); + __raw_writel(reg, ®s->tx_pong_tsr); return 0; } } @@ -458,7 +463,7 @@ static int emaclite_recv(struct udevice *dev, int flags, uchar **packetp) try_again: if (!emaclite->use_rx_pong_buffer_next) { - reg = in_be32(®s->rx_ping_rsr); + reg = __raw_readl(®s->rx_ping_rsr); debug("Testing data at rx_ping\n"); if ((reg & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) { debug("Data found in rx_ping buffer\n"); @@ -478,7 +483,7 @@ try_again: goto try_again; } } else { - reg = in_be32(®s->rx_pong_rsr); + reg = __raw_readl(®s->rx_pong_rsr); debug("Testing data at rx_pong\n"); if ((reg & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) { debug("Data found in rx_pong buffer\n"); @@ -525,9 +530,9 @@ try_again: length - first_read); /* Acknowledge the frame */ - reg = in_be32(ack); + reg = __raw_readl(ack); reg &= ~XEL_RSR_RECV_DONE_MASK; - out_be32(ack, reg); + __raw_writel(reg, ack); debug("Packet receive from 0x%p, length %dB\n", addr, length); *packetp = etherrxbuff; @@ -595,7 +600,8 @@ static int emaclite_ofdata_to_platdata(struct udevice *dev) int offset = 0; pdata->iobase = (phys_addr_t)dev_get_addr(dev); - emaclite->regs = (struct emaclite_regs *)pdata->iobase; + emaclite->regs = (struct emaclite_regs *)ioremap_nocache(pdata->iobase, + 0x10000); emaclite->phyaddr = -1; diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 669e37bb5d..9a7c187446 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -39,4 +39,11 @@ config PCI_TEGRA with a total of 5 lanes. Some boards require this for Ethernet support to work (e.g. beaver, jetson-tk1). +config PCI_XILINX + bool "Xilinx AXI Bridge for PCI Express" + depends on DM_PCI + help + Enable support for the Xilinx AXI bridge for PCI express, an IP block + which can be used on some generations of Xilinx FPGAs. + endmenu diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index f8be9bf1ea..9583e91ceb 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_PCI_TEGRA) += pci_tegra.o obj-$(CONFIG_TSI108_PCI) += tsi108_pci.o obj-$(CONFIG_WINBOND_83C553) += w83c553f.o obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape.o +obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 342b78c0c4..3b00e6a41b 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -837,7 +837,7 @@ static int pci_uclass_pre_probe(struct udevice *bus) hose = bus->uclass_priv; /* For bridges, use the top-level PCI controller */ - if (device_get_uclass_id(bus->parent) == UCLASS_ROOT) { + if (!device_is_on_pci_bus(bus)) { hose->ctlr = bus; ret = decode_regions(hose, gd->fdt_blob, bus->parent->of_offset, bus->of_offset); diff --git a/drivers/pci/pcie_xilinx.c b/drivers/pci/pcie_xilinx.c new file mode 100644 index 0000000000..521600180e --- /dev/null +++ b/drivers/pci/pcie_xilinx.c @@ -0,0 +1,220 @@ +/* + * Xilinx AXI Bridge for PCI Express Driver + * + * Copyright (C) 2016 Imagination Technologies + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <dm.h> +#include <pci.h> + +#include <asm/io.h> + +/** + * struct xilinx_pcie - Xilinx PCIe controller state + * @hose: The parent classes PCI controller state + * @cfg_base: The base address of memory mapped configuration space + */ +struct xilinx_pcie { + struct pci_controller hose; + void *cfg_base; +}; + +/* Register definitions */ +#define XILINX_PCIE_REG_PSCR 0x144 +#define XILINX_PCIE_REG_PSCR_LNKUP BIT(11) + +/** + * pcie_xilinx_link_up() - Check whether the PCIe link is up + * @pcie: Pointer to the PCI controller state + * + * Checks whether the PCIe link for the given device is up or down. + * + * Return: true if the link is up, else false + */ +static bool pcie_xilinx_link_up(struct xilinx_pcie *pcie) +{ + uint32_t pscr = __raw_readl(pcie->cfg_base + XILINX_PCIE_REG_PSCR); + + return pscr & XILINX_PCIE_REG_PSCR_LNKUP; +} + +/** + * pcie_xilinx_config_address() - Calculate the address of a config access + * @pcie: Pointer to the PCI controller state + * @bdf: Identifies the PCIe device to access + * @offset: The offset into the device's configuration space + * @paddress: Pointer to the pointer to write the calculates address to + * + * Calculates the address that should be accessed to perform a PCIe + * configuration space access for a given device identified by the PCIe + * controller device @pcie and the bus, device & function numbers in @bdf. If + * access to the device is not valid then the function will return an error + * code. Otherwise the address to access will be written to the pointer pointed + * to by @paddress. + * + * Return: 0 on success, else -ENODEV + */ +static int pcie_xilinx_config_address(struct xilinx_pcie *pcie, pci_dev_t bdf, + uint offset, void **paddress) +{ + unsigned int bus = PCI_BUS(bdf); + unsigned int dev = PCI_DEV(bdf); + unsigned int func = PCI_FUNC(bdf); + void *addr; + + if ((bus > 0) && !pcie_xilinx_link_up(pcie)) + return -ENODEV; + + /* + * Busses 0 (host-PCIe bridge) & 1 (its immediate child) are + * limited to a single device each. + */ + if ((bus < 2) && (dev > 0)) + return -ENODEV; + + addr = pcie->cfg_base; + addr += bus << 20; + addr += dev << 15; + addr += func << 12; + addr += offset; + *paddress = addr; + + return 0; +} + +/** + * pcie_xilinx_read_config() - Read from configuration space + * @pcie: Pointer to the PCI controller state + * @bdf: Identifies the PCIe device to access + * @offset: The offset into the device's configuration space + * @valuep: A pointer at which to store the read value + * @size: Indicates the size of access to perform + * + * Read a value of size @size from offset @offset within the configuration + * space of the device identified by the bus, device & function numbers in @bdf + * on the PCI bus @bus. + * + * Return: 0 on success, else -ENODEV or -EINVAL + */ +static int pcie_xilinx_read_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong *valuep, + enum pci_size_t size) +{ + struct xilinx_pcie *pcie = dev_get_priv(bus); + void *address; + int err; + + err = pcie_xilinx_config_address(pcie, bdf, offset, &address); + if (err < 0) { + *valuep = pci_get_ff(size); + return 0; + } + + switch (size) { + case PCI_SIZE_8: + *valuep = __raw_readb(address); + return 0; + case PCI_SIZE_16: + *valuep = __raw_readw(address); + return 0; + case PCI_SIZE_32: + *valuep = __raw_readl(address); + return 0; + default: + return -EINVAL; + } +} + +/** + * pcie_xilinx_write_config() - Write to configuration space + * @pcie: Pointer to the PCI controller state + * @bdf: Identifies the PCIe device to access + * @offset: The offset into the device's configuration space + * @value: The value to write + * @size: Indicates the size of access to perform + * + * Write the value @value of size @size from offset @offset within the + * configuration space of the device identified by the bus, device & function + * numbers in @bdf on the PCI bus @bus. + * + * Return: 0 on success, else -ENODEV or -EINVAL + */ +static int pcie_xilinx_write_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong value, + enum pci_size_t size) +{ + struct xilinx_pcie *pcie = dev_get_priv(bus); + void *address; + int err; + + err = pcie_xilinx_config_address(pcie, bdf, offset, &address); + if (err < 0) + return 0; + + switch (size) { + case PCI_SIZE_8: + __raw_writeb(value, address); + return 0; + case PCI_SIZE_16: + __raw_writew(value, address); + return 0; + case PCI_SIZE_32: + __raw_writel(value, address); + return 0; + default: + return -EINVAL; + } +} + +/** + * pcie_xilinx_ofdata_to_platdata() - Translate from DT to device state + * @dev: A pointer to the device being operated on + * + * Translate relevant data from the device tree pertaining to device @dev into + * state that the driver will later make use of. This state is stored in the + * device's private data structure. + * + * Return: 0 on success, else -EINVAL + */ +static int pcie_xilinx_ofdata_to_platdata(struct udevice *dev) +{ + struct xilinx_pcie *pcie = dev_get_priv(dev); + struct fdt_resource reg_res; + DECLARE_GLOBAL_DATA_PTR; + int err; + + err = fdt_get_resource(gd->fdt_blob, dev->of_offset, "reg", + 0, ®_res); + if (err < 0) { + error("\"reg\" resource not found\n"); + return err; + } + + pcie->cfg_base = map_physmem(reg_res.start, + fdt_resource_size(®_res), + MAP_NOCACHE); + + return 0; +} + +static const struct dm_pci_ops pcie_xilinx_ops = { + .read_config = pcie_xilinx_read_config, + .write_config = pcie_xilinx_write_config, +}; + +static const struct udevice_id pcie_xilinx_ids[] = { + { .compatible = "xlnx,axi-pcie-host-1.00.a" }, + { } +}; + +U_BOOT_DRIVER(pcie_xilinx) = { + .name = "pcie_xilinx", + .id = UCLASS_PCI, + .of_match = pcie_xilinx_ids, + .ops = &pcie_xilinx_ops, + .ofdata_to_platdata = pcie_xilinx_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct xilinx_pcie), +}; diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 88fca15357..3f6ea4d275 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -5,6 +5,7 @@ */ #include <common.h> +#include <clk.h> #include <dm.h> #include <errno.h> #include <fdtdec.h> @@ -352,6 +353,8 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev) { struct ns16550_platdata *plat = dev->platdata; fdt_addr_t addr; + struct clk clk; + int err; /* try Processor Local Bus device first */ addr = dev_get_addr(dev); @@ -397,9 +400,21 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev) "reg-offset", 0); plat->reg_shift = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg-shift", 0); - plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset, - "clock-frequency", - CONFIG_SYS_NS16550_CLK); + + err = clk_get_by_index(dev, 0, &clk); + if (!err) { + err = clk_get_rate(&clk); + if (!IS_ERR_VALUE(err)) + plat->clock = err; + } else if (err != -ENODEV && err != -ENOSYS) { + debug("ns16550 failed to get clock\n"); + return err; + } + + if (!plat->clock) + plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "clock-frequency", + CONFIG_SYS_NS16550_CLK); if (!plat->clock) { debug("ns16550 clock not defined\n"); return -EINVAL; diff --git a/include/clk.h b/include/clk.h index dc18b0310a..9b2452268d 100644 --- a/include/clk.h +++ b/include/clk.h @@ -59,7 +59,7 @@ struct clk { unsigned long id; }; -#if CONFIG_IS_ENABLED(OF_CONTROL) +#if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(CLK) struct phandle_2_cell; int clk_get_by_index_platdata(struct udevice *dev, int index, struct phandle_2_cell *cells, struct clk *clk); diff --git a/include/configs/boston.h b/include/configs/boston.h new file mode 100644 index 0000000000..e95805408a --- /dev/null +++ b/include/configs/boston.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __CONFIGS_BOSTON_H__ +#define __CONFIGS_BOSTON_H__ + +/* + * General board configuration + */ +#define CONFIG_DISPLAY_BOARDINFO + +/* + * CPU + */ +#define CONFIG_SYS_MIPS_TIMER_FREQ 30000000 + +/* + * PCI + */ +#define CONFIG_PCI +#define CONFIG_PCI_PNP +#define CONFIG_CMD_PCI + +/* + * Memory map + */ +#ifdef CONFIG_64BIT +# define CONFIG_SYS_SDRAM_BASE 0xffffffff80000000 +#else +# define CONFIG_SYS_SDRAM_BASE 0x80000000 +#endif + +#define CONFIG_SYS_INIT_SP_OFFSET 0x400000 + +#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE + +#define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + 0x100000) + +#define CONFIG_SYS_MEMTEST_START (CONFIG_SYS_SDRAM_BASE + 0) +#define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_SDRAM_BASE + 0x10000000) + +#define CONFIG_SYS_MALLOC_LEN (256 * 1024) + +/* + * Console + */ +#define CONFIG_SYS_MAXARGS 16 +#define CONFIG_SYS_CBSIZE 256 +#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \ + sizeof(CONFIG_SYS_PROMPT) + 16) +#define CONFIG_SYS_LONGHELP +#define CONFIG_BAUDRATE 115200 + +/* + * Flash + */ +#define CONFIG_FLASH_CFI_DRIVER +#define CONFIG_SYS_FLASH_CFI +#define CONFIG_SYS_FLASH_PROTECTION +#define CONFIG_SYS_FLASH_USE_BUFFER_WRITE +#define CONFIG_SYS_MAX_FLASH_BANKS_DETECT 1 +#define CONFIG_SYS_MAX_FLASH_SECT 1024 + +/* + * Environment + */ +#define CONFIG_ENV_IS_IN_FLASH +#define CONFIG_ENV_SECT_SIZE 0x20000 +#define CONFIG_ENV_SIZE CONFIG_ENV_SECT_SIZE +#ifdef CONFIG_64BIT +# define CONFIG_ENV_ADDR \ + (0xffffffffb8000000 + (128 << 20) - CONFIG_ENV_SIZE) +#else +# define CONFIG_ENV_ADDR \ + (0xb8000000 + (128 << 20) - CONFIG_ENV_SIZE) +#endif + +#endif /* __CONFIGS_BOSTON_H__ */ diff --git a/include/configs/imgtec_xilfpga.h b/include/configs/imgtec_xilfpga.h new file mode 100644 index 0000000000..0a7fe60214 --- /dev/null +++ b/include/configs/imgtec_xilfpga.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016, Imagination Technologies Ltd. + * + * Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com> + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Imagination Technologies Ltd. MIPSfpga + */ + +#ifndef __XILFPGA_CONFIG_H +#define __XILFPGA_CONFIG_H + +/* BootROM + MIG is pretty smart. DDR and Cache initialized */ +#define CONFIG_SKIP_LOWLEVEL_INIT + +/*-------------------------------------------- + * CPU configuration + */ +/* CPU Timer rate */ +#define CONFIG_SYS_MIPS_TIMER_FREQ 50000000 + +/* Cache Configuration */ +#define CONFIG_SYS_MIPS_CACHE_MODE CONF_CM_CACHABLE_NONCOHERENT + +/*---------------------------------------------------------------------- + * Memory Layout + */ + +/* SDRAM Configuration (for final code, data, stack, heap) */ +#define CONFIG_SYS_SDRAM_BASE 0x80000000 +#define CONFIG_SYS_SDRAM_SIZE 0x08000000 /* 128 Mbytes */ +#define CONFIG_SYS_INIT_SP_ADDR \ + (CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_SDRAM_SIZE - 0x1000) + +#define CONFIG_SYS_MALLOC_LEN (256 << 10) +#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE +#define CONFIG_SYS_LOAD_ADDR 0x80500000 /* default load address */ + +/*---------------------------------------------------------------------- + * Commands + */ +#define CONFIG_SYS_LONGHELP /* undef to save memory */ + +/*------------------------------------------------- + * FLASH configuration + */ +#define CONFIG_SYS_NO_FLASH + +/*------------------------------------------------------------ + * Console Configuration + */ +#define CONFIG_SYS_CBSIZE 1024 /* Console I/O Buffer Size */ +#define CONFIG_SYS_MAXARGS 16 /* max number of command args*/ +#define CONFIG_BAUDRATE 115200 + +/* ------------------------------------------------- + * Environment + */ +#define CONFIG_ENV_IS_NOWHERE 1 +#define CONFIG_ENV_SIZE 0x4000 + +/* --------------------------------------------------------------------- + * Board boot configuration + */ +#define CONFIG_TIMESTAMP /* Print image info with timestamp */ + +#endif /* __XILFPGA_CONFIG_H */ diff --git a/include/dt-bindings/clock/boston-clock.h b/include/dt-bindings/clock/boston-clock.h new file mode 100644 index 0000000000..25f9cd25f2 --- /dev/null +++ b/include/dt-bindings/clock/boston-clock.h @@ -0,0 +1,13 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef __DT_BINDINGS_CLOCK_BOSTON_CLOCK_H__ +#define __DT_BINDINGS_CLOCK_BOSTON_CLOCK_H__ + +#define BOSTON_CLK_SYS 0 +#define BOSTON_CLK_CPU 1 + +#endif /* __DT_BINDINGS_CLOCK_BOSTON_CLOCK_H__ */ diff --git a/include/dt-bindings/interrupt-controller/mips-gic.h b/include/dt-bindings/interrupt-controller/mips-gic.h new file mode 100644 index 0000000000..cf35a577e3 --- /dev/null +++ b/include/dt-bindings/interrupt-controller/mips-gic.h @@ -0,0 +1,9 @@ +#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_MIPS_GIC_H +#define _DT_BINDINGS_INTERRUPT_CONTROLLER_MIPS_GIC_H + +#include <dt-bindings/interrupt-controller/irq.h> + +#define GIC_SHARED 0 +#define GIC_LOCAL 1 + +#endif |