[U-Boot] [PATCH 1/4] mips: Add basic MediaTek MT7620/88 support
Stefan Roese
sr at denx.de
Thu Aug 9 14:22:22 UTC 2018
Hi Daniel,
On 09.08.2018 15:28, Daniel Schwierzeck wrote:
> Am Do., 9. Aug. 2018 um 12:46 Uhr schrieb Stefan Roese <sr at denx.de>:
>>
>> Hi Daniel,
>>
>> On 07.08.2018 17:44, Daniel Schwierzeck wrote:
>>> 2018-08-06 17:11 GMT+02:00 Stefan Roese <sr at denx.de>:
>>>> This patch adds basic support for the MediaTek MT7620/88 SoCs. Parts of
>>>> the code is copied from the MediaTek GitHub repository:
>>>>
>>>> https://github.com/MediaTek-Labs/linkit-smart-uboot.git
>>>>
>>>> Support for the LinkIt Smart 7688 module and the Gardena Smart Gateway
>>>> both based on the MT7688 will be added in further patches.
>>>>
>>>> Signed-off-by: Stefan Roese <sr at denx.de>
>>>> Cc: Daniel Schwierzeck <daniel.schwierzeck at gmail.com>
>>>> ---
>>>> arch/mips/Kconfig | 15 ++
>>>> arch/mips/Makefile | 1 +
>>>> arch/mips/mach-mt7620/Kconfig | 130 ++++++++++
>>>> arch/mips/mach-mt7620/Makefile | 8 +
>>>> arch/mips/mach-mt7620/cpu.c | 66 +++++
>>>> arch/mips/mach-mt7620/ddr_calibrate.c | 331 +++++++++++++++++++++++++
>>>> arch/mips/mach-mt7620/lowlevel_init.S | 337 ++++++++++++++++++++++++++
>>>> arch/mips/mach-mt7620/mt76xx.h | 39 +++
>>>> 8 files changed, 927 insertions(+)
>>>> create mode 100644 arch/mips/mach-mt7620/Kconfig
>>>> create mode 100644 arch/mips/mach-mt7620/Makefile
>>>> create mode 100644 arch/mips/mach-mt7620/cpu.c
>>>> create mode 100644 arch/mips/mach-mt7620/ddr_calibrate.c
>>>> create mode 100644 arch/mips/mach-mt7620/lowlevel_init.S
>>>> create mode 100644 arch/mips/mach-mt7620/mt76xx.h
>>>>
>>>> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
>>>> index 31b622ff51..af791c320d 100644
>>>> --- a/arch/mips/Kconfig
>>>> +++ b/arch/mips/Kconfig
>>>> @@ -87,6 +87,20 @@ config ARCH_BMIPS
>>>> select SYSRESET
>>>> imply CMD_DM
>>>>
>>>> +config ARCH_MT7620
>>>> + bool "Support MT7620/7688 SoCs"
>>>> + select SUPPORTS_LITTLE_ENDIAN
>>>> + select SUPPORTS_CPU_MIPS32_R1
>>>> + select SUPPORTS_CPU_MIPS32_R2
>>>> + select ROM_EXCEPTION_VECTORS
>>>> + select MIPS_TUNE_4KC
>>>
>>> MT7620 has a MIPS 24kc core, thus you could optimize for that
>>
>> Okay.
>>
>>>> + select OF_CONTROL
>>>> + select DM
>>>> + select DM_SERIAL
>>>> + select DM_SPI
>>>> + select DM_SPI_FLASH
>>>> + select DISPLAY_CPUINFO
>>>> +
>>>
>>> could you sort this in alphabetic order?
>>
>> Okay, will do in v2.
>>
>>> There were some patches recently
>>> which did the sorting tree wide. Also drop the SPI options until you add a
>>> SPI driver.
>>
>> The SPI driver is also on the list:
>>
>> http://patchwork.ozlabs.org/patch/954365/
>
> ok, I didn't received this one. But since SPI is not strictly
> required, you should prefer "imply" instead of a hard "select".
I've not seen an MT76xx board without SPI NOR flash, but this is
okay, I will turn this option into an "imply" instead in v2.
>>
>>>> config MACH_PIC32
>>>> bool "Support Microchip PIC32"
>>>> select DM
>>>> @@ -141,6 +155,7 @@ source "board/qemu-mips/Kconfig"
>>>> source "arch/mips/mach-ath79/Kconfig"
>>>> source "arch/mips/mach-bmips/Kconfig"
>>>> source "arch/mips/mach-pic32/Kconfig"
>>>> +source "arch/mips/mach-mt7620/Kconfig"
>>>>
>>>> if MIPS
>>>>
>>>> diff --git a/arch/mips/Makefile b/arch/mips/Makefile
>>>> index 5deec9a202..cc8ea5d7d4 100644
>>>> --- a/arch/mips/Makefile
>>>> +++ b/arch/mips/Makefile
>>>> @@ -15,6 +15,7 @@ machine-$(CONFIG_SOC_AU1X00) += au1x00
>>>> machine-$(CONFIG_ARCH_ATH79) += ath79
>>>> machine-$(CONFIG_ARCH_BMIPS) += bmips
>>>> machine-$(CONFIG_MACH_PIC32) += pic32
>>>> +machine-$(CONFIG_ARCH_MT7620) += mt7620
>>>>
>>>> machdirs := $(patsubst %,arch/mips/mach-%/,$(machine-y))
>>>> libs-y += $(machdirs)
>>>> diff --git a/arch/mips/mach-mt7620/Kconfig b/arch/mips/mach-mt7620/Kconfig
>>>> new file mode 100644
>>>> index 0000000000..40e15b8a31
>>>> --- /dev/null
>>>> +++ b/arch/mips/mach-mt7620/Kconfig
>>>> @@ -0,0 +1,130 @@
>>>> +menu "MediaTek MIPS platforms"
>>>> + depends on ARCH_MT7620
>>>> +
>>>> +config SYS_MALLOC_F_LEN
>>>> + default 0x1000
>>>> +
>>>> +config SYS_SOC
>>>> + default "mt7620" if SOC_MT7620
>>>> +
>>>> +choice
>>>> + prompt "MediaTek MIPS SoC select"
>>>> +
>>>> +config SOC_MT7620
>>>> + bool "MT7620/8"
>>>> + select MIPS_L1_CACHE_SHIFT_5
>>>> + help
>>>> + This supports MediaTek MIPS MT7620 family.
>>>> +
>>>> +endchoice
>>>> +
>>>> +choice
>>>> + prompt "Board select"
>>>> +
>>>> +config BOARD_LINKIT_SMART_7688
>>>> + bool "LinkIt Smart 7688"
>>>> + depends on SOC_MT7620
>>>> + select SUPPORTS_BOOT_RAM
>>>> + help
>>>> + Seeed LinkIt Smart 7688 boards have a MT7688 SoC with 128 MiB of RAM
>>>> + and 32 MiB of flash (SPI).
>>>> + Between its different peripherals there's an integrated switch with 4
>>>> + ethernet ports, 1 USB port, 1 UART, GPIO buttons and LEDs, and
>>>> + a MT7688 (PCIe).
>>>
>>> could you add this part with patch 3/4?
>>
>> Ah, yes. This slipped in too early.
>>
>>>> +
>>>> +endchoice
>>>> +
>>>> +choice
>>>> + prompt "Boot mode"
>>>> +
>>>> +config BOOT_RAM
>>>> + bool "RAM boot"
>>>> + depends on SUPPORTS_BOOT_RAM
>>>> + select SKIP_LOWLEVEL_INIT
>>>> + help
>>>> + This builds an image that is linked to a RAM address. It can be used
>>>> + for booting from CFE via TFTP using an ELF image, but it can also be
>>>> + booted from RAM by other bootloaders using a BIN image.
>>>> +
>>>> +config BOOT_ROM
>>>> + bool "ROM boot"
>>>> + depends on SUPPORTS_BOOT_RAM
>>>> + help
>>>> + This builds an image that is linked to a ROM address. It can be
>>>> + used as main bootloader image which is programmed onto the onboard
>>>> + flash storage (SPI NOR).
>>>> +
>>>> +endchoice
>>>> +
>>>> +choice
>>>> + prompt "DDR2 size"
>>>> +
>>>> +config ONBOARD_DDR2_SIZE_256MBIT
>>>> + bool "256MBit (32MByte) total size"
>>>> + depends on BOOT_ROM
>>>> + help
>>>> + Use 256MBit (32MByte) of DDR total size
>>>> +
>>>> +config ONBOARD_DDR2_SIZE_512MBIT
>>>> + bool "512MBit (64MByte) total size"
>>>> + depends on BOOT_ROM
>>>> + help
>>>> + Use 512MBit (64MByte) of DDR total size
>>>> +
>>>> +config ONBOARD_DDR2_SIZE_1024MBIT
>>>> + bool "1024MBit (128MByte) total size"
>>>> + depends on BOOT_ROM
>>>> + help
>>>> + Use 1024MBit (128MByte) of DDR total size
>>>> +
>>>> +config ONBOARD_DDR2_SIZE_2048MBIT
>>>> + bool "2048MBit (256MByte) total size"
>>>> + depends on BOOT_ROM
>>>> + help
>>>> + Use 2048MBit (256MByte) of DDR total size
>>>> +
>>>> +endchoice
>>>> +
>>>> +choice
>>>> + prompt "DDR2 chip width"
>>>> +
>>>> +config ONBOARD_DDR2_CHIP_WIDTH_8BIT
>>>> + bool "8bit DDR chip width"
>>>> + depends on BOOT_ROM
>>>> + help
>>>> + Use DDR chips with 8bit width
>>>> +
>>>> +config ONBOARD_DDR2_CHIP_WIDTH_16BIT
>>>> + bool "16bit DDR chip width"
>>>> + depends on BOOT_ROM
>>>> + help
>>>> + Use DDR chips with 16bit width
>>>> +
>>>> +endchoice
>>>> +
>>>> +choice
>>>> + prompt "DDR2 bus width"
>>>> +
>>>> +config ONBOARD_DDR2_BUS_WIDTH_16BIT
>>>> + bool "16bit DDR bus width"
>>>> + depends on BOOT_ROM
>>>> + help
>>>> + Use 16bit DDR bus width
>>>> +
>>>> +config ONBOARD_DDR2_BUS_WIDTH_32BIT
>>>> + bool "32bit DDR bus width"
>>>> + depends on BOOT_ROM
>>>> + help
>>>> + Use 32bit DDR bus width
>>>> +
>>>> +endchoice
>>>> +
>>>> +config SUPPORTS_BOOT_RAM
>>>> + bool
>>>> +
>>>> +config SKIP_LOWLEVEL_INIT
>>>> + bool
>>>
>>> this is a legacy config option, thus you have to define it in your
>>> board config header file.
>>> MIPS shouldn't add a Kconfig symbol for that. This have to be migrated
>>> to Kconfig tree-wide.
>>
>> Will move to config header for now.
>>
>>>> +
>>>> +source "board/seeed/linkit-smart-7688/Kconfig"
>>>
>>> could you add this part with patch 3/4?
>>
>> Sure.
>>
>>>> +
>>>> +endmenu
>>>> diff --git a/arch/mips/mach-mt7620/Makefile b/arch/mips/mach-mt7620/Makefile
>>>> new file mode 100644
>>>> index 0000000000..1f3e65e8a5
>>>> --- /dev/null
>>>> +++ b/arch/mips/mach-mt7620/Makefile
>>>> @@ -0,0 +1,8 @@
>>>> +# SPDX-License-Identifier: GPL-2.0+
>>>> +
>>>> +obj-y += cpu.o
>>>> +
>>>> +ifndef CONFIG_SKIP_LOWLEVEL_INIT
>>>> +obj-y += ddr_calibrate.o
>>>> +obj-y += lowlevel_init.o
>>>> +endif
>>>> diff --git a/arch/mips/mach-mt7620/cpu.c b/arch/mips/mach-mt7620/cpu.c
>>>> new file mode 100644
>>>> index 0000000000..0b22956499
>>>> --- /dev/null
>>>> +++ b/arch/mips/mach-mt7620/cpu.c
>>>> @@ -0,0 +1,66 @@
>>>> +// SPDX-License-Identifier: GPL-2.0+
>>>> +/*
>>>> + * Copyright (C) 2018 Stefan Roese <sr at denx.de>
>>>> + */
>>>> +
>>>> +#include <common.h>
>>>> +#include <dm.h>
>>>> +#include <ram.h>
>>>> +#include <asm/io.h>
>>>> +#include <linux/io.h>
>>>> +#include <linux/sizes.h>
>>>> +#include "mt76xx.h"
>>>> +
>>>> +#define STR_LEN 6
>>>> +
>>>> +#ifdef CONFIG_BOOT_ROM
>>>> +int mach_cpu_init(void)
>>>> +{
>>>> + void (*ptr)(void);
>>>> +
>>>> + /*
>>>> + * DDR calibration routine needs to be called very early. This
>>>> + * function also configures the clock to run at full speed.
>>>> + */
>>>> + ptr = (void *)CKSEG0ADDR(ddr_calibrate);
>>>> + (*ptr)();
>>>
>>> what is the purpose of forcing the function symbol to KSEG0?
>>
>> Its copied from the original MediaTek code. I just tested it without
>> forcing the execution into KSEG0 and the DDR calibration is extremely
>> slow then, taking a few minutes to complete.
>>
>> I have to admit that I am not 100% sure, if the caches are configured
>> 100% correctly / optimally for this SoC. Perhaps you (or someone else)
>> has some improvements here.
>
> I guess the BootROM does some XiP magic with the SPI flash controller
> and runs in the uncached KSEG1 segment.
> That would explain why the pre-relocation code runs so slowly. But
> this shift from KSEG1 to KSEG0 could be done
> generically in start.S after the cache initialization is complete. I
> will have a look at it.
That would be great. Please let me know if you need some help with
testing etc.
>>
>>>> +
>>>> + return 0;
>>>> +}
>>>> +#endif
>>>> +
>>>> +int print_cpuinfo(void)
>>>> +{
>>>> + static const char * const boot_str[] = { "PLL (3-Byte SPI Addr)",
>>>> + "PLL (4-Byte SPI Addr)",
>>>> + "XTAL (3-Byte SPI Addr)",
>>>> + "XTAL (4-Byte SPI Addr)" };
>>>> + char *chr = (char *)MT76XX_CHIPID;
>>>> + char buf[STR_LEN + 1];
>>>> + u32 val;
>>>> +
>>>> + snprintf(buf, STR_LEN + 1, "%s", chr);
>>>> + val = readl((void *)MT76XX_CHIP_REV_ID);
>>>> + printf("CPU: %-*s Rev %ld.%ld - ", STR_LEN, buf,
>>>> + (val & GENMASK(11, 8)) >> 8, val & GENMASK(3, 0));
>>>> +
>>>> + val = (readl((void *)MT76XX_SYSCFG0) & GENMASK(3, 1)) >> 1;
>>>> + printf("Boot from %s\n", boot_str[val]);
>>>
>>> could you try to create a CPU driver like on BMIPS?
>>
>> Do you really think this is necessary just for printing some SoC
>> information here?
>
> according to the datasheet those registers are in the memory space of
> the system controller block. Thus you should create at least a syscon
> driver. Also the device tree you're going to add references this
> syscon device.
Yes, this would be a plus, to get rid of the base address definition
in the header and use the DT here. I'll take a look...
>>
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +void _machine_restart(void)
>>>> +{
>>>> + writel(0x01, (void *)MT76XX_RSTCTL);
>>>> +
>>>> + while (1)
>>>> + ; /* NOP */
>>>
>>> could you try to create a reset controller driver? Then you could also
>>> use the generic syscon-reboot driver.
>>
>> Yes, I also thought about this. Will do in v2.
>>
>>>> +}
>>>> +
>>>> +int dram_init(void)
>>>> +{
>>>> + gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, SZ_256M);
>>>
>>> shouldn't you return the real configured DRAM size here?
>>
>> I always like using get_ram_size() as it automatically detects the
>> RAM size. This might be different (smaller) than the one configured,
>> if HW problems with the DDR interface exist.
>>
>> We might think about printing a warning, if the detected size does not
>> match the configured one.
>>
>>>> +
>>>> + return 0;
>>>> +}
>>>> diff --git a/arch/mips/mach-mt7620/ddr_calibrate.c b/arch/mips/mach-mt7620/ddr_calibrate.c
>>>> new file mode 100644
>>>> index 0000000000..6fd136674e
>>>> --- /dev/null
>>>> +++ b/arch/mips/mach-mt7620/ddr_calibrate.c
>>>> @@ -0,0 +1,331 @@
>>>> +// SPDX-License-Identifier: GPL-2.0+
>>>> +/*
>>>> + * Copyright (C) 2018 Stefan Roese <sr at denx.de>
>>>> + *
>>>> + * This code is mostly based on the code extracted from this MediaTek
>>>> + * github repository:
>>>> + *
>>>> + * https://github.com/MediaTek-Labs/linkit-smart-uboot.git
>>>> + *
>>>> + * I was not able to find a specific license or other developers
>>>> + * copyrights here, so I can't add them here.
>>>> + *
>>>> + * Most functions in this file are copied from the MediaTek U-Boot
>>>> + * repository. Without any documentation, it was impossible to really
>>>> + * implement this differently. So its mostly a cleaned-up version of
>>>> + * the original code, with only support for the MT7628 / MT7688 SoC.
>>>> + */
>>>> +
>>>> +#include <common.h>
>>>> +#include <linux/io.h>
>>>> +#include <asm/cacheops.h>
>>>> +#include <asm/io.h>
>>>> +#include "mt76xx.h"
>>>> +
>>>> +#define NUM_OF_CACHELINE 64
>>>> +#define MIN_START 6
>>>> +#define MIN_FINE_START 0xf
>>>> +#define MAX_START 7
>>>> +#define MAX_FINE_START 0x0
>>>> +
>>>> +#define CPU_FRAC_DIV 1
>>>> +
>>>> +#if defined(CONFIG_ONBOARD_DDR2_SIZE_256MBIT)
>>>> +#define DRAM_BUTTOM 0x02000000
>>>> +#endif
>>>> +#if defined(CONFIG_ONBOARD_DDR2_SIZE_512MBIT)
>>>> +#define DRAM_BUTTOM 0x04000000
>>>> +#endif
>>>> +#if defined(CONFIG_ONBOARD_DDR2_SIZE_1024MBIT)
>>>> +#define DRAM_BUTTOM 0x08000000
>>>> +#endif
>>>> +#if defined(CONFIG_ONBOARD_DDR2_SIZE_2048MBIT)
>>>> +#define DRAM_BUTTOM 0x10000000
>>>> +#endif
>>>> +
>>>> +static inline void cal_memcpy(void *src, void *dst, u32 size)
>>>> +{
>>>> + u8 *psrc = (u8 *)src;
>>>> + u8 *pdst = (u8 *)dst;
>>>> + int i;
>>>> +
>>>> + for (i = 0; i < size; i++, psrc++, pdst++)
>>>> + *pdst = *psrc;
>>>> +}
>>>> +
>>>> +static inline void cal_memset(void *src, u8 pat, u32 size)
>>>> +{
>>>> + u8 *psrc = (u8 *)src;
>>>> + int i;
>>>> +
>>>> + for (i = 0; i < size; i++, psrc++)
>>>> + *psrc = pat;
>>>> +}
>>>> +
>>>> +#define pref_op(hint, addr) \
>>>> + __asm__ __volatile__( \
>>>> + ".set push\n" \
>>>> + ".set noreorder\n" \
>>>> + "pref %0, %1\n" \
>>>> + ".set pop\n" \
>>>> + : \
>>>> + : "i" (hint), "R" (*(u8 *)(addr)))
>>>> +
>>>> +#define cache_op(op, addr) \
>>>> + __asm__ __volatile__( \
>>>> + ".set push\n" \
>>>> + ".set noreorder\n" \
>>>> + ".set mips3\n" \
>>>> + "cache %0, %1\n" \
>>>> + ".set pop\n" \
>>>> + : \
>>>> + : "i" (op), "R" (*(u8 *)(addr)))
>>>
>>> cache_op() is already available in arch/mips/include/asm/cacheops.h.
>>
>> Hmm, Where exactly?
>
> sorry, I meant mips_cache()
Not needed anymore when moved to using the generic invalidate
dcache function.
>>
>>> Maybe you could add pref_op in the same way to that file.
>>
>> Could make sense, but please see above. Again, I'm still pretty new to
>> MIPS and especially the caches.
>
> I noticed prefetch() is already defined in
> arch/mips/include/asm/processor.h. You could utilize it if you add a
> boolean Kconfig option CONFIG_CPU_HAS_PREFETCH in arch/mips/Kconfig
> and select it for MT7620.
Yes. But which implementation is the correct one for this SoC?
#define PREF(hint, addr) \
.set push; \
.set arch=r5000; \
pref hint, addr; \
.set pop
#define PREFE(hint, addr) \
.set push; \
.set mips0; \
.set eva; \
prefe hint, addr; \
.set pop
#define PREFX(hint, addr) \
.set push; \
.set arch=r5000; \
prefx hint, addr; \
.set pop
Thanks,
Stefan
More information about the U-Boot
mailing list