Prepare v2022.04-rc4

-----BEGIN PGP SIGNATURE-----
 
 iQGzBAABCgAdFiEEGjx/cOCPqxcHgJu/FHw5/5Y0tywFAmIvp/8ACgkQFHw5/5Y0
 tyyI6wwApR++p9BBlWEZn1B5sivCXcs9oCX3Vs8vegpiiRbs/pGsyKV6pfEHHYV5
 lhw1YNZ0accKmqBmX19tdpQ2ZzHq3+g0eGJL8xioXU3hRoZZNsDewAF8KS+aHPpk
 qMuA+xbDi08I6z2qtrIpaDd//DO2jAkFF+/TKOzSgUSxBaomQiziZaB2x28bIBH2
 zsLMP4vzZ03uCSZVSd7HMBz0qiGhioJo5Ch2eU4TTJW19CXeMTAuav6SDq+6vJGi
 cIUe31YEe742jOVmtf2RuJQ+mDjsEfT11wvRajcbOlH/Ho7E5iFxQkmOEThpvybE
 YD5d5uLLpQj42PfBpSvx4nMJcvyOmqxdizUJxCgi/q5HrhdzcO6LwLLON0T4W4zG
 Vsue+iTjOKXgLdD8g/VogL38iHxhpfY7zsFB98vvHcoLwhEXvfvhO8Dj/lwLw4Ic
 88B6uz3TqAPNqSnTWphJPCwG8STwyqlvLXwTF+eICbtQW3uuHEtnmlsXQJeFmdUa
 fGK8dUfr
 =wyE5
 -----END PGP SIGNATURE-----

Merge tag 'v2022.04-rc4' into next

Prepare v2022.04-rc4
This commit is contained in:
Tom Rini 2022-03-14 17:40:36 -04:00
commit 2abf048ab7
95 changed files with 2240 additions and 584 deletions

View File

@ -22,11 +22,13 @@ Andreas Bießmann <andreas@biessmann.org>
Aneesh V <aneesh@ti.com>
Anup Patel <anup@brainfault.org> <anup.patel@wdc.com>
Atish Patra <atishp@atishpatra.org> <atish.patra@wdc.com>
Bin Meng <bmeng.cn@gmail.com> <bin.meng@windriver.com>
Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@bootlin.com>
Boris Brezillon <bbrezillon@kernel.org> <boris.brezillon@free-electrons.com>
Dirk Behme <dirk.behme@googlemail.com>
Fabio Estevam <fabio.estevam@nxp.com>
Heinrich Schuchardt <xypron.glpk@gmx.de> <heinrich.schuchardt@canonical.com>
Heinrich Schuchardt <xypron.glpk@gmx.de> xypron.glpk@gmx.de <xypron.glpk@gmx.de>
Jagan Teki <402jagan@gmail.com>
Jagan Teki <jaganna@gmail.com>
Jagan Teki <jaganna@xilinx.com>
@ -35,7 +37,15 @@ Jagan Teki <jagannadha.sutradharudu-teki@xilinx.com>
Jernej Skrabec <jernej.skrabec@gmail.com> <jernej.skrabec@siol.net>
Igor Opaniuk <igor.opaniuk@gmail.com> <igor.opaniuk@linaro.org>
Igor Opaniuk <igor.opaniuk@gmail.com> <igor.opaniuk@toradex.com>
Marek Vasut <marex@denx.de> <marek.vasut+renesas@gmail.com>
Marek Vasut <marex@denx.de> <marek.vasut@gmail.com>
Marek Vasut <marex@denx.de> <marex at denx.de>
Markus Klotzbuecher <mk@denx.de>
Masahiro Yamada <yamada.masahiro@socionext.com> <yamada.m@jp.panasonic.com>
Masahiro Yamada <yamada.masahiro@socionext.com> <masahiroy@kernel.org>
Michal Simek <michal.simek@xilinx.com> <monstr@monstr.eu>
Michal Simek <michal.simek@xilinx.com> <Monstr@seznam.cz>
Michal Simek <michal.simek@xilinx.com> <root@monstr.eu>
Nicolas Saenz Julienne <nsaenz@kernel.org> <nsaenzjulienne@suse.de>
Patrice Chotard <patrice.chotard@foss.st.com> <patrice.chotard@st.com>
Patrick Delaunay <patrick.delaunay@foss.st.com> <patrick.delaunay@st.com>
@ -47,10 +57,19 @@ Ricardo Ribalda <ricardo@ribalda.com> <ricardo.ribalda@gmail.com>
Ruchika Gupta <ruchika.gupta@nxp.com> <ruchika.gupta@freescale.com>
Sandeep Paulraj <s-paulraj@ti.com>
Shaohui Xie <Shaohui.Xie@freescale.com>
Stefan Roese <stroese>
Stefan Roese <sr@denx.de> <stroese>
Stefano Babic <sbabic@denx.de>
Tom Rini <trini@konsulko.com> <trini@ti.com>
TsiChung Liew <Tsi-Chung.Liew@freescale.com>
Wolfgang Denk <wdenk>
Wolfgang Denk <wd@denx.de> <wdenk>
Wolfgang Denk <wd@denx.de> <wd@pollux.denx.de>
Wolfgang Denk <wd@denx.de> <wd@pollux.(none)>
Wolfgang Denk <wd@denx.de> <wd@fifi.denx.de>
Wolfgang Denk <wd@denx.de> <wd@nyx.denx.de>
Wolfgang Denk <wd@denx.de> <wd@atlas.denx.de>
Wolfgang Denk <wd@denx.de> <wd@castor.denx.de>
Wolfgang Denk <wd@denx.de> <wd@xpert.denx.de>
Wolfgang Denk <wd@denx.de> <wd@nyx.(none)>
York Sun <yorksun@freescale.com>
York Sun <york.sun@nxp.com>
Łukasz Majewski <l.majewski@samsung.com>

View File

@ -1171,6 +1171,13 @@ S: Maintained
T: git https://source.denx.de/u-boot/custodians/u-boot-sh.git
F: arch/sh/
SL28CLPD
M: Michael Walle <michael@walle.cc>
S: Maintained
F: drivers/gpio/sl28cpld-gpio.c
F: drivers/misc/sl28cpld.c
F: drivers/watchdog/sl28cpld-wdt.c
SPI
M: Jagan Teki <jagan@amarulasolutions.com>
S: Maintained
@ -1329,6 +1336,14 @@ F: include/virtio*.h
F: test/dm/virtio.c
F: doc/develop/driver-model/virtio.rst
WATCHDOG
M: Stefan Roese <sr@denx.de>
S: Maintained
T: git https://source.denx.de/u-boot/custodians/u-boot-watchdog.git
F: cmd/wdt.c
F: drivers/watchdog/
F: include/watchdog*.h
X86
M: Simon Glass <sjg@chromium.org>
M: Bin Meng <bmeng.cn@gmail.com>

View File

@ -3,7 +3,7 @@
VERSION = 2022
PATCHLEVEL = 04
SUBLEVEL =
EXTRAVERSION = -rc3
EXTRAVERSION = -rc4
NAME =
# *DOCUMENTATION*
@ -1412,7 +1412,7 @@ MKIMAGEFLAGS_u-boot-spl.kwb = -n $(KWD_CONFIG_FILE) \
$(if $(KEYDIR),-k $(KEYDIR))
MKIMAGEFLAGS_u-boot.pbl = -n $(srctree)/$(CONFIG_SYS_FSL_PBL_RCW:"%"=%) \
-R $(srctree)/$(CONFIG_SYS_FSL_PBL_PBI:"%"=%) -T pblimage
-R $(srctree)/$(CONFIG_SYS_FSL_PBL_PBI:"%"=%) -A $(ARCH) -T pblimage
ifeq ($(CONFIG_MPC85xx)$(CONFIG_OF_SEPARATE),yy)
UBOOT_BIN := u-boot-with-dtb.bin

View File

@ -1075,6 +1075,8 @@ config ARCH_SUNXI
select DM_ETH
select DM_GPIO
select DM_I2C if I2C
select DM_SPI if SPI
select DM_SPI_FLASH if SPI
select DM_KEYBOARD
select DM_MMC if MMC
select DM_SCSI if SCSI

View File

@ -25,9 +25,9 @@ ENTRY(return_to_fel)
mov sp, r0
mov lr, r1
ldr r0, =fel_stash
ldr r1, [r0, #16]
mcr p15, 0, r1, c1, c0, 0 @ Write CP15 Control Register
ldr r1, [r0, #12]
mcr p15, 0, r1, c1, c0, 0 @ Write CP15 SCTLR register
ldr r1, [r0, #8]
msr cpsr, r1 @ Write CPSR
bx lr
ENDPROC(return_to_fel)

View File

@ -139,7 +139,9 @@
/*
* U-Boot port for Turris Mox has a bug which always expects that "ranges" DT property
* contains exactly 2 ranges with 3 (child) address cells, 2 (parent) address cells and
* 2 size cells and also expects that the second range starts at 16 MB offset. If these
* 2 size cells and also expects that the second range starts at 16 MB offset. Also it
* expects that first range uses same address for PCI (child) and CPU (parent) cells (so
* no remapping) and that this address is the lowest from all specified ranges. If these
* conditions are not met then U-Boot crashes during loading kernel DTB file. PCIe address
* space is 128 MB long, so the best split between MEM and IO is to use fixed 16 MB window
* for IO and the rest 112 MB (64+32+16) for MEM. Controller supports 32-bit IO mapping.
@ -148,6 +150,9 @@
* https://source.denx.de/u-boot/u-boot/-/commit/cb2ddb291ee6fcbddd6d8f4ff49089dfe580f5d7
* https://source.denx.de/u-boot/u-boot/-/commit/c64ac3b3185aeb3846297ad7391fc6df8ecd73bf
* https://source.denx.de/u-boot/u-boot/-/commit/4a82fca8e330157081fc132a591ebd99ba02ee33
* Bug related to requirement of same child and parent addresses for first range is fixed
* in U-Boot version 2022.04 by following commit:
* https://source.denx.de/u-boot/u-boot/-/commit/1fd54253bca7d43d046bba4853fe5fafd034bc17
*/
#address-cells = <3>;
#size-cells = <2>;

View File

@ -499,7 +499,7 @@
* (totaling 127 MiB) for MEM.
*/
ranges = <0x82000000 0 0xe8000000 0 0xe8000000 0 0x07f00000 /* Port 0 MEM */
0x81000000 0 0xeff00000 0 0xeff00000 0 0x00100000>; /* Port 0 IO*/
0x81000000 0 0x00000000 0 0xeff00000 0 0x00100000>; /* Port 0 IO */
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &pcie_intc 0>,
<0 0 0 2 &pcie_intc 1>,

View File

@ -27,6 +27,7 @@
fit {
offset = <CONFIG_SPL_PAD_TO>;
description = "FIT image with multiple configurations";
fit,fdt-list = "of-list";
images {
uboot {
@ -41,95 +42,20 @@
};
};
fdt-1 {
description = "fsl-ls1028a-kontron-sl28";
@fdt-SEQ {
description = "NAME";
type = "flat_dt";
arch = "arm";
compression = "none";
blob {
filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28.dtb";
};
};
fdt-2 {
description = "fsl-ls1028a-kontron-sl28-var1";
type = "flat_dt";
arch = "arm";
compression = "none";
blob {
filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28-var1.dtb";
};
};
fdt-3 {
description = "fsl-ls1028a-kontron-sl28-var2";
type = "flat_dt";
arch = "arm";
compression = "none";
blob {
filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28-var2.dtb";
};
};
fdt-4 {
description = "fsl-ls1028a-kontron-sl28-var3";
type = "flat_dt";
arch = "arm";
compression = "none";
blob {
filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28-var3.dtb";
};
};
fdt-5 {
description = "fsl-ls1028a-kontron-sl28-var4";
type = "flat_dt";
arch = "arm";
compression = "none";
blob {
filename = "arch/arm/dts/fsl-ls1028a-kontron-sl28-var4.dtb";
};
};
};
configurations {
default = "conf-1";
default = "@config-DEFAULT-SEQ";
conf-1 {
description = "fsl-ls1028a-kontron-sl28";
@config-SEQ {
description = "NAME";
firmware = "uboot";
fdt = "fdt-1";
};
conf-2 {
description = "fsl-ls1028a-kontron-sl28-var1";
firmware = "uboot";
fdt = "fdt-2";
};
conf-3 {
description = "fsl-ls1028a-kontron-sl28-var2";
firmware = "uboot";
fdt = "fdt-3";
};
conf-4 {
description = "fsl-ls1028a-kontron-sl28-var3";
firmware = "uboot";
loadables = "uboot";
fdt = "fdt-4";
};
conf-5 {
description = "fsl-ls1028a-kontron-sl28-var4";
firmware = "uboot";
loadables = "uboot";
fdt = "fdt-5";
fdt = "fdt-SEQ";
};
};
};
@ -189,27 +115,7 @@
};
configurations {
conf-1 {
firmware = "bl31";
loadables = "uboot";
};
conf-2 {
firmware = "bl31";
loadables = "uboot";
};
conf-3 {
firmware = "bl31";
loadables = "uboot";
};
conf-4 {
firmware = "bl31";
loadables = "uboot";
};
conf-5 {
@config-SEQ {
firmware = "bl31";
loadables = "uboot";
};
@ -238,23 +144,7 @@
};
configurations {
conf-1 {
loadables = "uboot", "bl32";
};
conf-2 {
loadables = "uboot", "bl32";
};
conf-3 {
loadables = "uboot", "bl32";
};
conf-4 {
loadables = "uboot", "bl32";
};
conf-5 {
@config-SEQ {
loadables = "uboot", "bl32";
};
};

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) Siemens AG, 2018-2021
* Copyright (c) Siemens AG, 2018-2022
*
* Authors:
* Le Jin <le.jin@siemens.com>
@ -27,6 +27,29 @@
&cbass_mcu {
u-boot,dm-spl;
mcu_navss: bus@28380000 {
ringacc@2b800000 {
reg = <0x0 0x2b800000 0x0 0x400000>,
<0x0 0x2b000000 0x0 0x400000>,
<0x0 0x28590000 0x0 0x100>,
<0x0 0x2a500000 0x0 0x40000>,
<0x0 0x28440000 0x0 0x40000>;
reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target", "cfg";
ti,dma-ring-reset-quirk;
};
dma-controller@285c0000 {
reg = <0x0 0x285c0000 0x0 0x100>,
<0x0 0x284c0000 0x0 0x4000>,
<0x0 0x2a800000 0x0 0x40000>,
<0x0 0x284a0000 0x0 0x4000>,
<0x0 0x2aa00000 0x0 0x40000>,
<0x0 0x28400000 0x0 0x2000>;
reg-names = "gcfg", "rchan", "rchanrt", "tchan",
"tchanrt", "rflow";
};
};
};
&cbass_wakeup {

View File

@ -125,7 +125,9 @@
#address-cells = <1>;
#size-cells = <0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gmac0_default &pinctrl_gmac0_txc_default>;
pinctrl-0 = <&pinctrl_gmac0_default
&pinctrl_gmac0_mdio_default
&pinctrl_gmac0_txc_default>;
phy-mode = "rgmii-id";
status = "okay";
@ -138,7 +140,7 @@
#address-cells = <1>;
#size-cells = <0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gmac1_default>;
pinctrl-0 = <&pinctrl_gmac1_default &pinctrl_gmac1_mdio_default>;
phy-mode = "rmii";
status = "okay";
@ -235,14 +237,20 @@
<PIN_PA15__G0_TXEN>,
<PIN_PA30__G0_RXCK>,
<PIN_PA18__G0_RXDV>,
<PIN_PA22__G0_MDC>,
<PIN_PA23__G0_MDIO>,
<PIN_PA25__G0_125CK>;
slew-rate = <0>;
bias-disable;
};
pinctrl_gmac0_mdio_default: gmac0_mdio_default {
pinmux = <PIN_PA22__G0_MDC>,
<PIN_PA23__G0_MDIO>;
bias-disable;
};
pinctrl_gmac0_txc_default: gmac0_txc_default {
pinmux = <PIN_PA24__G0_TXCK>;
slew-rate = <0>;
bias-pull-up;
};
@ -254,8 +262,13 @@
<PIN_PD25__G1_RX0>,
<PIN_PD26__G1_RX1>,
<PIN_PD27__G1_RXER>,
<PIN_PD24__G1_RXDV>,
<PIN_PD28__G1_MDC>,
<PIN_PD24__G1_RXDV>;
slew-rate = <0>;
bias-disable;
};
pinctrl_gmac1_mdio_default: gmac1_mdio_default {
pinmux = <PIN_PD28__G1_MDC>,
<PIN_PD29__G1_MDIO>;
bias-disable;
};

View File

@ -160,6 +160,7 @@ enum sunxi_gpio_number {
#define SUNXI_GPC_SDC2 3
#define SUN6I_GPC_SDC3 4
#define SUN50I_GPC_SPI0 4
#define SUNIV_GPC_SPI0 2
#define SUNXI_GPD_LCD0 2
#define SUNXI_GPD_LVDS0 3

View File

@ -19,6 +19,15 @@
#define SUNXI_BOOTED_FROM_MMC0_HIGH 0x10
#define SUNXI_BOOTED_FROM_MMC2_HIGH 0x12
/*
* Values taken from the F1C200s BootROM stack
* to determine where we booted from.
*/
#define SUNIV_BOOTED_FROM_MMC0 0xffff40f8
#define SUNIV_BOOTED_FROM_NAND 0xffff4114
#define SUNIV_BOOTED_FROM_SPI 0xffff4130
#define SUNIV_BOOTED_FROM_MMC1 0xffff4150
#define is_boot0_magic(addr) (memcmp((void *)(addr), BOOT0_MAGIC, 8) == 0)
uint32_t sunxi_get_boot_device(void);

View File

@ -251,7 +251,8 @@ void board_init_f(ulong dummy)
k3_sysfw_print_ver();
/* Perform EEPROM-based board detection */
do_board_detect();
if (IS_ENABLED(CONFIG_TI_I2C_BOARD_DETECT))
do_board_detect();
#if defined(CONFIG_CPU_V7R) && defined(CONFIG_K3_AVS0)
ret = uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(k3_avs),

View File

@ -316,8 +316,8 @@ static int fdt_setprop_inplace_u32_partial(void *blob, int node,
int a3700_fdt_fix_pcie_regions(void *blob)
{
int acells, pacells, scells;
u32 base, fix_offset;
u32 base, lowest_cpu_addr, fix_offset;
int pci_cells, cpu_cells, size_cells;
const u32 *ranges;
int node, pnode;
int ret, i, len;
@ -331,51 +331,80 @@ int a3700_fdt_fix_pcie_regions(void *blob)
return node;
ranges = fdt_getprop(blob, node, "ranges", &len);
if (!ranges || len % sizeof(u32))
return -ENOENT;
if (!ranges || !len || len % sizeof(u32))
return -EINVAL;
/*
* The "ranges" property is an array of
* { <child address> <parent address> <size in child address space> }
* { <PCI address> <CPU address> <size in PCI address space> }
* where number of PCI address cells and size cells is stored in the
* "#address-cells" and "#size-cells" properties of the same node
* containing the "ranges" property and number of CPU address cells
* is stored in the parent's "#address-cells" property.
*
* All 3 elements can span a diffent number of cells. Fetch their sizes.
* All 3 elements can span a diffent number of cells. Fetch them.
*/
pnode = fdt_parent_offset(blob, node);
acells = fdt_address_cells(blob, node);
pacells = fdt_address_cells(blob, pnode);
scells = fdt_size_cells(blob, node);
pci_cells = fdt_address_cells(blob, node);
cpu_cells = fdt_address_cells(blob, pnode);
size_cells = fdt_size_cells(blob, node);
/* Child PCI addresses always use 3 cells */
if (acells != 3)
return -ENOENT;
/* PCI addresses always use 3 cells */
if (pci_cells != 3)
return -EINVAL;
/* Calculate fixup offset from first child address (in last cell) */
fix_offset = base - fdt32_to_cpu(ranges[2]);
/* CPU addresses on Armada 37xx always use 2 cells */
if (cpu_cells != 2)
return -EINVAL;
/* If fixup offset is zero then there is nothing to fix */
for (i = 0; i < len / sizeof(u32);
i += pci_cells + cpu_cells + size_cells) {
/*
* Parent CPU addresses on Armada 37xx are always 32-bit, so
* check that the high word is zero.
*/
if (fdt32_to_cpu(ranges[i + pci_cells]))
return -EINVAL;
if (i == 0 ||
fdt32_to_cpu(ranges[i + pci_cells + 1]) < lowest_cpu_addr)
lowest_cpu_addr = fdt32_to_cpu(ranges[i + pci_cells + 1]);
}
/* Calculate fixup offset from the lowest (first) CPU address */
fix_offset = base - lowest_cpu_addr;
/* If fixup offset is zero there is nothing to fix */
if (!fix_offset)
return 0;
/*
* Fix address (last cell) of each child address and each parent
* address
* Fix each CPU address and corresponding PCI address if PCI address
* is not already remapped (has the same value)
*/
for (i = 0; i < len / sizeof(u32); i += acells + pacells + scells) {
for (i = 0; i < len / sizeof(u32);
i += pci_cells + cpu_cells + size_cells) {
u32 cpu_addr;
u64 pci_addr;
int idx;
/* fix child address */
idx = i + acells - 1;
/* Fix CPU address */
idx = i + pci_cells + cpu_cells - 1;
cpu_addr = fdt32_to_cpu(ranges[idx]);
ret = fdt_setprop_inplace_u32_partial(blob, node, "ranges", idx,
fdt32_to_cpu(ranges[idx]) +
fix_offset);
cpu_addr + fix_offset);
if (ret)
return ret;
/* fix parent address */
idx = i + acells + pacells - 1;
/* Fix PCI address only if it isn't remapped (is same as CPU) */
idx = i + pci_cells - 1;
pci_addr = ((u64)fdt32_to_cpu(ranges[idx - 1]) << 32) |
fdt32_to_cpu(ranges[idx]);
if (cpu_addr != pci_addr)
continue;
ret = fdt_setprop_inplace_u32_partial(blob, node, "ranges", idx,
fdt32_to_cpu(ranges[idx]) +
fix_offset);
cpu_addr + fix_offset);
if (ret)
return ret;
}

View File

@ -332,9 +332,6 @@ config MACH_SUN9I
config MACH_SUN50I
bool "sun50i (Allwinner A64)"
select ARM64
select SPI
select DM_SPI if SPI
select DM_SPI_FLASH
select PHY_SUN4I_USB
select SUN6I_PRCM
select SUNXI_DE2
@ -1038,7 +1035,7 @@ config SPL_STACK_R_ADDR
config SPL_SPI_SUNXI
bool "Support for SPI Flash on Allwinner SoCs in SPL"
depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUNXI_H3_H5 || MACH_SUN50I || MACH_SUN8I_R40 || MACH_SUN50I_H6
depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUNXI_H3_H5 || MACH_SUN50I || MACH_SUN8I_R40 || MACH_SUN50I_H6 || MACH_SUNIV
help
Enable support for SPI Flash. This option allows SPL to read from
sunxi SPI Flash. It uses the same method as the boot ROM, so does

View File

@ -191,12 +191,48 @@ SPL_LOAD_IMAGE_METHOD("FEL", 0, BOOT_DEVICE_BOARD, spl_board_load_image);
#define SUNXI_INVALID_BOOT_SOURCE -1
static int suniv_get_boot_source(void)
{
/* Get the last function call from BootROM's stack. */
u32 brom_call = *(u32 *)(uintptr_t)(fel_stash.sp - 4);
/* translate SUNIV BootROM stack to standard SUNXI boot sources */
switch (brom_call) {
case SUNIV_BOOTED_FROM_MMC0:
return SUNXI_BOOTED_FROM_MMC0;
case SUNIV_BOOTED_FROM_SPI:
return SUNXI_BOOTED_FROM_SPI;
case SUNIV_BOOTED_FROM_MMC1:
return SUNXI_BOOTED_FROM_MMC2;
/* SPI NAND is not supported yet. */
case SUNIV_BOOTED_FROM_NAND:
return SUNXI_INVALID_BOOT_SOURCE;
}
/* If we get here something went wrong try to boot from FEL.*/
printf("Unknown boot source from BROM: 0x%x\n", brom_call);
return SUNXI_INVALID_BOOT_SOURCE;
}
static int sunxi_get_boot_source(void)
{
/*
* On the ARMv5 SoCs, the SPL header in SRAM is overwritten by the
* exception vectors in U-Boot proper, so we won't find any
* information there. Also the FEL stash is only valid in the SPL,
* so we can't use that either. So if this is called from U-Boot
* proper, just return MMC0 as a placeholder, for now.
*/
if (IS_ENABLED(CONFIG_MACH_SUNIV) &&
!IS_ENABLED(CONFIG_SPL_BUILD))
return SUNXI_BOOTED_FROM_MMC0;
if (!is_boot0_magic(SPL_ADDR + 4)) /* eGON.BT0 */
return SUNXI_INVALID_BOOT_SOURCE;
return readb(SPL_ADDR + 0x28);
if (IS_ENABLED(CONFIG_MACH_SUNIV))
return suniv_get_boot_source();
else
return readb(SPL_ADDR + 0x28);
}
/* The sunxi internal brom will try to loader external bootloader
@ -276,36 +312,10 @@ unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc,
return sector;
}
#ifdef CONFIG_MACH_SUNIV
/*
* The suniv BROM does not pass the boot media type to SPL, so we try with the
* boot sequence in BROM: mmc0->spinor->fail.
* TODO: This has the slight chance of being wrong (invalid SPL signature,
* but valid U-Boot legacy image on the SD card), but this should be rare.
* It looks like we can deduce from some BROM state upon entering the SPL
* (registers, SP, or stack itself) where the BROM was coming from and use
* that here.
*/
void board_boot_order(u32 *spl_boot_list)
{
/*
* See the comments above in sunxi_get_boot_device() for information
* about FEL boot.
*/
if (!is_boot0_magic(SPL_ADDR + 4)) {
spl_boot_list[0] = BOOT_DEVICE_BOARD;
return;
}
spl_boot_list[0] = BOOT_DEVICE_MMC1;
spl_boot_list[1] = BOOT_DEVICE_SPI;
}
#else
u32 spl_boot_device(void)
{
return sunxi_get_boot_device();
}
#endif
__weak void sunxi_sram_init(void)
{

View File

@ -90,6 +90,7 @@
#define SPI0_CLK_DIV_BY_2 0x1000
#define SPI0_CLK_DIV_BY_4 0x1001
#define SPI0_CLK_DIV_BY_32 0x100f
/*****************************************************************************/
@ -132,7 +133,8 @@ static uintptr_t spi0_base_address(void)
if (IS_ENABLED(CONFIG_MACH_SUN50I_H6))
return 0x05010000;
if (!is_sun6i_gen_spi())
if (!is_sun6i_gen_spi() ||
IS_ENABLED(CONFIG_MACH_SUNIV))
return 0x01C05000;
return 0x01C68000;
@ -156,11 +158,16 @@ static void spi0_enable_clock(void)
if (!IS_ENABLED(CONFIG_MACH_SUN50I_H6))
setbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
/* Divide by 4 */
writel(SPI0_CLK_DIV_BY_4, base + (is_sun6i_gen_spi() ?
SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL));
/* 24MHz from OSC24M */
writel((1 << 31), CCM_SPI0_CLK);
if (IS_ENABLED(CONFIG_MACH_SUNIV)) {
/* Divide by 32, clock source is AHB clock 200MHz */
writel(SPI0_CLK_DIV_BY_32, base + SUN6I_SPI0_CCTL);
} else {
/* Divide by 4 */
writel(SPI0_CLK_DIV_BY_4, base + (is_sun6i_gen_spi() ?
SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL));
/* 24MHz from OSC24M */
writel((1 << 31), CCM_SPI0_CLK);
}
if (is_sun6i_gen_spi()) {
/* Enable SPI in the master mode and do a soft reset */
@ -191,7 +198,8 @@ static void spi0_disable_clock(void)
SUN4I_CTL_ENABLE);
/* Disable the SPI0 clock */
writel(0, CCM_SPI0_CLK);
if (!IS_ENABLED(CONFIG_MACH_SUNIV))
writel(0, CCM_SPI0_CLK);
/* Close the SPI0 gate */
if (!IS_ENABLED(CONFIG_MACH_SUN50I_H6))
@ -212,6 +220,8 @@ static void spi0_init(void)
if (IS_ENABLED(CONFIG_MACH_SUN50I) ||
IS_ENABLED(CONFIG_MACH_SUN50I_H6))
pin_function = SUN50I_GPC_SPI0;
else if (IS_ENABLED(CONFIG_MACH_SUNIV))
pin_function = SUNIV_GPC_SPI0;
spi0_pinmux_setup(pin_function);
spi0_enable_clock();

View File

@ -47,7 +47,13 @@ enum {
BINF_RW_B = 2
};
enum {
/**
* enum cros_fw_type_t - Used to indicate Chromium OS firmware type
*
* Chromium OS uses a region of the GNVS starting at offset 0x100 to store
* various bits of information, including the type of firmware being booted
*/
enum cros_fw_type_t {
FIRMWARE_TYPE_AUTO_DETECT = -1,
FIRMWARE_TYPE_RECOVERY = 0,
FIRMWARE_TYPE_NORMAL = 1,

View File

@ -1,3 +1,3 @@
dsdt.aml
dsdt.asl.tmp
dsdt.c
dsdt_generated.aml
dsdt_generated.asl.tmp
dsdt_generated.c

View File

@ -73,6 +73,7 @@ static struct mv_ddr_topology_map board_topology_map = {
{0}, /* timing parameters */
{ {0} }, /* electrical configuration */
{0}, /* electrical parameters */
0, /* ODT configuration */
0, /* Clock enable mask */
160 /* Clock delay */
};

View File

@ -1,3 +1,3 @@
dsdt.aml
dsdt.asl.tmp
dsdt.c
dsdt_generated.aml
dsdt_generated.asl.tmp
dsdt_generated.c

View File

@ -2,12 +2,12 @@ COREBOOT BOARD
M: Simon Glass <sjg@chromium.org>
S: Maintained
F: board/coreboot/coreboot/
F: include/configs/chromebook_link.h
F: include/configs/coreboot.h
F: configs/coreboot_defconfig
COREBOOT64 BOARD
M: Simon Glass <sjg@chromium.org>
S: Maintained
F: board/coreboot/coreboot/
F: include/configs/chromebook_link.h
F: include/configs/coreboot.h
F: configs/coreboot64_defconfig

View File

@ -1,3 +1,3 @@
dsdt.aml
dsdt.asl.tmp
dsdt.c
dsdt_generated.aml
dsdt_generated.asl.tmp
dsdt_generated.c

View File

@ -1,3 +1,3 @@
dsdt.aml
dsdt.asl.tmp
dsdt.c
dsdt_generated.aml
dsdt_generated.asl.tmp
dsdt_generated.c

View File

@ -1,3 +1,3 @@
dsdt.aml
dsdt.asl.tmp
dsdt.c
dsdt_generated.aml
dsdt_generated.asl.tmp
dsdt_generated.c

View File

@ -1,3 +1,3 @@
dsdt.aml
dsdt.asl.tmp
dsdt.c
dsdt_generated.aml
dsdt_generated.asl.tmp
dsdt_generated.c

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
#include <common.h>
#include <dm.h>
#include <malloc.h>
#include <errno.h>
#include <fsl_ddr.h>
@ -14,7 +15,9 @@
#include <asm/arch/soc.h>
#include <fsl_immap.h>
#include <netdev.h>
#include <wdt.h>
#include <sl28cpld.h>
#include <fdtdec.h>
#include <miiphy.h>
@ -39,16 +42,68 @@ int board_eth_init(struct bd_info *bis)
return pci_eth_init(bis);
}
static int __sl28cpld_read(uint reg)
{
struct udevice *dev;
int ret;
ret = uclass_get_device_by_driver(UCLASS_NOP,
DM_DRIVER_GET(sl28cpld), &dev);
if (ret)
return ret;
return sl28cpld_read(dev, reg);
}
static void print_cpld_version(void)
{
int version = __sl28cpld_read(SL28CPLD_VERSION);
if (version < 0)
printf("CPLD: error reading version (%d)\n", version);
else
printf("CPLD: v%d\n", version);
}
int checkboard(void)
{
printf("EL: %d\n", current_el());
if (CONFIG_IS_ENABLED(SL28CPLD))
print_cpld_version();
return 0;
}
static void stop_recovery_watchdog(void)
{
struct udevice *dev;
int ret;
ret = uclass_get_device_by_driver(UCLASS_WDT,
DM_DRIVER_GET(sl28cpld_wdt), &dev);
if (!ret)
wdt_stop(dev);
}
int fsl_board_late_init(void)
{
/*
* Usually, the after a board reset, the watchdog is enabled by
* default. This is to supervise the bootloader boot-up. Therefore,
* to prevent a watchdog reset if we don't actively kick it, we have
* to disable it.
*
* If the watchdog isn't enabled at reset (which is a configuration
* option) disabling it doesn't hurt either.
*/
if (!CONFIG_IS_ENABLED(WATCHDOG_AUTOSTART))
stop_recovery_watchdog();
return 0;
}
void detail_board_ddr_info(void)
{
puts("\nDDR ");
print_size(gd->bd->bi_dram[0].size + gd->bd->bi_dram[1].size, "");
print_ddr_info(0);
}

View File

@ -147,6 +147,7 @@ static struct mv_ddr_topology_map board_topology_map = {
{0}, /* timing parameters */
{ {0} }, /* electrical configuration */
{0,}, /* electrical parameters */
0, /* ODT configuration */
0x3, /* clock enable mask */
};

View File

@ -171,21 +171,56 @@ void i2c_init_board(void)
#endif
}
#if defined(CONFIG_ENV_IS_IN_MMC) && defined(CONFIG_ENV_IS_IN_FAT)
/*
* Try to use the environment from the boot source first.
* For MMC, this means a FAT partition on the boot device (SD or eMMC).
* If the raw MMC environment is also enabled, this is tried next.
* SPI flash falls back to FAT (on SD card).
*/
enum env_location env_get_location(enum env_operation op, int prio)
{
switch (prio) {
case 0:
return ENVL_FAT;
enum env_location boot_loc = ENVL_FAT;
case 1:
return ENVL_MMC;
gd->env_load_prio = prio;
switch (sunxi_get_boot_device()) {
case BOOT_DEVICE_MMC1:
case BOOT_DEVICE_MMC2:
boot_loc = ENVL_FAT;
break;
case BOOT_DEVICE_NAND:
if (IS_ENABLED(CONFIG_ENV_IS_IN_NAND))
boot_loc = ENVL_NAND;
break;
case BOOT_DEVICE_SPI:
if (IS_ENABLED(CONFIG_ENV_IS_IN_SPI_FLASH))
boot_loc = ENVL_SPI_FLASH;
break;
case BOOT_DEVICE_BOARD:
break;
default:
return ENVL_UNKNOWN;
break;
}
/* Always try to access the environment on the boot device first. */
if (prio == 0)
return boot_loc;
if (prio == 1) {
switch (boot_loc) {
case ENVL_SPI_FLASH:
return ENVL_FAT;
case ENVL_FAT:
if (IS_ENABLED(CONFIG_ENV_IS_IN_MMC))
return ENVL_MMC;
break;
default:
break;
}
}
return ENVL_UNKNOWN;
}
#endif
#ifdef CONFIG_DM_MMC
static void mmc_pinmux_setup(int sdc);

View File

@ -129,6 +129,7 @@ int ft_board_setup(void *blob, struct bd_info *bd)
}
#endif
#ifdef CONFIG_TI_I2C_BOARD_DETECT
int do_board_detect(void)
{
int ret;
@ -353,23 +354,26 @@ static int probe_daughtercards(void)
return 0;
}
#endif
int board_late_init(void)
{
struct ti_am6_eeprom *ep = TI_AM6_EEPROM_DATA;
if (IS_ENABLED(CONFIG_TI_I2C_BOARD_DETECT)) {
struct ti_am6_eeprom *ep = TI_AM6_EEPROM_DATA;
setup_board_eeprom_env();
setup_board_eeprom_env();
/*
* The first MAC address for ethernet a.k.a. ethernet0 comes from
* efuse populated via the am654 gigabit eth switch subsystem driver.
* All the other ones are populated via EEPROM, hence continue with
* an index of 1.
*/
board_ti_am6_set_ethaddr(1, ep->mac_addr_cnt);
/*
* The first MAC address for ethernet a.k.a. ethernet0 comes from
* efuse populated via the am654 gigabit eth switch subsystem driver.
* All the other ones are populated via EEPROM, hence continue with
* an index of 1.
*/
board_ti_am6_set_ethaddr(1, ep->mac_addr_cnt);
/* Check for and probe any plugged-in daughtercards */
probe_daughtercards();
/* Check for and probe any plugged-in daughtercards */
probe_daughtercards();
}
return 0;
}

View File

@ -397,36 +397,34 @@ void configure_serdes_torrent(void)
void configure_serdes_sierra(void)
{
struct udevice *dev, *lnk_dev;
struct phy serdes;
struct udevice *dev, *link_dev;
struct phy link;
int ret, count, i;
int link_count = 0;
if (!IS_ENABLED(CONFIG_PHY_CADENCE_SIERRA))
return;
ret = uclass_get_device_by_driver(UCLASS_PHY,
ret = uclass_get_device_by_driver(UCLASS_MISC,
DM_DRIVER_GET(sierra_phy_provider),
&dev);
if (ret)
printf("Sierra init failed:%d\n", ret);
serdes.dev = dev;
serdes.id = 0;
count = device_get_child_count(dev);
for (i = 0; i < count; i++) {
ret = device_get_child(dev, i, &lnk_dev);
ret = device_get_child(dev, i, &link_dev);
if (ret)
printf("probe of sierra child node %d failed\n", i);
if (link_dev->driver->id == UCLASS_PHY) {
link.dev = link_dev;
link.id = link_count++;
ret = generic_phy_power_on(&link);
if (ret)
printf("phy_power_on failed !!\n");
}
}
ret = generic_phy_init(&serdes);
if (ret)
printf("phy_init failed!!\n");
ret = generic_phy_power_on(&serdes);
if (ret)
printf("phy_power_on failed !!\n");
}
#ifdef CONFIG_BOARD_LATE_INIT

View File

@ -11,17 +11,23 @@
#include <lcd.h>
#include <video.h>
#define CSI "\x1b["
static int do_video_clear(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
#if defined(CONFIG_DM_VIDEO)
struct udevice *dev;
__maybe_unused struct udevice *dev;
/* Send clear screen and home */
printf(CSI "2J" CSI "1;1H");
#if defined(CONFIG_DM_VIDEO)
#if !defined(CONFIG_VIDEO_ANSI)
if (uclass_first_device_err(UCLASS_VIDEO, &dev))
return CMD_RET_FAILURE;
if (video_clear(dev))
return CMD_RET_FAILURE;
#endif
#elif defined(CONFIG_CFB_CONSOLE)
video_clear();
#elif defined(CONFIG_LCD)

View File

@ -111,5 +111,5 @@ U_BOOT_CMD(pwm, 6, 0, do_pwm,
"invert <pwm_dev_num> <channel> <polarity> - invert polarity\n"
"pwm config <pwm_dev_num> <channel> <period_ns> <duty_ns> - config PWM\n"
"pwm enable <pwm_dev_num> <channel> - enable PWM output\n"
"pwm disable <pwm_dev_num> <channel> - eisable PWM output\n"
"pwm disable <pwm_dev_num> <channel> - disable PWM output\n"
"Note: All input values are in decimal");

View File

@ -193,3 +193,4 @@ CONFIG_UFS=y
CONFIG_CADENCE_UFS=y
CONFIG_TI_J721E_UFS=y
CONFIG_OF_LIBFDT_OVERLAY=y
CONFIG_MMC_SPEED_MODE_SET=y

View File

@ -162,3 +162,4 @@ CONFIG_UFS=y
CONFIG_CADENCE_UFS=y
CONFIG_TI_J721E_UFS=y
CONFIG_OF_LIBFDT_OVERLAY=y
CONFIG_MMC_SPEED_MODE_SET=y

View File

@ -42,23 +42,23 @@ CONFIG_CMD_GREPENV=y
CONFIG_CMD_NVEDIT_EFI=y
CONFIG_CMD_DFU=y
CONFIG_CMD_DM=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_GPT=y
CONFIG_CMD_I2C=y
CONFIG_CMD_MMC=y
CONFIG_CMD_PCI=y
CONFIG_CMD_USB=y
CONFIG_CMD_USB_MASS_STORAGE=y
CONFIG_CMD_WDT=y
CONFIG_CMD_CACHE=y
CONFIG_CMD_EFIDEBUG=y
CONFIG_CMD_RNG=y
CONFIG_OF_CONTROL=y
CONFIG_SPL_OF_CONTROL=y
CONFIG_OF_LIST=""
CONFIG_OF_LIST="fsl-ls1028a-kontron-sl28 fsl-ls1028a-kontron-sl28-var1 fsl-ls1028a-kontron-sl28-var2 fsl-ls1028a-kontron-sl28-var3 fsl-ls1028a-kontron-sl28-var4"
CONFIG_ENV_OVERWRITE=y
CONFIG_ENV_IS_IN_SPI_FLASH=y
CONFIG_SYS_REDUNDAND_ENVIRONMENT=y
CONFIG_NET_RANDOM_ETHADDR=y
CONFIG_NETCONSOLE=y
CONFIG_SPL_DM_SEQ_ALIAS=y
CONFIG_SATA=y
CONFIG_SCSI_AHCI=y
@ -69,8 +69,10 @@ CONFIG_DDR_ECC=y
CONFIG_ECC_INIT_VIA_DDRCONTROLLER=y
CONFIG_DFU_MMC=y
CONFIG_DFU_SF=y
CONFIG_SL28CPLD_GPIO=y
CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
CONFIG_I2C_MUX=y
CONFIG_SL28CPLD=y
CONFIG_MMC_HS400_SUPPORT=y
CONFIG_FSL_ESDHC=y
CONFIG_FSL_ESDHC_SUPPORT_ADMA2=y
@ -102,6 +104,11 @@ CONFIG_USB_DWC3=y
CONFIG_USB_DWC3_LAYERSCAPE=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_DOWNLOAD=y
# CONFIG_WATCHDOG is not set
# CONFIG_WATCHDOG_AUTOSTART is not set
CONFIG_WDT=y
CONFIG_WDT_SL28CPLD=y
CONFIG_WDT_SP805=y
CONFIG_OF_LIBFDT_ASSUME_MASK=0x0
CONFIG_OF_LIBFDT_OVERLAY=y
CONFIG_EFI_SET_TIME=y

View File

@ -7,9 +7,7 @@ CONFIG_DRAM_CLK=672
CONFIG_MMC_SUNXI_SLOT_EXTRA=2
CONFIG_SPL_SPI_SUNXI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_DM_SPI_FLASH=y
CONFIG_SPI_FLASH_XMC=y
CONFIG_SPI=y
CONFIG_DM_SPI=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y

View File

@ -7,10 +7,8 @@ CONFIG_DRAM_CLK=672
CONFIG_MMC_SUNXI_SLOT_EXTRA=2
CONFIG_SPL_SPI_SUNXI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_DM_SPI_FLASH=y
CONFIG_SPI_FLASH_XMC=y
CONFIG_SUN8I_EMAC=y
CONFIG_SPI=y
CONFIG_DM_SPI=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y

View File

@ -9,3 +9,5 @@ CONFIG_MACH_SUNIV=y
CONFIG_DRAM_CLK=156
CONFIG_DRAM_ZQ=0
# CONFIG_VIDEO_SUNXI is not set
CONFIG_SPL_SPI_SUNXI=y
# CONFIG_SYSRESET is not set

View File

@ -11,5 +11,6 @@ CONFIG_MMC0_CD_PIN=""
CONFIG_SPL_SPI_SUNXI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_SUN8I_EMAC=y
CONFIG_SPI=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y

View File

@ -11,9 +11,11 @@ CONFIG_SPL_SPI_SUNXI=y
CONFIG_SPL_I2C=y
CONFIG_SPL_SYS_I2C_LEGACY=y
CONFIG_SYS_I2C_MVTWSI=y
CONFIG_SPI_FLASH_MACRONIX=y
CONFIG_SUN8I_EMAC=y
CONFIG_SY8106A_POWER=y
CONFIG_SY8106A_VOUT1_VOLT=1100
CONFIG_SPI=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_MUSB_GADGET=y

View File

@ -8,6 +8,8 @@ CONFIG_DRAM_CLK=624
CONFIG_SPL_SPI_SUNXI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_CONSOLE_MUX=y
CONFIG_SPI_FLASH_WINBOND=y
CONFIG_SUN8I_EMAC=y
CONFIG_SPI=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y

View File

@ -7,7 +7,9 @@ CONFIG_RESERVE_ALLWINNER_BOOT0_HEADER=y
CONFIG_MACPWR="PD14"
CONFIG_SPL_SPI_SUNXI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_SPI_FLASH_WINBOND=y
CONFIG_PHY_REALTEK=y
CONFIG_SUN8I_EMAC=y
CONFIG_SPI=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y

View File

@ -15,5 +15,7 @@ CONFIG_SPL_SYS_I2C_LEGACY=y
CONFIG_SYS_I2C_MVTWSI=y
CONFIG_SYS_I2C_SLAVE=0x7f
CONFIG_SYS_I2C_SPEED=400000
CONFIG_SPI_FLASH_MACRONIX=y
CONFIG_PHY_REALTEK=y
CONFIG_SUN8I_EMAC=y
CONFIG_SPI=y

View File

@ -8,6 +8,8 @@ CONFIG_DRAM_CLK=624
CONFIG_SPL_SPI_SUNXI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_CONSOLE_MUX=y
CONFIG_SPI_FLASH_WINBOND=y
CONFIG_SUN8I_EMAC=y
CONFIG_SPI=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y

View File

@ -10,6 +10,8 @@ CONFIG_MMC0_CD_PIN=""
CONFIG_MMC_SUNXI_SLOT_EXTRA=2
CONFIG_SPL_SPI_SUNXI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_SPI_FLASH_WINBOND=y
CONFIG_SUN8I_EMAC=y
CONFIG_SPI=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y

View File

@ -11,8 +11,10 @@ CONFIG_USB3_VBUS_PIN="PL5"
CONFIG_SPL_SPI_SUNXI=y
# CONFIG_PSCI_RESET is not set
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_SPI_FLASH_WINBOND=y
CONFIG_SUN8I_EMAC=y
CONFIG_PHY_SUN50I_USB3=y
CONFIG_SPI=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_DWC3=y
CONFIG_USB_EHCI_HCD=y

View File

@ -12,8 +12,10 @@ CONFIG_SPL_SYS_I2C_LEGACY=y
CONFIG_SYS_I2C_MVTWSI=y
CONFIG_SYS_I2C_SLAVE=0x7f
CONFIG_SYS_I2C_SPEED=400000
CONFIG_SPI_FLASH_WINBOND=y
# CONFIG_NETDEVICES is not set
CONFIG_AXP209_POWER=y
CONFIG_AXP_DCDC2_VOLT=1250
CONFIG_AXP_DCDC3_VOLT=3300
CONFIG_CONS_INDEX=3
CONFIG_SPI=y

View File

@ -13,5 +13,6 @@ CONFIG_SPL_SPI_SUNXI=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_SPI_FLASH_WINBOND=y
CONFIG_SUN8I_EMAC=y
CONFIG_SPI=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y

View File

@ -14,6 +14,7 @@ CONFIG_DEFAULT_DEVICE_TREE="imx6q-tbs2910"
CONFIG_PRE_CON_BUF_ADDR=0x7c000000
CONFIG_CMD_HDMIDETECT=y
CONFIG_AHCI=y
CONFIG_LTO=y
CONFIG_SUPPORT_RAW_INITRD=y
CONFIG_BOOTDELAY=3
CONFIG_USE_BOOTCOMMAND=y

View File

@ -93,3 +93,4 @@ CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
CONFIG_WDT=y
CONFIG_WDT_ORION=y
CONFIG_EXT4_WRITE=y

View File

@ -17,7 +17,7 @@ CONFIG_ANDROID_BOOT_IMAGE=y
CONFIG_BOOTDELAY=1
CONFIG_USE_BOOTARGS=y
CONFIG_BOOTARGS="console=ttyAMA0 earlycon=pl011,0x1c090000 debug user_debug=31 loglevel=9"
CONFIG_BOOTCOMMAND="if smhload ${boot_name} ${boot_addr_r}; then set bootargs; abootimg addr ${boot_addr_r}; abootimg get dtb --index=0 fdt_addr_r; bootm ${boot_addr_r} ${boot_addr_r} ${fdt_addr_r}; else; set fdt_high 0xffffffffffffffff; set initrd_high 0xffffffffffffffff; smhload ${kernel_name} ${kernel_addr}; smhload ${fdtfile} ${fdt_addr_r}; smhload ${ramdisk_name} ${ramdisk_addr_r} ramdisk_end; fdt addr ${fdt_addr_r}; fdt resize; fdt chosen ${ramdisk_addr_r} ${ramdisk_end}; booti $kernel_addr - $fdt_addr_r; fi"
CONFIG_BOOTCOMMAND="if smhload ${boot_name} ${boot_addr_r}; then setenv bootargs; abootimg addr ${boot_addr_r}; abootimg get dtb --index=0 fdt_addr_r; bootm ${boot_addr_r} ${boot_addr_r} ${fdt_addr_r}; else; setenv fdt_high 0xffffffffffffffff; setenv initrd_high 0xffffffffffffffff; smhload ${kernel_name} ${kernel_addr_r}; smhload ${fdtfile} ${fdt_addr_r}; smhload ${ramdisk_name} ${ramdisk_addr_r} ramdisk_end; fdt addr ${fdt_addr_r}; fdt resize; fdt chosen ${ramdisk_addr_r} ${ramdisk_end}; booti $kernel_addr_r - $fdt_addr_r; fi"
# CONFIG_DISPLAY_CPUINFO is not set
# CONFIG_DISPLAY_BOARDINFO is not set
CONFIG_SYS_PROMPT="VExpress64# "

View File

@ -23,34 +23,17 @@ Copy u-boot.rom to a TFTP server.
Install the bootloader on the board
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Please note, this bootloader doesn't support the builtin watchdog (yet),
therefore you have to disable it, see below. Otherwise you'll end up in
the failsafe bootloader on every reset::
To install the bootloader binary use the following command::
> tftp path/to/u-boot.rom
> sf probe 0
> sf update $fileaddr 0x210000 $filesize
The board is fully failsafe, you can't break anything. But because you've
disabled the builtin watchdog you might have to manually enter failsafe
mode by asserting the ``FORCE_RECOV#`` line during board reset.
Disable the builtin watchdog
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- boot into the failsafe bootloader, either by asserting the
``FORCE_RECOV#`` line or if you still have the original bootloader
installed you can use the command::
> wdt dev cpld_watchdog@4a; wdt expire 1
- in the failsafe bootloader use the "sl28 nvm" command to disable
the automatic start of the builtin watchdog::
> sl28 nvm 0008
- power-cycle the board
The board is fully failsafe, you can't break anything. If builtin watchdog
is enabled, you'll automatically end up in the failsafe bootloader if
something goes wrong. If the watchdog is disabled, you have to manually
enter failsafe mode by asserting the ``FORCE_RECOV#`` line during board
reset.
Update image
------------
@ -67,20 +50,41 @@ Afterward you can copy this file to your ESP into the /EFI/UpdateCapsule/
folder. On the next EFI boot this will automatically update your
bootloader.
Useful I2C tricks
-----------------
Builtin watchdog
----------------
The board has a board management controller which is not supported in
u-boot (yet). But you can use the i2c command to access it.
The builtin watchdog will supervise the bootloader startup. If anything
goes wrong it will reset the board and boot into the failsafe bootloader.
- reset into failsafe bootloader::
Once the bootloader is started successfully, it will disable the watchdog
timer.
> i2c mw 4a 5.1 0; i2c mw 4a 6.1 6b; i2c mw 4a 4.1 42
wdt command flags
^^^^^^^^^^^^^^^^^
- read board management controller version::
The `wdt start` as well as the `wdt expire` command take a flags argument.
The supported bitmask is as follows.
> i2c md 4a 3.1 1
| Bit | Description |
| --- | ----------------------------- |
| 0 | Enable failsafe mode |
| 1 | Lock the control register |
| 2 | Disable board reset |
| 3 | Enable WDT_TIME_OUT# line |
For example, you can use `wdt expire 1` to issue a reset and boot into the
failsafe bootloader.
Disable the builtin watchdog
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If for some reason, this isn't a desired behavior, the watchdog can also
be configured to not be enabled on board reset. It's configuration is saved
in the non-volatile board configuration bits. To change these you can use
the `sl28 nvm` command.
For more information on the non-volatile board configuration bits, see the
following section.
Non-volatile Board Configuration Bits
-------------------------------------

View File

@ -560,7 +560,7 @@ Write U-boot SPL and U-boot to their partitions.
.. code-block:: none
dd if=u-boot-spl.bin of=/dev/mtdblock0 bs=4096 seek=5 conv=sync
dd if=spl/u-boot-spl.bin of=/dev/mtdblock0 bs=4096 seek=5 conv=sync
dd if=u-boot.itb of=/dev/mtdblock0 bs=4096 seek=261 conv=sync
Power off the board.

11
doc/build/gcc.rst vendored
View File

@ -25,11 +25,12 @@ Depending on the build targets further packages maybe needed
sudo apt-get install bc bison build-essential coccinelle \
device-tree-compiler dfu-util efitools flex gdisk graphviz imagemagick \
liblz4-tool libguestfs-tools libncurses-dev libpython3-dev libsdl2-dev \
libssl-dev lz4 lzma lzma-alone openssl pkg-config python3 \
python3-coverage python3-pkg-resources python3-pycryptodome \
python3-pyelftools python3-pytest python3-sphinxcontrib.apidoc \
python3-sphinx-rtd-theme python3-virtualenv swig
liblz4-tool libgnutls28-dev libguestfs-tools libncurses-dev \
libpython3-dev libsdl2-dev libssl-dev lz4 lzma lzma-alone openssl \
pkg-config python3 python3-coverage python3-pkg-resources \
python3-pycryptodome python3-pyelftools python3-pytest \
python3-sphinxcontrib.apidoc python3-sphinx-rtd-theme python3-virtualenv \
swig
SUSE based
~~~~~~~~~~

View File

@ -1,4 +1,4 @@
.TH KWBOOT 1 "2021-08-25"
.TH KWBOOT 1 "2022-03-02"
.SH NAME
kwboot \- Boot Marvell Kirkwood (and others 32-bit) SoCs over a serial link.
@ -11,7 +11,7 @@ kwboot \- Boot Marvell Kirkwood (and others 32-bit) SoCs over a serial link.
.SH "DESCRIPTION"
The \fBkwboot\fP program boots boards based on Marvell's 32-bit
platforms including Kirkwood, Dove, A370, AXP, A375, A38x
platforms including Kirkwood, Dove, Avanta, A370, AXP, A375, A38x
and A39x over their integrated UART. Boot image files will typically
contain a second stage boot loader, such as U-Boot. The image file
must conform to Marvell's BootROM firmware image format
@ -47,6 +47,48 @@ code in it's header which may also print some output via UART (for
example U-Boot SPL does this). In such a case, this output is also
written to stdout after the header is sent.
.TP
.B "\-b"
Do only handshake on \fITTY\fP without uploading any file. File upload
could be done later via option \fB\-D\fP or via any other Xmodem
application, like \fBsx\fP(1).
.TP
.B "\-d"
Do special handshake on \fITTY\fP for console debug mode.
This will instruct BootROM to enter builtin simple console debug mode.
Should be combined with option \fB\-t\fP.
To get a BootROM help, type this command followed by ENTER key:
.RS 1.2i
.TP
.B ?
.RE
.IP
Armada 38x BootROM has a bug which cause that BootROM's standard output
is turned off on UART when SPI-NOR contains valid boot image. Nevertheless
BootROM's standard input and BootROM's terminal echo are active and working
fine. To workaround this BootROM bug with standard output, it is possible
to manually overwrite BootROM variables stored in SRAM which BootROM use
for checking if standard output is enabled or not. To enable BootROM
standard output on UART, type this command folled by ENTER key:
.RS 1.2i
.TP
.B w 0x40034100 1
.RE
.TP
.BI "\-D" " image"
Upload file \fIimage\fP over \fITTY\fP without initial handshake.
This method is used primary on Dove platforms, where BootROM does
not support initial handshake for entering UART upload mode and
strapping pins (exported via e.g. buttons) are used instead.
.TP
.BI "\-p"
Obsolete. Does nothing.
@ -55,13 +97,33 @@ In the past, when this option was used, the program patched the header
in the image prior upload, to "UART boot" type. This is now done by
default.
.TP
.B "\-q"
Obsolete. Does nothing.
It is unknown whether it did something in the past.
.TP
.BI "\-s" " response-timeout"
Specify custom response timeout when doing handshake. Default value is 50 ms.
It is the timeout between sending two consecutive handshake patterns, meaning
how long to wait for response from BootROM. Affects only option \fB\-b\fP with
image file and option \fB\-d\fP.
Option \fB-a\fP specify response timeout suitable for Armada XP BootROM and
currently it is 1000 ms.
Some testing showed that specifying 24 ms as response timeout make handshake
with Armada 385 BootROM more stable.
.TP
.BI "\-t"
Run a terminal program, connecting standard input and output to
.RB \fITTY\fP.
If used in combination with \fB-b\fP, terminal mode is entered
immediately following a successful image upload.
If used in combination with \fB\-b\fP, \fB\-D\fP or \fB\-d\fP option,
terminal mode is entered immediately following a successful image upload
or successful handshake (if not doing image upload).
If standard I/O streams connect to a console, this mode will terminate
after receiving \fBctrl-\e\fP followed by \fBc\fP from console input.
@ -85,9 +147,42 @@ Tested values for \fIbaudrate\fP for Armada 38x include: 115200,
230400, 460800, 500000, 576000, 921600, 1000000, 1152000, 1500000,
2000000, 2500000, 3125000, 4000000 and 5200000.
.SH "EXAMPLES"
Instruct BootROM to enter boot Xmodem boot mode, send \fIu-boot-spl.kwb\fP
kwbimage file via Xmodem on \fI/dev/ttyUSB0\fP at 115200 Bd and run terminal
program:
.IP
.B kwboot -b u-boot-spl.kwb -t /dev/ttyUSB0
.PP
Instruct BootROM to enter boot Xmodem boot mode, send header of
\fIu-boot-spl.kwb\fP kwbimage file via Xmodem at 115200 Bd, then instruct
BootROM to change baudrate to 5200000 Bd, send data part of the kwbimage
file via Xmodem at high speed and finally run terminal program:
.IP
.B kwboot -b u-boot-spl.kwb -B 5200000 -t /dev/ttyUSB0
.PP
Only send \fIu-boot-spl.kwb\fP kwbimage file via Xmodem on \fI/dev/ttyUSB0\fP
at 115200 Bd:
.IP
.B kwboot -D u-boot-spl.kwb /dev/ttyUSB0
.PP
Instruct BootROM to enter console debug mode and run terminal program on
\fI/dev/ttyUSB0\fP at 115200 Bd:
.IP
.B kwboot -d -t /dev/ttyUSB0
.PP
Only run terminal program on \fI/dev/ttyUSB0\fP at 115200 Bd:
.IP
.B kwboot -t /dev/ttyUSB0
.SH "SEE ALSO"
.PP
\fBmkimage\fP(1)
\fBmkimage\fP(1), \fBsx\fP(1)
.SH "AUTHORS"

View File

@ -552,4 +552,10 @@ config ZYNQMP_GPIO_MODEPIN
are accessed using xilinx firmware. In modepin register, [3:0] bits
set direction, [7:4] bits read IO, [11:8] bits set/clear IO.
config SL28CPLD_GPIO
bool "Kontron sl28cpld GPIO driver"
depends on DM_GPIO && SL28CPLD
help
Support GPIO access on Kontron sl28cpld board management controllers.
endif

View File

@ -71,4 +71,5 @@ obj-$(CONFIG_NX_GPIO) += nx_gpio.o
obj-$(CONFIG_SIFIVE_GPIO) += sifive-gpio.o
obj-$(CONFIG_NOMADIK_GPIO) += nmk_gpio.o
obj-$(CONFIG_MAX7320_GPIO) += max7320_gpio.o
obj-$(CONFIG_SL28CPLD_GPIO) += sl28cpld-gpio.o
obj-$(CONFIG_ZYNQMP_GPIO_MODEPIN) += zynqmp_gpio_modepin.o

View File

@ -0,0 +1,165 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* GPIO driver for the sl28cpld
*
* Copyright (c) 2021 Michael Walle <michael@walle.cc>
*/
#include <common.h>
#include <dm.h>
#include <asm/gpio.h>
#include <sl28cpld.h>
/* GPIO flavor */
#define SL28CPLD_GPIO_DIR 0x00
#define SL28CPLD_GPIO_OUT 0x01
#define SL28CPLD_GPIO_IN 0x02
/* input-only flavor */
#define SL28CPLD_GPI_IN 0x00
/* output-only flavor */
#define SL28CPLD_GPO_OUT 0x00
enum {
SL28CPLD_GPIO,
SL28CPLD_GPI,
SL28CPLD_GPO,
};
static int sl28cpld_gpio_get_value(struct udevice *dev, unsigned int gpio)
{
ulong type = dev_get_driver_data(dev);
int val, reg;
switch (type) {
case SL28CPLD_GPIO:
reg = SL28CPLD_GPIO_IN;
break;
case SL28CPLD_GPI:
reg = SL28CPLD_GPI_IN;
break;
case SL28CPLD_GPO:
/* we are output only, thus just return the output value */
reg = SL28CPLD_GPO_OUT;
break;
default:
return -EINVAL;
}
val = sl28cpld_read(dev, reg);
return val < 0 ? val : !!(val & BIT(gpio));
}
static int sl28cpld_gpio_set_value(struct udevice *dev, unsigned int gpio,
int value)
{
ulong type = dev_get_driver_data(dev);
uint reg;
switch (type) {
case SL28CPLD_GPIO:
reg = SL28CPLD_GPIO_OUT;
break;
case SL28CPLD_GPO:
reg = SL28CPLD_GPO_OUT;
break;
case SL28CPLD_GPI:
default:
return -EINVAL;
}
if (value)
return sl28cpld_update(dev, reg, 0, BIT(gpio));
else
return sl28cpld_update(dev, reg, BIT(gpio), 0);
}
static int sl28cpld_gpio_direction_input(struct udevice *dev, unsigned int gpio)
{
ulong type = dev_get_driver_data(dev);
switch (type) {
case SL28CPLD_GPI:
return 0;
case SL28CPLD_GPIO:
return sl28cpld_update(dev, SL28CPLD_GPIO_DIR, BIT(gpio), 0);
case SL28CPLD_GPO:
default:
return -EINVAL;
}
}
static int sl28cpld_gpio_direction_output(struct udevice *dev,
unsigned int gpio, int value)
{
ulong type = dev_get_driver_data(dev);
int ret;
/* set_value() will report an error if we are input-only */
ret = sl28cpld_gpio_set_value(dev, gpio, value);
if (ret)
return ret;
if (type == SL28CPLD_GPIO)
return sl28cpld_update(dev, SL28CPLD_GPIO_DIR, 0, BIT(gpio));
return 0;
}
static int sl28cpld_gpio_get_function(struct udevice *dev, unsigned int gpio)
{
ulong type = dev_get_driver_data(dev);
int val;
switch (type) {
case SL28CPLD_GPIO:
val = sl28cpld_read(dev, SL28CPLD_GPIO_DIR);
if (val < 0)
return val;
if (val & BIT(gpio))
return GPIOF_OUTPUT;
else
return GPIOF_INPUT;
case SL28CPLD_GPI:
return GPIOF_INPUT;
case SL28CPLD_GPO:
return GPIOF_OUTPUT;
default:
return -EINVAL;
}
}
static const struct dm_gpio_ops sl28cpld_gpio_ops = {
.direction_input = sl28cpld_gpio_direction_input,
.direction_output = sl28cpld_gpio_direction_output,
.get_value = sl28cpld_gpio_get_value,
.set_value = sl28cpld_gpio_set_value,
.get_function = sl28cpld_gpio_get_function,
};
static int sl28cpld_gpio_probe(struct udevice *dev)
{
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
uc_priv->gpio_count = 8;
uc_priv->bank_name = dev_read_name(dev);
return 0;
}
static const struct udevice_id sl28cpld_gpio_ids[] = {
{ .compatible = "kontron,sl28cpld-gpio", .data = SL28CPLD_GPIO},
{ .compatible = "kontron,sl28cpld-gpo", .data = SL28CPLD_GPO},
{ .compatible = "kontron,sl28cpld-gpi", .data = SL28CPLD_GPI},
{ }
};
U_BOOT_DRIVER(sl28cpld_gpio) = {
.name = "sl28cpld_gpio",
.id = UCLASS_GPIO,
.of_match = sl28cpld_gpio_ids,
.probe = sl28cpld_gpio_probe,
.ops = &sl28cpld_gpio_ops,
};

View File

@ -512,4 +512,12 @@ config ESM_PMIC
config FSL_IFC
bool
config SL28CPLD
bool "Enable Kontron sl28cpld multi-function driver"
depends on DM_I2C
help
Support for the Kontron sl28cpld management controller. This is
the base driver which provides common access methods for the
sub-drivers.
endmenu

View File

@ -82,3 +82,4 @@ obj-$(CONFIG_MICROCHIP_FLEXCOM) += microchip_flexcom.o
obj-$(CONFIG_K3_AVS0) += k3_avs.o
obj-$(CONFIG_ESM_K3) += k3_esm.o
obj-$(CONFIG_ESM_PMIC) += esm_pmic.o
obj-$(CONFIG_SL28CPLD) += sl28cpld.o

105
drivers/misc/sl28cpld.c Normal file
View File

@ -0,0 +1,105 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2021 Michael Walle <michael@walle.cc>
*/
#include <common.h>
#include <dm.h>
#include <i2c.h>
struct sl28cpld_child_plat {
uint offset;
};
/*
* The access methods works either with the first argument being a child
* device or with the MFD device itself.
*/
static int sl28cpld_read_child(struct udevice *dev, uint offset)
{
struct sl28cpld_child_plat *plat = dev_get_parent_plat(dev);
struct udevice *mfd = dev_get_parent(dev);
return dm_i2c_reg_read(mfd, offset + plat->offset);
}
int sl28cpld_read(struct udevice *dev, uint offset)
{
if (dev->driver == DM_DRIVER_GET(sl28cpld))
return dm_i2c_reg_read(dev, offset);
else
return sl28cpld_read_child(dev, offset);
}
static int sl28cpld_write_child(struct udevice *dev, uint offset,
uint8_t value)
{
struct sl28cpld_child_plat *plat = dev_get_parent_plat(dev);
struct udevice *mfd = dev_get_parent(dev);
return dm_i2c_reg_write(mfd, offset + plat->offset, value);
}
int sl28cpld_write(struct udevice *dev, uint offset, uint8_t value)
{
if (dev->driver == DM_DRIVER_GET(sl28cpld))
return dm_i2c_reg_write(dev, offset, value);
else
return sl28cpld_write_child(dev, offset, value);
}
int sl28cpld_update(struct udevice *dev, uint offset, uint8_t clear,
uint8_t set)
{
int val;
val = sl28cpld_read(dev, offset);
if (val < 0)
return val;
val &= ~clear;
val |= set;
return sl28cpld_write(dev, offset, val);
}
static int sl28cpld_probe(struct udevice *dev)
{
i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS |
DM_I2C_CHIP_WR_ADDRESS);
return 0;
}
static int sl28cpld_child_post_bind(struct udevice *dev)
{
struct sl28cpld_child_plat *plat = dev_get_parent_plat(dev);
int offset;
if (!dev_has_ofnode(dev))
return 0;
offset = dev_read_u32_default(dev, "reg", -1);
if (offset == -1)
return -EINVAL;
plat->offset = offset;
return 0;
}
static const struct udevice_id sl28cpld_ids[] = {
{ .compatible = "kontron,sl28cpld" },
{}
};
U_BOOT_DRIVER(sl28cpld) = {
.name = "sl28cpld",
.id = UCLASS_NOP,
.of_match = sl28cpld_ids,
.probe = sl28cpld_probe,
.bind = dm_scan_fdt_dev,
.flags = DM_FLAG_PRE_RELOC,
.per_child_plat_auto = sizeof(struct sl28cpld_child_plat),
.child_post_bind = sl28cpld_child_post_bind,
};

View File

@ -90,9 +90,33 @@ struct rockchip_sdhc {
};
struct sdhci_data {
int (*emmc_set_clock)(struct sdhci_host *host, unsigned int clock);
int (*emmc_phy_init)(struct udevice *dev);
int (*get_phy)(struct udevice *dev);
/**
* set_control_reg() - Set SDHCI control registers
*
* This is the set_control_reg() SDHCI operation that should be
* used for the hardware this driver data is associated with.
* Normally, this is used to set up control registers for
* voltage level and UHS speed mode.
*
* @host: SDHCI host structure
*/
void (*set_control_reg)(struct sdhci_host *host);
/**
* set_ios_post() - Host specific hook after set_ios() calls
*
* This is the set_ios_post() SDHCI operation that should be
* used for the hardware this driver data is associated with.
* Normally, this is a hook that is called after sdhci_set_ios()
* that does any necessary host-specific configuration.
*
* @host: SDHCI host structure
* Return: 0 if successful, -ve on error
*/
int (*set_ios_post)(struct sdhci_host *host);
};
static int rk3399_emmc_phy_init(struct udevice *dev)
@ -182,15 +206,28 @@ static int rk3399_emmc_get_phy(struct udevice *dev)
return 0;
}
static int rk3399_sdhci_emmc_set_clock(struct sdhci_host *host, unsigned int clock)
static void rk3399_sdhci_set_control_reg(struct sdhci_host *host)
{
struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, host);
struct mmc *mmc = host->mmc;
uint clock = mmc->tran_speed;
int cycle_phy = host->clock != clock && clock > EMMC_MIN_FREQ;
if (cycle_phy)
rk3399_emmc_phy_power_off(priv->phy);
sdhci_set_clock(host->mmc, clock);
sdhci_set_control_reg(host);
};
static int rk3399_sdhci_set_ios_post(struct sdhci_host *host)
{
struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, host);
struct mmc *mmc = host->mmc;
uint clock = mmc->tran_speed;
int cycle_phy = host->clock != clock && clock > EMMC_MIN_FREQ;
if (!clock)
clock = mmc->clock;
if (cycle_phy)
rk3399_emmc_phy_power_on(priv->phy, clock);
@ -269,10 +306,8 @@ static int rk3568_emmc_get_phy(struct udevice *dev)
return 0;
}
static int rockchip_sdhci_set_ios_post(struct sdhci_host *host)
static int rk3568_sdhci_set_ios_post(struct sdhci_host *host)
{
struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, host);
struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(priv->dev);
struct mmc *mmc = host->mmc;
uint clock = mmc->tran_speed;
u32 reg;
@ -280,8 +315,7 @@ static int rockchip_sdhci_set_ios_post(struct sdhci_host *host)
if (!clock)
clock = mmc->clock;
if (data->emmc_set_clock)
data->emmc_set_clock(host, clock);
rk3568_sdhci_emmc_set_clock(host, clock);
if (mmc->selected_mode == MMC_HS_400 || mmc->selected_mode == MMC_HS_400_ES) {
reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
@ -295,6 +329,26 @@ static int rockchip_sdhci_set_ios_post(struct sdhci_host *host)
return 0;
}
static void rockchip_sdhci_set_control_reg(struct sdhci_host *host)
{
struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, host);
struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(priv->dev);
if (data->set_control_reg)
data->set_control_reg(host);
}
static int rockchip_sdhci_set_ios_post(struct sdhci_host *host)
{
struct rockchip_sdhc *priv = container_of(host, struct rockchip_sdhc, host);
struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(priv->dev);
if (data->set_ios_post)
return data->set_ios_post(host);
return 0;
}
static int rockchip_sdhci_execute_tuning(struct mmc *mmc, u8 opcode)
{
struct sdhci_host *host = dev_get_priv(mmc->dev);
@ -358,6 +412,7 @@ static int rockchip_sdhci_execute_tuning(struct mmc *mmc, u8 opcode)
static struct sdhci_ops rockchip_sdhci_ops = {
.set_ios_post = rockchip_sdhci_set_ios_post,
.platform_execute_tuning = &rockchip_sdhci_execute_tuning,
.set_control_reg = rockchip_sdhci_set_control_reg,
};
static int rockchip_sdhci_probe(struct udevice *dev)
@ -436,15 +491,16 @@ static int rockchip_sdhci_bind(struct udevice *dev)
}
static const struct sdhci_data rk3399_data = {
.emmc_set_clock = rk3399_sdhci_emmc_set_clock,
.get_phy = rk3399_emmc_get_phy,
.emmc_phy_init = rk3399_emmc_phy_init,
.set_control_reg = rk3399_sdhci_set_control_reg,
.set_ios_post = rk3399_sdhci_set_ios_post,
};
static const struct sdhci_data rk3568_data = {
.emmc_set_clock = rk3568_sdhci_emmc_set_clock,
.get_phy = rk3568_emmc_get_phy,
.emmc_phy_init = rk3568_emmc_phy_init,
.set_ios_post = rk3568_sdhci_set_ios_post,
};
static const struct udevice_id sdhci_ids[] = {

View File

@ -119,7 +119,7 @@ const struct flash_info spi_nor_ids[] = {
},
{
INFO("gd25lq128", 0xc86018, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ |
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
},
{

View File

@ -30,37 +30,25 @@
#include <linux/sizes.h>
/* PCIe unit register offsets */
#define SELECT(x, n) ((x >> n) & 1UL)
#define PCIE_DEV_ID_OFF 0x0000
#define PCIE_CMD_OFF 0x0004
#define PCIE_DEV_REV_OFF 0x0008
#define PCIE_BAR_LO_OFF(n) (0x0010 + ((n) << 3))
#define PCIE_BAR_HI_OFF(n) (0x0014 + ((n) << 3))
#define PCIE_EXP_ROM_BAR_OFF 0x0030
#define PCIE_CAPAB_OFF 0x0060
#define PCIE_CTRL_STAT_OFF 0x0068
#define PCIE_HEADER_LOG_4_OFF 0x0128
#define PCIE_BAR_CTRL_OFF(n) (0x1804 + (((n) - 1) * 4))
#define PCIE_WIN04_CTRL_OFF(n) (0x1820 + ((n) << 4))
#define PCIE_WIN04_BASE_OFF(n) (0x1824 + ((n) << 4))
#define PCIE_WIN04_REMAP_OFF(n) (0x182c + ((n) << 4))
#define PCIE_WIN5_CTRL_OFF 0x1880
#define PCIE_WIN5_BASE_OFF 0x1884
#define PCIE_WIN5_REMAP_OFF 0x188c
#define PCIE_CONF_ADDR_OFF 0x18f8
#define PCIE_CONF_DATA_OFF 0x18fc
#define PCIE_MASK_OFF 0x1910
#define PCIE_MASK_ENABLE_INTS (0xf << 24)
#define PCIE_CTRL_OFF 0x1a00
#define PCIE_CTRL_X1_MODE BIT(0)
#define PCIE_CTRL_RC_MODE BIT(1)
#define PCIE_STAT_OFF 0x1a04
#define PCIE_STAT_BUS (0xff << 8)
#define PCIE_STAT_DEV (0x1f << 16)
#define PCIE_STAT_LINK_DOWN BIT(0)
#define PCIE_DEBUG_CTRL 0x1a60
#define PCIE_DEBUG_SOFT_RESET BIT(20)
#define MVPCIE_ROOT_PORT_PCI_CFG_OFF 0x0000
#define MVPCIE_ROOT_PORT_PCI_EXP_OFF 0x0060
#define MVPCIE_BAR_LO_OFF(n) (0x0010 + ((n) << 3))
#define MVPCIE_BAR_HI_OFF(n) (0x0014 + ((n) << 3))
#define MVPCIE_BAR_CTRL_OFF(n) (0x1804 + (((n) - 1) * 4))
#define MVPCIE_WIN04_CTRL_OFF(n) (0x1820 + ((n) << 4))
#define MVPCIE_WIN04_BASE_OFF(n) (0x1824 + ((n) << 4))
#define MVPCIE_WIN04_REMAP_OFF(n) (0x182c + ((n) << 4))
#define MVPCIE_WIN5_CTRL_OFF 0x1880
#define MVPCIE_WIN5_BASE_OFF 0x1884
#define MVPCIE_WIN5_REMAP_OFF 0x188c
#define MVPCIE_CONF_ADDR_OFF 0x18f8
#define MVPCIE_CONF_DATA_OFF 0x18fc
#define MVPCIE_CTRL_OFF 0x1a00
#define MVPCIE_CTRL_RC_MODE BIT(1)
#define MVPCIE_STAT_OFF 0x1a04
#define MVPCIE_STAT_BUS (0xff << 8)
#define MVPCIE_STAT_DEV (0x1f << 16)
#define MVPCIE_STAT_LINK_DOWN BIT(0)
#define LINK_WAIT_RETRIES 100
#define LINK_WAIT_TIMEOUT 1000
@ -77,7 +65,6 @@ struct mvebu_pcie {
u32 lane;
bool is_x4;
int devfn;
u32 lane_mask;
int sec_busno;
char name[16];
unsigned int mem_target;
@ -90,8 +77,8 @@ struct mvebu_pcie {
static inline bool mvebu_pcie_link_up(struct mvebu_pcie *pcie)
{
u32 val;
val = readl(pcie->base + PCIE_STAT_OFF);
return !(val & PCIE_STAT_LINK_DOWN);
val = readl(pcie->base + MVPCIE_STAT_OFF);
return !(val & MVPCIE_STAT_LINK_DOWN);
}
static void mvebu_pcie_wait_for_link(struct mvebu_pcie *pcie)
@ -115,20 +102,20 @@ static void mvebu_pcie_set_local_bus_nr(struct mvebu_pcie *pcie, int busno)
{
u32 stat;
stat = readl(pcie->base + PCIE_STAT_OFF);
stat &= ~PCIE_STAT_BUS;
stat = readl(pcie->base + MVPCIE_STAT_OFF);
stat &= ~MVPCIE_STAT_BUS;
stat |= busno << 8;
writel(stat, pcie->base + PCIE_STAT_OFF);
writel(stat, pcie->base + MVPCIE_STAT_OFF);
}
static void mvebu_pcie_set_local_dev_nr(struct mvebu_pcie *pcie, int devno)
{
u32 stat;
stat = readl(pcie->base + PCIE_STAT_OFF);
stat &= ~PCIE_STAT_DEV;
stat = readl(pcie->base + MVPCIE_STAT_OFF);
stat &= ~MVPCIE_STAT_DEV;
stat |= devno << 16;
writel(stat, pcie->base + PCIE_STAT_OFF);
writel(stat, pcie->base + MVPCIE_STAT_OFF);
}
static inline struct mvebu_pcie *hose_to_pcie(struct pci_controller *hose)
@ -198,18 +185,18 @@ static int mvebu_pcie_read_config(const struct udevice *bus, pci_dev_t bdf,
addr = PCI_CONF1_EXT_ADDRESS(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset);
/* write address */
writel(addr, pcie->base + PCIE_CONF_ADDR_OFF);
writel(addr, pcie->base + MVPCIE_CONF_ADDR_OFF);
/* read data */
switch (size) {
case PCI_SIZE_8:
data = readb(pcie->base + PCIE_CONF_DATA_OFF + (offset & 3));
data = readb(pcie->base + MVPCIE_CONF_DATA_OFF + (offset & 3));
break;
case PCI_SIZE_16:
data = readw(pcie->base + PCIE_CONF_DATA_OFF + (offset & 2));
data = readw(pcie->base + MVPCIE_CONF_DATA_OFF + (offset & 2));
break;
case PCI_SIZE_32:
data = readl(pcie->base + PCIE_CONF_DATA_OFF);
data = readl(pcie->base + MVPCIE_CONF_DATA_OFF);
break;
default:
return -EINVAL;
@ -289,18 +276,18 @@ static int mvebu_pcie_write_config(struct udevice *bus, pci_dev_t bdf,
addr = PCI_CONF1_EXT_ADDRESS(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset);
/* write address */
writel(addr, pcie->base + PCIE_CONF_ADDR_OFF);
writel(addr, pcie->base + MVPCIE_CONF_ADDR_OFF);
/* write data */
switch (size) {
case PCI_SIZE_8:
writeb(value, pcie->base + PCIE_CONF_DATA_OFF + (offset & 3));
writeb(value, pcie->base + MVPCIE_CONF_DATA_OFF + (offset & 3));
break;
case PCI_SIZE_16:
writew(value, pcie->base + PCIE_CONF_DATA_OFF + (offset & 2));
writew(value, pcie->base + MVPCIE_CONF_DATA_OFF + (offset & 2));
break;
case PCI_SIZE_32:
writel(value, pcie->base + PCIE_CONF_DATA_OFF);
writel(value, pcie->base + MVPCIE_CONF_DATA_OFF);
break;
default:
return -EINVAL;
@ -324,20 +311,20 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie)
/* First, disable and clear BARs and windows. */
for (i = 1; i < 3; i++) {
writel(0, pcie->base + PCIE_BAR_CTRL_OFF(i));
writel(0, pcie->base + PCIE_BAR_LO_OFF(i));
writel(0, pcie->base + PCIE_BAR_HI_OFF(i));
writel(0, pcie->base + MVPCIE_BAR_CTRL_OFF(i));
writel(0, pcie->base + MVPCIE_BAR_LO_OFF(i));
writel(0, pcie->base + MVPCIE_BAR_HI_OFF(i));
}
for (i = 0; i < 5; i++) {
writel(0, pcie->base + PCIE_WIN04_CTRL_OFF(i));
writel(0, pcie->base + PCIE_WIN04_BASE_OFF(i));
writel(0, pcie->base + PCIE_WIN04_REMAP_OFF(i));
writel(0, pcie->base + MVPCIE_WIN04_CTRL_OFF(i));
writel(0, pcie->base + MVPCIE_WIN04_BASE_OFF(i));
writel(0, pcie->base + MVPCIE_WIN04_REMAP_OFF(i));
}
writel(0, pcie->base + PCIE_WIN5_CTRL_OFF);
writel(0, pcie->base + PCIE_WIN5_BASE_OFF);
writel(0, pcie->base + PCIE_WIN5_REMAP_OFF);
writel(0, pcie->base + MVPCIE_WIN5_CTRL_OFF);
writel(0, pcie->base + MVPCIE_WIN5_BASE_OFF);
writel(0, pcie->base + MVPCIE_WIN5_REMAP_OFF);
/* Setup windows for DDR banks. Count total DDR size on the fly. */
size = 0;
@ -345,12 +332,12 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie)
const struct mbus_dram_window *cs = dram->cs + i;
writel(cs->base & 0xffff0000,
pcie->base + PCIE_WIN04_BASE_OFF(i));
writel(0, pcie->base + PCIE_WIN04_REMAP_OFF(i));
pcie->base + MVPCIE_WIN04_BASE_OFF(i));
writel(0, pcie->base + MVPCIE_WIN04_REMAP_OFF(i));
writel(((cs->size - 1) & 0xffff0000) |
(cs->mbus_attr << 8) |
(dram->mbus_dram_target_id << 4) | 1,
pcie->base + PCIE_WIN04_CTRL_OFF(i));
pcie->base + MVPCIE_WIN04_CTRL_OFF(i));
size += cs->size;
}
@ -360,14 +347,14 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie *pcie)
size = 1 << fls(size);
/* Setup BAR[1] to all DRAM banks. */
writel(dram->cs[0].base | 0xc, pcie->base + PCIE_BAR_LO_OFF(1));
writel(0, pcie->base + PCIE_BAR_HI_OFF(1));
writel(dram->cs[0].base | 0xc, pcie->base + MVPCIE_BAR_LO_OFF(1));
writel(0, pcie->base + MVPCIE_BAR_HI_OFF(1));
writel(((size - 1) & 0xffff0000) | 0x1,
pcie->base + PCIE_BAR_CTRL_OFF(1));
pcie->base + MVPCIE_BAR_CTRL_OFF(1));
/* Setup BAR[0] to internal registers. */
writel(pcie->intregs, pcie->base + PCIE_BAR_LO_OFF(0));
writel(0, pcie->base + PCIE_BAR_HI_OFF(0));
writel(pcie->intregs, pcie->base + MVPCIE_BAR_LO_OFF(0));
writel(0, pcie->base + MVPCIE_BAR_HI_OFF(0));
}
/* Only enable PCIe link, do not setup it */
@ -406,9 +393,9 @@ static void mvebu_pcie_setup_link(struct mvebu_pcie *pcie)
u32 reg;
/* Setup PCIe controller to Root Complex mode */
reg = readl(pcie->base + PCIE_CTRL_OFF);
reg |= PCIE_CTRL_RC_MODE;
writel(reg, pcie->base + PCIE_CTRL_OFF);
reg = readl(pcie->base + MVPCIE_CTRL_OFF);
reg |= MVPCIE_CTRL_RC_MODE;
writel(reg, pcie->base + MVPCIE_CTRL_OFF);
/*
* Set Maximum Link Width to X1 or X4 in Root Port's PCIe Link
@ -417,10 +404,10 @@ static void mvebu_pcie_setup_link(struct mvebu_pcie *pcie)
* be set to number of SerDes PCIe lanes (1 or 4). If this register is
* not set correctly then link with endpoint card is not established.
*/
reg = readl(pcie->base + PCIE_CAPAB_OFF + PCI_EXP_LNKCAP);
reg = readl(pcie->base + MVPCIE_ROOT_PORT_PCI_EXP_OFF + PCI_EXP_LNKCAP);
reg &= ~PCI_EXP_LNKCAP_MLW;
reg |= (pcie->is_x4 ? 4 : 1) << 4;
writel(reg, pcie->base + PCIE_CAPAB_OFF + PCI_EXP_LNKCAP);
writel(reg, pcie->base + MVPCIE_ROOT_PORT_PCI_EXP_OFF + PCI_EXP_LNKCAP);
}
static int mvebu_pcie_probe(struct udevice *dev)
@ -443,7 +430,7 @@ static int mvebu_pcie_probe(struct udevice *dev)
* have the same format in Marvell's specification as in PCIe
* specification, but their meaning is totally different and they do
* different things: they are aliased into internal mvebu registers
* (e.g. PCIE_BAR_LO_OFF) and these should not be changed or
* (e.g. MVPCIE_BAR_LO_OFF) and these should not be changed or
* reconfigured by pci device drivers.
*
* So our driver converts Type 0 config space to Type 1 and reports
@ -451,10 +438,10 @@ static int mvebu_pcie_probe(struct udevice *dev)
* Type 1 registers is redirected to the virtual cfgcache[] buffer,
* which avoids changing unrelated registers.
*/
reg = readl(pcie->base + PCIE_DEV_REV_OFF);
reg = readl(pcie->base + MVPCIE_ROOT_PORT_PCI_CFG_OFF + PCI_CLASS_REVISION);
reg &= ~0xffffff00;
reg |= (PCI_CLASS_BRIDGE_PCI << 8) << 8;
writel(reg, pcie->base + PCIE_DEV_REV_OFF);
writel(reg, pcie->base + MVPCIE_ROOT_PORT_PCI_CFG_OFF + PCI_CLASS_REVISION);
/*
* mvebu uses local bus number and local device number to determinate

View File

@ -358,26 +358,10 @@ static inline int cdns_reset_deassert(struct reset_control *rst)
return 0;
}
static inline struct cdns_sierra_inst *phy_get_drvdata(struct phy *phy)
static int cdns_sierra_link_init(struct phy *gphy)
{
struct cdns_sierra_phy *sp = dev_get_priv(phy->dev);
int index;
if (phy->id >= SIERRA_MAX_LANES)
return NULL;
for (index = 0; index < sp->nsubnodes; index++) {
if (phy->id == sp->phys[index]->mlane)
return sp->phys[index];
}
return NULL;
}
static int cdns_sierra_phy_init(struct phy *gphy)
{
struct cdns_sierra_inst *ins = phy_get_drvdata(gphy);
struct cdns_sierra_phy *phy = dev_get_priv(gphy->dev);
struct cdns_sierra_inst *ins = dev_get_priv(gphy->dev);
struct cdns_sierra_phy *phy = dev_get_priv(gphy->dev->parent);
struct cdns_sierra_data *init_data = phy->init_data;
struct cdns_sierra_vals *pma_cmn_vals, *pma_ln_vals;
enum cdns_sierra_phy_type phy_type = ins->phy_type;
@ -443,10 +427,11 @@ static int cdns_sierra_phy_init(struct phy *gphy)
return 0;
}
static int cdns_sierra_phy_on(struct phy *gphy)
static int cdns_sierra_link_on(struct phy *gphy)
{
struct cdns_sierra_inst *ins = phy_get_drvdata(gphy);
struct cdns_sierra_phy *sp = dev_get_priv(gphy->dev);
struct cdns_sierra_inst *ins = dev_get_priv(gphy->dev);
struct cdns_sierra_phy *sp = dev_get_priv(gphy->dev->parent);
struct udevice *dev = gphy->dev;
u32 val;
int ret;
@ -503,16 +488,16 @@ static int cdns_sierra_phy_on(struct phy *gphy)
return ret;
}
static int cdns_sierra_phy_off(struct phy *gphy)
static int cdns_sierra_link_off(struct phy *gphy)
{
struct cdns_sierra_inst *ins = phy_get_drvdata(gphy);
struct cdns_sierra_inst *ins = dev_get_priv(gphy->dev);
return reset_assert_bulk(ins->lnk_rst);
}
static int cdns_sierra_phy_reset(struct phy *gphy)
static int cdns_sierra_link_reset(struct phy *gphy)
{
struct cdns_sierra_phy *sp = dev_get_priv(gphy->dev);
struct cdns_sierra_phy *sp = dev_get_priv(gphy->dev->parent);
reset_control_assert(sp->phy_rst);
reset_control_deassert(sp->phy_rst);
@ -520,10 +505,10 @@ static int cdns_sierra_phy_reset(struct phy *gphy)
};
static const struct phy_ops ops = {
.init = cdns_sierra_phy_init,
.power_on = cdns_sierra_phy_on,
.power_off = cdns_sierra_phy_off,
.reset = cdns_sierra_phy_reset,
.init = cdns_sierra_link_init,
.power_on = cdns_sierra_link_on,
.power_off = cdns_sierra_link_off,
.reset = cdns_sierra_link_reset,
};
struct cdns_sierra_pll_mux_sel {
@ -580,7 +565,7 @@ static const struct clk_ops cdns_sierra_pll_mux_ops = {
.set_parent = cdns_sierra_pll_mux_set_parent,
};
int cdns_sierra_pll_mux_probe(struct udevice *dev)
static int cdns_sierra_pll_mux_probe(struct udevice *dev)
{
struct cdns_sierra_pll_mux *priv = dev_get_priv(dev);
struct cdns_sierra_phy *sp = dev_get_priv(dev->parent);
@ -1012,9 +997,8 @@ static int cdns_sierra_phy_get_resets(struct cdns_sierra_phy *sp,
return 0;
}
static int cdns_sierra_bind_link_nodes(struct cdns_sierra_phy *sp)
static int cdns_sierra_phy_bind(struct udevice *dev)
{
struct udevice *dev = sp->dev;
struct driver *link_drv;
ofnode child;
int rc;
@ -1079,6 +1063,7 @@ U_BOOT_DRIVER(sierra_phy_link) = {
.name = "sierra_phy_link",
.id = UCLASS_PHY,
.probe = cdns_sierra_link_probe,
.ops = &ops,
.priv_auto = sizeof(struct cdns_sierra_inst),
};
@ -1141,10 +1126,6 @@ static int cdns_sierra_phy_probe(struct udevice *dev)
}
sp->autoconf = dev_read_bool(dev, "cdns,autoconf");
/* Binding link nodes as children to serdes */
ret = cdns_sierra_bind_link_nodes(sp);
if (ret)
goto clk_disable;
dev_info(dev, "sierra probed\n");
return 0;
@ -1971,10 +1952,10 @@ static const struct udevice_id cdns_sierra_id_table[] = {
U_BOOT_DRIVER(sierra_phy_provider) = {
.name = "cdns,sierra",
.id = UCLASS_PHY,
.id = UCLASS_MISC,
.of_match = cdns_sierra_id_table,
.probe = cdns_sierra_phy_probe,
.remove = cdns_sierra_phy_remove,
.ops = &ops,
.bind = cdns_sierra_phy_bind,
.priv_auto = sizeof(struct cdns_sierra_phy),
};

View File

@ -45,11 +45,13 @@ static int nop_phy_init(struct phy *phy)
#if CONFIG_IS_ENABLED(DM_GPIO)
/* Take phy out of reset */
ret = dm_gpio_set_value(&priv->reset_gpio, false);
if (ret) {
if (CONFIG_IS_ENABLED(CLK))
clk_disable_bulk(&priv->bulk);
return ret;
if (dm_gpio_is_valid(&priv->reset_gpio)) {
ret = dm_gpio_set_value(&priv->reset_gpio, false);
if (ret) {
if (CONFIG_IS_ENABLED(CLK))
clk_disable_bulk(&priv->bulk);
return ret;
}
}
#endif
return 0;

View File

@ -162,11 +162,11 @@ static struct armada_37xx_pin_group armada_37xx_nb_groups[] = {
PIN_GRP_GPIO("emmc_nb", 27, 9, BIT(2), "emmc"),
PIN_GRP_GPIO_3("pwm0", 11, 1, BIT(3) | BIT(20), 0, BIT(20), BIT(3),
"pwm", "led"),
PIN_GRP_GPIO_3("pwm1", 11, 1, BIT(4) | BIT(21), 0, BIT(21), BIT(4),
PIN_GRP_GPIO_3("pwm1", 12, 1, BIT(4) | BIT(21), 0, BIT(21), BIT(4),
"pwm", "led"),
PIN_GRP_GPIO_3("pwm2", 11, 1, BIT(5) | BIT(22), 0, BIT(22), BIT(5),
PIN_GRP_GPIO_3("pwm2", 13, 1, BIT(5) | BIT(22), 0, BIT(22), BIT(5),
"pwm", "led"),
PIN_GRP_GPIO_3("pwm3", 11, 1, BIT(6) | BIT(23), 0, BIT(23), BIT(6),
PIN_GRP_GPIO_3("pwm3", 14, 1, BIT(6) | BIT(23), 0, BIT(23), BIT(6),
"pwm", "led"),
PIN_GRP_GPIO("pmic1", 7, 1, BIT(7), "pmic"),
PIN_GRP_GPIO("pmic0", 6, 1, BIT(8), "pmic"),

View File

@ -121,7 +121,7 @@ static int armada38x_rtc_reset(struct udevice *dev)
armada38x_rtc_write(0, rtc, RTC_CONF_TEST);
mdelay(500);
armada38x_rtc_write(0, rtc, RTC_TIME);
armada38x_rtc_write(BIT(0) | BIT(1), 0, RTC_STATUS);
armada38x_rtc_write(BIT(0) | BIT(1), rtc, RTC_STATUS);
}
return 0;

View File

@ -66,7 +66,8 @@ static int serial_check_stdout(const void *blob, struct udevice **devp)
*/
if (node > 0 && !lists_bind_fdt(gd->dm_root, offset_to_ofnode(node),
devp, NULL, false)) {
if (!device_probe(*devp))
if (device_get_uclass_id(*devp) == UCLASS_SERIAL &&
!device_probe(*devp))
return 0;
}

View File

@ -185,6 +185,12 @@ config ICH_SPI
access the SPI NOR flash on platforms embedding this Intel
ICH IP core.
config IPROC_QSPI
bool "Broadcom iProc QSPI Flash Controller driver"
help
Enable Broadcom iProc QSPI Flash Controller driver.
This driver can be used to access the SPI NOR flash.
config KIRKWOOD_SPI
bool "Marvell Kirkwood SPI Driver"
help

View File

@ -34,6 +34,7 @@ obj-$(CONFIG_FSL_DSPI) += fsl_dspi.o
obj-$(CONFIG_FSL_ESPI) += fsl_espi.o
obj-$(CONFIG_SYNQUACER_SPI) += spi-synquacer.o
obj-$(CONFIG_ICH_SPI) += ich.o
obj-$(CONFIG_IPROC_QSPI) += iproc_qspi.o
obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
obj-$(CONFIG_MESON_SPIFC) += meson_spifc.o
obj-$(CONFIG_MPC8XX_SPI) += mpc8xx_spi.o

View File

@ -201,11 +201,9 @@ static int cadence_spi_probe(struct udevice *bus)
}
}
ret = reset_get_bulk(bus, &priv->resets);
if (ret)
dev_warn(bus, "Can't get reset: %d\n", ret);
else
reset_deassert_bulk(&priv->resets);
priv->resets = devm_reset_bulk_get_optional(bus);
if (priv->resets)
reset_deassert_bulk(priv->resets);
if (!priv->qspi_is_init) {
cadence_qspi_apb_controller_init(plat);
@ -220,8 +218,12 @@ static int cadence_spi_probe(struct udevice *bus)
static int cadence_spi_remove(struct udevice *dev)
{
struct cadence_spi_priv *priv = dev_get_priv(dev);
int ret = 0;
return reset_release_bulk(&priv->resets);
if (priv->resets)
ret = reset_release_bulk(priv->resets);
return ret;
}
static int cadence_spi_set_mode(struct udevice *bus, uint mode)

View File

@ -56,7 +56,7 @@ struct cadence_spi_priv {
unsigned int qspi_calibrated_cs;
unsigned int previous_hz;
struct reset_ctl_bulk resets;
struct reset_ctl_bulk *resets;
};
/* Functions call declaration */

View File

@ -572,7 +572,7 @@ static int dw_spi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
int pos, i, ret = 0;
struct udevice *bus = slave->dev->parent;
struct dw_spi_priv *priv = dev_get_priv(bus);
u8 op_len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes;
u8 op_len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
u8 op_buf[op_len];
u32 cr0;

576
drivers/spi/iproc_qspi.c Normal file
View File

@ -0,0 +1,576 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2020-2021 Broadcom
*/
#include <common.h>
#include <dm.h>
#include <spi.h>
#include <spi-mem.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/iopoll.h>
#include <linux/log2.h>
/* Delay required to change the mode of operation */
#define BUSY_DELAY_US 1
#define BUSY_TIMEOUT_US 200000
#define DWORD_ALIGNED(a) (!(((ulong)(a)) & 3))
/* Chip attributes */
#define QSPI_AXI_CLK 175000000
#define SPBR_MIN 8U
#define SPBR_MAX 255U
#define NUM_CDRAM 16U
#define CDRAM_PCS0 2
#define CDRAM_CONT BIT(7)
#define CDRAM_BITS_EN BIT(6)
#define CDRAM_QUAD_MODE BIT(8)
#define CDRAM_RBIT_INPUT BIT(10)
#define MSPI_SPE BIT(6)
#define MSPI_CONT_AFTER_CMD BIT(7)
#define MSPI_MSTR BIT(7)
/* Register fields */
#define MSPI_SPCR0_MSB_BITS_8 0x00000020
#define BSPI_RAF_CONTROL_START_MASK 0x00000001
#define BSPI_RAF_STATUS_SESSION_BUSY_MASK 0x00000001
#define BSPI_RAF_STATUS_FIFO_EMPTY_MASK 0x00000002
#define BSPI_STRAP_OVERRIDE_DATA_QUAD_SHIFT 3
#define BSPI_STRAP_OVERRIDE_4BYTE_SHIFT 2
#define BSPI_STRAP_OVERRIDE_DATA_DUAL_SHIFT 1
#define BSPI_STRAP_OVERRIDE_SHIFT 0
#define BSPI_BPC_DATA_SHIFT 0
#define BSPI_BPC_MODE_SHIFT 8
#define BSPI_BPC_ADDR_SHIFT 16
#define BSPI_BPC_CMD_SHIFT 24
#define BSPI_BPP_ADDR_SHIFT 16
/* MSPI registers */
#define MSPI_SPCR0_LSB_REG 0x000
#define MSPI_SPCR0_MSB_REG 0x004
#define MSPI_SPCR1_LSB_REG 0x008
#define MSPI_SPCR1_MSB_REG 0x00c
#define MSPI_NEWQP_REG 0x010
#define MSPI_ENDQP_REG 0x014
#define MSPI_SPCR2_REG 0x018
#define MSPI_STATUS_REG 0x020
#define MSPI_CPTQP_REG 0x024
#define MSPI_TX_REG 0x040
#define MSPI_RX_REG 0x0c0
#define MSPI_CDRAM_REG 0x140
#define MSPI_WRITE_LOCK_REG 0x180
#define MSPI_DISABLE_FLUSH_GEN_REG 0x184
/* BSPI registers */
#define BSPI_REVISION_ID_REG 0x000
#define BSPI_SCRATCH_REG 0x004
#define BSPI_MAST_N_BOOT_CTRL_REG 0x008
#define BSPI_BUSY_STATUS_REG 0x00c
#define BSPI_INTR_STATUS_REG 0x010
#define BSPI_B0_STATUS_REG 0x014
#define BSPI_B0_CTRL_REG 0x018
#define BSPI_B1_STATUS_REG 0x01c
#define BSPI_B1_CTRL_REG 0x020
#define BSPI_STRAP_OVERRIDE_CTRL_REG 0x024
#define BSPI_FLEX_MODE_ENABLE_REG 0x028
#define BSPI_BITS_PER_CYCLE_REG 0x02C
#define BSPI_BITS_PER_PHASE_REG 0x030
#define BSPI_CMD_AND_MODE_BYTE_REG 0x034
#define BSPI_FLASH_UPPER_ADDR_BYTE_REG 0x038
#define BSPI_XOR_VALUE_REG 0x03C
#define BSPI_XOR_ENABLE_REG 0x040
#define BSPI_PIO_MODE_ENABLE_REG 0x044
#define BSPI_PIO_IODIR_REG 0x048
#define BSPI_PIO_DATA_REG 0x04C
/* RAF registers */
#define BSPI_RAF_START_ADDRESS_REG 0x00
#define BSPI_RAF_NUM_WORDS_REG 0x04
#define BSPI_RAF_CTRL_REG 0x08
#define BSPI_RAF_FULLNESS_REG 0x0C
#define BSPI_RAF_WATERMARK_REG 0x10
#define BSPI_RAF_STATUS_REG 0x14
#define BSPI_RAF_READ_DATA_REG 0x18
#define BSPI_RAF_WORD_CNT_REG 0x1C
#define BSPI_RAF_CURR_ADDR_REG 0x20
#define XFER_DUAL BIT(30)
#define XFER_QUAD BIT(31)
#define FLUSH_BIT BIT(0)
#define MAST_N_BOOT_BIT BIT(0)
#define WRITE_LOCK_BIT BIT(0)
#define CEIL(m, n) (((m) + (n) - 1) / (n))
#define UPPER_BYTE_MASK 0xFF000000
#define SIZE_16MB 0x001000000
/*
* struct bcmspi_priv - qspi private structure
*
* @bspi_addr: bspi read address
* @bspi_4byte_addr: bspi 4 byte address mode
* @mspi: mspi registers block address
* @bspi: bspi registers block address
* @bspi_raf: bspi raf registers block address
*/
struct bcmspi_priv {
u32 bspi_addr;
bool bspi_4byte_addr;
fdt_addr_t mspi;
fdt_addr_t bspi;
fdt_addr_t bspi_raf;
};
/* BSPI mode */
static void bspi_flush_prefetch_buffers(struct bcmspi_priv *priv)
{
writel(0, priv->bspi + BSPI_B0_CTRL_REG);
writel(0, priv->bspi + BSPI_B1_CTRL_REG);
writel(FLUSH_BIT, priv->bspi + BSPI_B0_CTRL_REG);
writel(FLUSH_BIT, priv->bspi + BSPI_B1_CTRL_REG);
}
static int bspi_enable(struct bcmspi_priv *priv)
{
/* Disable write lock */
writel(0, priv->mspi + MSPI_WRITE_LOCK_REG);
/* Flush prefetch buffers */
bspi_flush_prefetch_buffers(priv);
/* Switch to BSPI */
writel(0, priv->bspi + BSPI_MAST_N_BOOT_CTRL_REG);
return 0;
}
static int bspi_disable(struct bcmspi_priv *priv)
{
int ret;
uint val;
if ((readl(priv->bspi + BSPI_MAST_N_BOOT_CTRL_REG) & 1) == 0) {
ret = readl_poll_timeout(priv->bspi + BSPI_BUSY_STATUS_REG, val, !(val & 1),
BUSY_TIMEOUT_US);
if (ret) {
printf("%s: Failed to disable bspi, device busy\n", __func__);
return ret;
}
/* Switch to MSPI */
writel(MAST_N_BOOT_BIT, priv->bspi + BSPI_MAST_N_BOOT_CTRL_REG);
udelay(BUSY_DELAY_US);
val = readl(priv->bspi + BSPI_MAST_N_BOOT_CTRL_REG);
if (!(val & 1)) {
printf("%s: Failed to enable mspi\n", __func__);
return -EBUSY;
}
}
/* Enable write lock */
writel(WRITE_LOCK_BIT, priv->mspi + MSPI_WRITE_LOCK_REG);
return 0;
}
static int bspi_read_via_raf(struct bcmspi_priv *priv, u8 *rx, uint bytes)
{
u32 status;
uint words;
int aligned;
int ret;
/*
* Flush data from the previous session (unlikely)
* Read outstanding bits in the poll condition to empty FIFO
*/
ret = readl_poll_timeout(priv->bspi_raf + BSPI_RAF_STATUS_REG,
status,
(!readl(priv->bspi_raf + BSPI_RAF_READ_DATA_REG) &&
status & BSPI_RAF_STATUS_FIFO_EMPTY_MASK) &&
!(status & BSPI_RAF_STATUS_SESSION_BUSY_MASK),
BUSY_TIMEOUT_US);
if (ret) {
printf("%s: Failed to flush fifo\n", __func__);
return ret;
}
/* Transfer is in words */
words = CEIL(bytes, 4);
/* Setup hardware */
if (priv->bspi_4byte_addr) {
u32 val = priv->bspi_addr & UPPER_BYTE_MASK;
if (val != readl(priv->bspi + BSPI_FLASH_UPPER_ADDR_BYTE_REG)) {
writel(val, priv->bspi + BSPI_FLASH_UPPER_ADDR_BYTE_REG);
bspi_flush_prefetch_buffers(priv);
}
}
writel(priv->bspi_addr & ~UPPER_BYTE_MASK, priv->bspi_raf + BSPI_RAF_START_ADDRESS_REG);
writel(words, priv->bspi_raf + BSPI_RAF_NUM_WORDS_REG);
writel(0, priv->bspi_raf + BSPI_RAF_WATERMARK_REG);
/* Start reading */
writel(BSPI_RAF_CONTROL_START_MASK, priv->bspi_raf + BSPI_RAF_CTRL_REG);
aligned = DWORD_ALIGNED(rx);
while (bytes) {
status = readl(priv->bspi_raf + BSPI_RAF_STATUS_REG);
if (!(status & BSPI_RAF_STATUS_FIFO_EMPTY_MASK)) {
/* RAF is LE only, convert data to host endianness */
u32 data = le32_to_cpu(readl(priv->bspi_raf + BSPI_RAF_READ_DATA_REG));
/* Check if we can use the whole word */
if (aligned && bytes >= 4) {
*(u32 *)rx = data;
rx += 4;
bytes -= 4;
} else {
uint chunk = min(bytes, 4U);
/* Read out bytes one by one */
while (chunk) {
*rx++ = (u8)data;
data >>= 8;
chunk--;
bytes--;
}
}
continue;
}
if (!(status & BSPI_RAF_STATUS_SESSION_BUSY_MASK)) {
/* FIFO is empty and the session is done */
break;
}
}
return 0;
}
static int bspi_read(struct bcmspi_priv *priv, u8 *rx, uint bytes)
{
int ret;
/* Transfer data */
while (bytes > 0) {
/* Special handing since RAF cannot go across 16MB boundary */
uint trans = bytes;
/* Divide into multiple transfers if it goes across the 16MB boundary */
if (priv->bspi_4byte_addr && (priv->bspi_addr >> 24) !=
((priv->bspi_addr + bytes) >> 24))
trans = SIZE_16MB - (priv->bspi_addr & ~UPPER_BYTE_MASK);
ret = bspi_read_via_raf(priv, rx, trans);
if (ret)
return ret;
priv->bspi_addr += trans;
rx += trans;
bytes -= trans;
}
bspi_flush_prefetch_buffers(priv);
return 0;
}
static void bspi_set_flex_mode(struct bcmspi_priv *priv, const struct spi_mem_op *op)
{
int bpp = (op->dummy.nbytes * 8) / op->dummy.buswidth;
int cmd = op->cmd.opcode;
int bpc = ilog2(op->data.buswidth) << BSPI_BPC_DATA_SHIFT |
ilog2(op->addr.buswidth) << BSPI_BPC_ADDR_SHIFT |
ilog2(op->cmd.buswidth) << BSPI_BPC_CMD_SHIFT;
int so = BIT(BSPI_STRAP_OVERRIDE_SHIFT) |
(op->data.buswidth > 1) << BSPI_STRAP_OVERRIDE_DATA_DUAL_SHIFT |
(op->addr.nbytes > 3) << BSPI_STRAP_OVERRIDE_4BYTE_SHIFT |
(op->data.buswidth > 3) << BSPI_STRAP_OVERRIDE_DATA_QUAD_SHIFT;
/* Disable flex mode first */
writel(0, priv->bspi + BSPI_FLEX_MODE_ENABLE_REG);
/* Configure single, dual or quad mode */
writel(bpc, priv->bspi + BSPI_BITS_PER_CYCLE_REG);
/* Opcode */
writel(cmd, priv->bspi + BSPI_CMD_AND_MODE_BYTE_REG);
/* Count of dummy cycles */
writel(bpp, priv->bspi + BSPI_BITS_PER_PHASE_REG);
/* Enable 4-byte address */
if (priv->bspi_4byte_addr) {
setbits_le32(priv->bspi + BSPI_BITS_PER_PHASE_REG, BIT(BSPI_BPP_ADDR_SHIFT));
} else {
clrbits_le32(priv->bspi + BSPI_BITS_PER_PHASE_REG, BIT(BSPI_BPP_ADDR_SHIFT));
writel(0, priv->bspi + BSPI_FLASH_UPPER_ADDR_BYTE_REG);
}
/* Enable flex mode to take effect */
writel(1, priv->bspi + BSPI_FLEX_MODE_ENABLE_REG);
/* Flush prefetch buffers since 32MB window BSPI could be used */
bspi_flush_prefetch_buffers(priv);
/* Override the strap settings */
writel(so, priv->bspi + BSPI_STRAP_OVERRIDE_CTRL_REG);
}
static int bspi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
{
struct udevice *bus = dev_get_parent(slave->dev);
struct bcmspi_priv *priv = dev_get_priv(bus);
int ret = -ENOTSUPP;
/* BSPI read */
if (op->data.dir == SPI_MEM_DATA_IN &&
op->data.nbytes && op->addr.nbytes) {
priv->bspi_4byte_addr = (op->addr.nbytes > 3);
priv->bspi_addr = op->addr.val;
bspi_set_flex_mode(priv, op);
ret = bspi_read(priv, op->data.buf.in, op->data.nbytes);
}
return ret;
}
static const struct spi_controller_mem_ops bspi_mem_ops = {
.exec_op = bspi_exec_op,
};
/* MSPI mode */
static int mspi_exec(struct bcmspi_priv *priv, uint bytes, const u8 *tx, u8 *rx, ulong flags)
{
u32 cdr = CDRAM_PCS0 | CDRAM_CONT;
bool use_16bits = !(bytes & 1);
if (flags & XFER_QUAD) {
cdr |= CDRAM_QUAD_MODE;
if (!tx)
cdr |= CDRAM_RBIT_INPUT;
}
while (bytes) {
uint chunk;
uint queues;
uint i;
uint val;
int ret;
if (use_16bits) {
chunk = min(bytes, NUM_CDRAM * 2);
queues = (chunk + 1) / 2;
bytes -= chunk;
/* Fill CDRAMs */
for (i = 0; i < queues; i++)
writel(cdr | CDRAM_BITS_EN, priv->mspi + MSPI_CDRAM_REG + 4 * i);
/* Fill TXRAMs */
for (i = 0; i < chunk; i++)
writel(tx ? tx[i] : 0xff, priv->mspi + MSPI_TX_REG + 4 * i);
} else {
/* Determine how many bytes to process this time */
chunk = min(bytes, NUM_CDRAM);
queues = chunk;
bytes -= chunk;
/* Fill CDRAMs and TXRAMS */
for (i = 0; i < chunk; i++) {
writel(cdr, priv->mspi + MSPI_CDRAM_REG + 4 * i);
writel(tx ? tx[i] : 0xff, priv->mspi + MSPI_TX_REG + 8 * i);
}
}
/* Setup queue pointers */
writel(0, priv->mspi + MSPI_NEWQP_REG);
writel(queues - 1, priv->mspi + MSPI_ENDQP_REG);
/* Deassert CS if requested and it's the last transfer */
if (bytes == 0 && (flags & SPI_XFER_END))
clrbits_le32(priv->mspi + MSPI_CDRAM_REG + ((queues - 1) << 2), CDRAM_CONT);
/* Kick off */
writel(0, priv->mspi + MSPI_STATUS_REG);
if (bytes == 0 && (flags & SPI_XFER_END))
writel(MSPI_SPE, priv->mspi + MSPI_SPCR2_REG);
else
writel(MSPI_SPE | MSPI_CONT_AFTER_CMD,
priv->mspi + MSPI_SPCR2_REG);
ret = readl_poll_timeout(priv->mspi + MSPI_STATUS_REG, val, (val & 1),
BUSY_TIMEOUT_US);
if (ret) {
printf("%s: Failed to disable bspi, device busy\n", __func__);
return ret;
}
/* Read data out */
if (rx) {
if (use_16bits) {
for (i = 0; i < chunk; i++)
rx[i] = readl(priv->mspi + MSPI_RX_REG + 4 * i) & 0xff;
} else {
for (i = 0; i < chunk; i++)
rx[i] = readl(priv->mspi + MSPI_RX_REG + 8 * i + 4) & 0xff;
}
}
/* Advance pointers */
if (tx)
tx += chunk;
if (rx)
rx += chunk;
}
return 0;
}
static int mspi_xfer(struct udevice *dev, uint bitlen, const void *dout, void *din, ulong flags)
{
struct udevice *bus = dev_get_parent(dev);
struct bcmspi_priv *priv = dev_get_priv(bus);
uint bytes;
int ret = 0;
/* we can only transfer multiples of 8 bits */
if (bitlen % 8)
return -EPROTONOSUPPORT;
bytes = bitlen / 8;
if (flags & SPI_XFER_BEGIN) {
/* Switch to MSPI */
ret = bspi_disable(priv);
if (ret)
return ret;
}
/* MSPI: Transfer */
if (bytes)
ret = mspi_exec(priv, bytes, dout, din, flags);
if (flags & SPI_XFER_END) {
/* Switch back to BSPI */
ret = bspi_enable(priv);
if (ret)
return ret;
}
return ret;
}
/* iProc interface */
static int iproc_qspi_set_speed(struct udevice *bus, uint speed)
{
struct bcmspi_priv *priv = dev_get_priv(bus);
uint spbr;
/* MSPI: SCK configuration */
spbr = (QSPI_AXI_CLK - 1) / (2 * speed) + 1;
writel(max(min(spbr, SPBR_MAX), SPBR_MIN), priv->mspi + MSPI_SPCR0_LSB_REG);
return 0;
}
static int iproc_qspi_set_mode(struct udevice *bus, uint mode)
{
struct bcmspi_priv *priv = dev_get_priv(bus);
/* MSPI: set master bit and mode */
writel(MSPI_MSTR /* Master */ | (mode & 3), priv->mspi + MSPI_SPCR0_MSB_REG);
return 0;
}
static int iproc_qspi_claim_bus(struct udevice *dev)
{
/* Nothing to do */
return 0;
}
static int iproc_qspi_release_bus(struct udevice *dev)
{
struct udevice *bus = dev_get_parent(dev);
struct bcmspi_priv *priv = dev_get_priv(bus);
/* Make sure no operation is in progress */
writel(0, priv->mspi + MSPI_SPCR2_REG);
udelay(BUSY_DELAY_US);
return 0;
}
static int iproc_qspi_of_to_plat(struct udevice *bus)
{
struct bcmspi_priv *priv = dev_get_priv(bus);
priv->bspi = dev_read_addr_name(bus, "bspi");
if (IS_ERR((void *)priv->bspi)) {
printf("%s: Failed to get bspi base address\n", __func__);
return PTR_ERR((void *)priv->bspi);
}
priv->bspi_raf = dev_read_addr_name(bus, "bspi_raf");
if (IS_ERR((void *)priv->bspi_raf)) {
printf("%s: Failed to get bspi_raf base address\n", __func__);
return PTR_ERR((void *)priv->bspi_raf);
}
priv->mspi = dev_read_addr_name(bus, "mspi");
if (IS_ERR((void *)priv->mspi)) {
printf("%s: Failed to get mspi base address\n", __func__);
return PTR_ERR((void *)priv->mspi);
}
return 0;
}
static int iproc_qspi_probe(struct udevice *bus)
{
struct bcmspi_priv *priv = dev_get_priv(bus);
/* configure mspi */
writel(0, priv->mspi + MSPI_SPCR1_LSB_REG);
writel(0, priv->mspi + MSPI_SPCR1_MSB_REG);
writel(0, priv->mspi + MSPI_NEWQP_REG);
writel(0, priv->mspi + MSPI_ENDQP_REG);
writel(0, priv->mspi + MSPI_SPCR2_REG);
/* configure bspi */
bspi_enable(priv);
return 0;
}
static const struct dm_spi_ops iproc_qspi_ops = {
.claim_bus = iproc_qspi_claim_bus,
.release_bus = iproc_qspi_release_bus,
.xfer = mspi_xfer,
.set_speed = iproc_qspi_set_speed,
.set_mode = iproc_qspi_set_mode,
.mem_ops = &bspi_mem_ops,
};
static const struct udevice_id iproc_qspi_ids[] = {
{ .compatible = "brcm,iproc-qspi" },
{ }
};
U_BOOT_DRIVER(iproc_qspi) = {
.name = "iproc_qspi",
.id = UCLASS_SPI,
.of_match = iproc_qspi_ids,
.ops = &iproc_qspi_ops,
.of_to_plat = iproc_qspi_of_to_plat,
.priv_auto = sizeof(struct bcmspi_priv),
.probe = iproc_qspi_probe,
};

View File

@ -267,6 +267,13 @@ config WDT_SBSA
In the single stage mode, when the timeout is reached, your system
will be reset by WS1. The first signal (WS0) is ignored.
config WDT_SL28CPLD
bool "sl28cpld watchdog timer support"
depends on WDT && SL28CPLD
help
Enable support for the watchdog timer in the Kontron sl28cpld
management controller.
config WDT_SP805
bool "SP805 watchdog timer support"
depends on WDT

View File

@ -35,6 +35,7 @@ obj-$(CONFIG_WDT_OCTEONTX) += octeontx_wdt.o
obj-$(CONFIG_WDT_OMAP3) += omap_wdt.o
obj-$(CONFIG_WDT_SBSA) += sbsa_gwdt.o
obj-$(CONFIG_WDT_K3_RTI) += rti_wdt.o
obj-$(CONFIG_WDT_SL28CPLD) += sl28cpld-wdt.o
obj-$(CONFIG_WDT_SP805) += sp805_wdt.o
obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o
obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o

View File

@ -58,13 +58,11 @@ static void counter_disable(struct a37xx_wdt *priv, int id)
clrbits_le32(priv->reg + CNTR_CTRL(id), CNTR_CTRL_ENABLE);
}
static int init_counter(struct a37xx_wdt *priv, int id, u32 mode, u32 trig_src)
static void init_counter(struct a37xx_wdt *priv, int id, u32 mode, u32 trig_src)
{
u32 reg;
reg = readl(priv->reg + CNTR_CTRL(id));
if (reg & CNTR_CTRL_ACTIVE)
return -EBUSY;
reg &= ~(CNTR_CTRL_MODE_MASK | CNTR_CTRL_PRESCALE_MASK |
CNTR_CTRL_TRIG_SRC_MASK);
@ -79,8 +77,6 @@ static int init_counter(struct a37xx_wdt *priv, int id, u32 mode, u32 trig_src)
reg |= trig_src;
writel(reg, priv->reg + CNTR_CTRL(id));
return 0;
}
static int a37xx_wdt_reset(struct udevice *dev)
@ -116,16 +112,9 @@ static int a37xx_wdt_expire_now(struct udevice *dev, ulong flags)
static int a37xx_wdt_start(struct udevice *dev, u64 ms, ulong flags)
{
struct a37xx_wdt *priv = dev_get_priv(dev);
int err;
err = init_counter(priv, 0, CNTR_CTRL_MODE_ONESHOT, 0);
if (err < 0)
return err;
err = init_counter(priv, 1, CNTR_CTRL_MODE_HWSIG,
CNTR_CTRL_TRIG_SRC_PREV_CNTR);
if (err < 0)
return err;
init_counter(priv, 0, CNTR_CTRL_MODE_ONESHOT, 0);
init_counter(priv, 1, CNTR_CTRL_MODE_HWSIG, CNTR_CTRL_TRIG_SRC_PREV_CNTR);
priv->timeout = ms * priv->clk_rate / 1000 / CNTR_CTRL_PRESCALE_MIN;

View File

@ -41,7 +41,7 @@
struct rti_wdt_priv {
phys_addr_t regs;
unsigned int clk_khz;
unsigned int clk_hz;
};
#ifdef CONFIG_WDT_K3_RTI_LOAD_FW
@ -139,7 +139,7 @@ static int rti_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
if (ret < 0)
return ret;
timer_margin = timeout_ms * priv->clk_khz / 1000;
timer_margin = timeout_ms * priv->clk_hz / 1000;
timer_margin >>= WDT_PRELOAD_SHIFT;
if (timer_margin > WDT_PRELOAD_MAX)
timer_margin = WDT_PRELOAD_MAX;
@ -185,7 +185,15 @@ static int rti_wdt_probe(struct udevice *dev)
if (ret)
return ret;
priv->clk_khz = clk_get_rate(&clk);
priv->clk_hz = clk_get_rate(&clk);
/*
* If watchdog is running at 32k clock, it is not accurate.
* Adjust frequency down in this case so that it does not expire
* earlier than expected.
*/
if (priv->clk_hz < 32768)
priv->clk_hz = priv->clk_hz * 9 / 10;
return 0;
}

View File

@ -0,0 +1,109 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Watchdog driver for the sl28cpld
*
* Copyright (c) 2021 Michael Walle <michael@walle.cc>
*/
#include <common.h>
#include <dm.h>
#include <wdt.h>
#include <sl28cpld.h>
#include <div64.h>
#define SL28CPLD_WDT_CTRL 0x00
#define WDT_CTRL_EN0 BIT(0)
#define WDT_CTRL_EN1 BIT(1)
#define WDT_CTRL_EN_MASK GENMASK(1, 0)
#define WDT_CTRL_LOCK BIT(2)
#define WDT_CTRL_ASSERT_SYS_RESET BIT(6)
#define WDT_CTRL_ASSERT_WDT_TIMEOUT BIT(7)
#define SL28CPLD_WDT_TIMEOUT 0x01
#define SL28CPLD_WDT_KICK 0x02
#define WDT_KICK_VALUE 0x6b
static int sl28cpld_wdt_reset(struct udevice *dev)
{
return sl28cpld_write(dev, SL28CPLD_WDT_KICK, WDT_KICK_VALUE);
}
static int sl28cpld_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
{
int ret, val;
val = sl28cpld_read(dev, SL28CPLD_WDT_CTRL);
if (val < 0)
return val;
/* (1) disable watchdog */
val &= ~WDT_CTRL_EN_MASK;
ret = sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val);
if (ret)
return ret;
/* (2) set timeout */
ret = sl28cpld_write(dev, SL28CPLD_WDT_TIMEOUT, lldiv(timeout, 1000));
if (ret)
return ret;
/* (3) kick it, will reset timer to the timeout value */
ret = sl28cpld_wdt_reset(dev);
if (ret)
return ret;
/* (4) enable either recovery or normal one */
if (flags & BIT(0))
val |= WDT_CTRL_EN1;
else
val |= WDT_CTRL_EN0;
if (flags & BIT(1))
val |= WDT_CTRL_LOCK;
if (flags & BIT(2))
val &= ~WDT_CTRL_ASSERT_SYS_RESET;
else
val |= WDT_CTRL_ASSERT_SYS_RESET;
if (flags & BIT(3))
val |= WDT_CTRL_ASSERT_WDT_TIMEOUT;
else
val &= ~WDT_CTRL_ASSERT_WDT_TIMEOUT;
return sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val);
}
static int sl28cpld_wdt_stop(struct udevice *dev)
{
int val;
val = sl28cpld_read(dev, SL28CPLD_WDT_CTRL);
if (val < 0)
return val;
return sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val & ~WDT_CTRL_EN_MASK);
}
static int sl28cpld_wdt_expire_now(struct udevice *dev, ulong flags)
{
return sl28cpld_wdt_start(dev, 0, flags);
}
static const struct wdt_ops sl28cpld_wdt_ops = {
.start = sl28cpld_wdt_start,
.reset = sl28cpld_wdt_reset,
.stop = sl28cpld_wdt_stop,
.expire_now = sl28cpld_wdt_expire_now,
};
static const struct udevice_id sl28cpld_wdt_ids[] = {
{ .compatible = "kontron,sl28cpld-wdt", },
{}
};
U_BOOT_DRIVER(sl28cpld_wdt) = {
.name = "sl28cpld-wdt",
.id = UCLASS_WDT,
.of_match = sl28cpld_wdt_ids,
.ops = &sl28cpld_wdt_ops,
};

View File

@ -36,6 +36,8 @@ struct wdt_priv {
ulong next_reset;
/* Whether watchdog_start() has been called on the device. */
bool running;
/* No autostart */
bool noautostart;
};
static void init_watchdog_dev(struct udevice *dev)
@ -52,7 +54,7 @@ static void init_watchdog_dev(struct udevice *dev)
dev->name);
}
if (!IS_ENABLED(CONFIG_WATCHDOG_AUTOSTART)) {
if (!IS_ENABLED(CONFIG_WATCHDOG_AUTOSTART) || priv->noautostart) {
printf("WDT: Not starting %s\n", dev->name);
return;
}
@ -256,16 +258,19 @@ static int wdt_pre_probe(struct udevice *dev)
* indicated by a hw_margin_ms property.
*/
ulong reset_period = 1000;
bool noautostart = false;
struct wdt_priv *priv;
if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) {
timeout = dev_read_u32_default(dev, "timeout-sec", timeout);
reset_period = dev_read_u32_default(dev, "hw_margin_ms",
4 * reset_period) / 4;
noautostart = dev_read_bool(dev, "u-boot,noautostart");
}
priv = dev_get_uclass_priv(dev);
priv->timeout = timeout;
priv->reset_period = reset_period;
priv->noautostart = noautostart;
/*
* Pretend this device was last reset "long" ago so the first
* watchdog_reset will actually call its ->reset method.

7
env/Kconfig vendored
View File

@ -320,6 +320,7 @@ config ENV_IS_IN_SPI_FLASH
default y if NORTHBRIDGE_INTEL_IVYBRIDGE
default y if INTEL_QUARK
default y if INTEL_QUEENSBAY
default y if ARCH_SUNXI
help
Define this if you have a SPI Flash memory device which you
want to use for the environment.
@ -536,7 +537,7 @@ config ENV_OFFSET
ENV_IS_IN_SPI_FLASH
default 0x3f8000 if ARCH_ROCKCHIP && ENV_IS_IN_MMC
default 0x140000 if ARCH_ROCKCHIP && ENV_IS_IN_SPI_FLASH
default 0x88000 if ARCH_SUNXI
default 0xF0000 if ARCH_SUNXI
default 0xE0000 if ARCH_ZYNQ
default 0x1E00000 if ARCH_ZYNQMP
default 0x7F40000 if ARCH_VERSAL
@ -559,7 +560,8 @@ config ENV_OFFSET_REDUND
config ENV_SIZE
hex "Environment Size"
default 0x40000 if ENV_IS_IN_SPI_FLASH && ARCH_ZYNQMP
default 0x20000 if ARCH_SUNXI || ARCH_ZYNQ || ARCH_OMAP2PLUS || ARCH_AT91
default 0x20000 if ARCH_ZYNQ || ARCH_OMAP2PLUS || ARCH_AT91
default 0x10000 if ARCH_SUNXI
default 0x8000 if ARCH_ROCKCHIP && ENV_IS_IN_MMC
default 0x2000 if ARCH_ROCKCHIP && ENV_IS_IN_SPI_FLASH
default 0x8000 if ARCH_ZYNQMP || ARCH_VERSAL
@ -575,6 +577,7 @@ config ENV_SECT_SIZE
default 0x40000 if ARCH_ZYNQMP || ARCH_VERSAL
default 0x20000 if ARCH_ZYNQ || ARCH_OMAP2PLUS || ARCH_AT91
default 0x20000 if MICROBLAZE && ENV_IS_IN_SPI_FLASH
default 0x10000 if ARCH_SUNXI && ENV_IS_IN_SPI_FLASH
help
Size of the sector containing the environment.

View File

@ -243,12 +243,36 @@
"run distro_bootcmd;run sd2_bootcmd;" \
"env exists secureboot && esbc_halt;"
#ifdef CONFIG_CMD_USB
#define BOOT_TARGET_DEVICES_USB(func) func(USB, usb, 0)
#else
#define BOOT_TARGET_DEVICES_USB(func)
#endif
#ifdef CONFIG_MMC
#define BOOT_TARGET_DEVICES_MMC(func, instance) func(MMC, mmc, instance)
#else
#define BOOT_TARGET_DEVICES_MMC(func)
#endif
#ifdef CONFIG_SCSI
#define BOOT_TARGET_DEVICES_SCSI(func) func(SCSI, scsi, 0)
#else
#define BOOT_TARGET_DEVICES_SCSI(func)
#endif
#ifdef CONFIG_CMD_DHCP
#define BOOT_TARGET_DEVICES_DHCP(func) func(DHCP, dhcp, na)
#else
#define BOOT_TARGET_DEVICES_DHCP(func)
#endif
#define BOOT_TARGET_DEVICES(func) \
func(USB, usb, 0) \
func(MMC, mmc, 0) \
func(MMC, mmc, 1) \
func(SCSI, scsi, 0) \
func(DHCP, dhcp, na)
BOOT_TARGET_DEVICES_USB(func) \
BOOT_TARGET_DEVICES_MMC(func, 0) \
BOOT_TARGET_DEVICES_MMC(func, 1) \
BOOT_TARGET_DEVICES_SCSI(func) \
BOOT_TARGET_DEVICES_DHCP(func)
#include <config_distro_bootcmd.h>
#endif /* __LX2_COMMON_H */

View File

@ -55,7 +55,7 @@
"do;" \
"setenv overlaystring ${overlaystring}'#'${overlay};" \
"done;\0" \
"run_fit=bootm ${addr_fit}#${fdtfile}${overlaystring}\0" \
"run_fit=bootm ${addr_fit}#conf-${fdtfile}${overlaystring}\0" \
/*
* DDR information. If the CONFIG_NR_DRAM_BANKS is not defined,

View File

@ -342,7 +342,7 @@ struct efi_open_protocol_info_item {
*/
struct efi_handler {
struct list_head link;
const efi_guid_t *guid;
const efi_guid_t guid;
void *protocol_interface;
struct list_head open_infos;
};

16
include/sl28cpld.h Normal file
View File

@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2021 Michael Walle <michael@walle.cc>
*/
#ifndef __SL28CPLD_H
#define __SL28CPLD_H
#define SL28CPLD_VERSION 0x03
int sl28cpld_read(struct udevice *dev, uint offset);
int sl28cpld_write(struct udevice *dev, uint offset, uint8_t value);
int sl28cpld_update(struct udevice *dev, uint offset, uint8_t clear,
uint8_t set);
#endif

View File

@ -552,7 +552,7 @@ efi_status_t efi_search_protocol(const efi_handle_t handle,
struct efi_handler *protocol;
protocol = list_entry(lhandle, struct efi_handler, link);
if (!guidcmp(protocol->guid, protocol_guid)) {
if (!guidcmp(&protocol->guid, protocol_guid)) {
if (handler)
*handler = protocol;
return EFI_SUCCESS;
@ -604,7 +604,7 @@ efi_status_t efi_remove_all_protocols(const efi_handle_t handle)
list_for_each_entry_safe(protocol, pos, &efiobj->protocols, link) {
efi_status_t ret;
ret = efi_remove_protocol(handle, protocol->guid,
ret = efi_remove_protocol(handle, &protocol->guid,
protocol->protocol_interface);
if (ret != EFI_SUCCESS)
return ret;
@ -1131,7 +1131,7 @@ efi_status_t efi_add_protocol(const efi_handle_t handle,
handler = calloc(1, sizeof(struct efi_handler));
if (!handler)
return EFI_OUT_OF_RESOURCES;
handler->guid = protocol;
memcpy((void *)&handler->guid, protocol, sizeof(efi_guid_t));
handler->protocol_interface = protocol_interface;
INIT_LIST_HEAD(&handler->open_infos);
list_add_tail(&handler->link, &efiobj->protocols);
@ -1227,7 +1227,7 @@ static efi_status_t efi_get_drivers(efi_handle_t handle,
/* Count all driver associations */
list_for_each_entry(handler, &handle->protocols, link) {
if (protocol && guidcmp(handler->guid, protocol))
if (protocol && guidcmp(&handler->guid, protocol))
continue;
list_for_each_entry(item, &handler->open_infos, link) {
if (item->info.attributes &
@ -1249,7 +1249,7 @@ static efi_status_t efi_get_drivers(efi_handle_t handle,
return EFI_OUT_OF_RESOURCES;
/* Collect unique driver handles */
list_for_each_entry(handler, &handle->protocols, link) {
if (protocol && guidcmp(handler->guid, protocol))
if (protocol && guidcmp(&handler->guid, protocol))
continue;
list_for_each_entry(item, &handler->open_infos, link) {
if (item->info.attributes &
@ -2446,7 +2446,7 @@ static efi_status_t EFIAPI efi_protocols_per_handle(
protocol = list_entry(protocol_handle,
struct efi_handler, link);
(*protocol_buffer)[j] = (void *)protocol->guid;
(*protocol_buffer)[j] = (void *)&protocol->guid;
++j;
}
}
@ -3094,7 +3094,7 @@ close_next:
(efi_handle_t)image_obj)
continue;
r = EFI_CALL(efi_close_protocol
(efiobj, protocol->guid,
(efiobj, &protocol->guid,
info->info.agent_handle,
info->info.controller_handle
));

View File

@ -91,7 +91,7 @@ void efi_print_image_infos(void *pc)
list_for_each_entry(efiobj, &efi_obj_list, link) {
list_for_each_entry(handler, &efiobj->protocols, link) {
if (!guidcmp(handler->guid, &efi_guid_loaded_image)) {
if (!guidcmp(&handler->guid, &efi_guid_loaded_image)) {
efi_print_image_info(
(struct efi_loaded_image_obj *)efiobj,
handler->protocol_interface, pc);

View File

@ -383,12 +383,11 @@ static int rsa_sign_with_key(EVP_PKEY *pkey, struct padding_algo *padding_algo,
goto err_alloc;
}
context = EVP_MD_CTX_create();
context = EVP_MD_CTX_new();
if (!context) {
ret = rsa_err("EVP context creation failed");
goto err_create;
}
EVP_MD_CTX_init(context);
ckey = EVP_PKEY_CTX_new(pkey, NULL);
if (!ckey) {
@ -425,8 +424,7 @@ static int rsa_sign_with_key(EVP_PKEY *pkey, struct padding_algo *padding_algo,
goto err_sign;
}
EVP_MD_CTX_reset(context);
EVP_MD_CTX_destroy(context);
EVP_MD_CTX_free(context);
debug("Got signature: %zu bytes, expected %d\n", size, EVP_PKEY_size(pkey));
*sigp = sig;
@ -435,7 +433,7 @@ static int rsa_sign_with_key(EVP_PKEY *pkey, struct padding_algo *padding_algo,
return 0;
err_sign:
EVP_MD_CTX_destroy(context);
EVP_MD_CTX_free(context);
err_create:
free(sig);
err_alloc:

View File

@ -196,6 +196,9 @@ hostprogs-$(CONFIG_EXYNOS5250) += mkexynosspl
hostprogs-$(CONFIG_EXYNOS5420) += mkexynosspl
HOSTCFLAGS_mkexynosspl.o := -pedantic
HOSTCFLAGS_kwboot.o += -pthread
HOSTLDLIBS_kwboot += -pthread -ltinfo
ifdtool-objs := $(LIBFDT_OBJS) ifdtool.o
hostprogs-$(CONFIG_X86) += ifdtool

View File

@ -1,15 +1,40 @@
/*
* Boot a Marvell SoC, with Xmodem over UART0.
* supports Kirkwood, Dove, Armada 370, Armada XP, Armada 375, Armada 38x and
* Armada 39x
* supports Kirkwood, Dove, Avanta, Armada 370, Armada XP, Armada 375,
* Armada 38x and Armada 39x.
*
* (c) 2012 Daniel Stodden <daniel.stodden@gmail.com>
* (c) 2021 Pali Rohár <pali@kernel.org>
* (c) 2021 Marek Behún <marek.behun@nic.cz>
*
* References: marvell.com, "88F6180, 88F6190, 88F6192, and 88F6281
* Integrated Controller: Functional Specifications" December 2,
* 2008. Chapter 24.2 "BootROM Firmware".
* References:
* - "88F6180, 88F6190, 88F6192, and 88F6281: Integrated Controller: Functional
* Specifications" December 2, 2008. Chapter 24.2 "BootROM Firmware".
* https://web.archive.org/web/20130730091033/https://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf
* - "88AP510: High-Performance SoC with Integrated CPU, 2D/3D Graphics
* Processor, and High-Definition Video Decoder: Functional Specifications"
* August 3, 2011. Chapter 5 "BootROM Firmware"
* https://web.archive.org/web/20120130172443/https://www.marvell.com/application-processors/armada-500/assets/Armada-510-Functional-Spec.pdf
* - "88F6710, 88F6707, and 88F6W11: ARMADA(R) 370 SoC: Functional Specifications"
* May 26, 2014. Chapter 6 "BootROM Firmware".
* https://web.archive.org/web/20140617183701/https://www.marvell.com/embedded-processors/armada-300/assets/ARMADA370-FunctionalSpec-datasheet.pdf
* - "MV78230, MV78260, and MV78460: ARMADA(R) XP Family of Highly Integrated
* Multi-Core ARMv7 Based SoC Processors: Functional Specifications"
* May 29, 2014. Chapter 6 "BootROM Firmware".
* https://web.archive.org/web/20180829171131/https://www.marvell.com/embedded-processors/armada-xp/assets/ARMADA-XP-Functional-SpecDatasheet.pdf
* - "ARMADA(R) 375 Value-Performance Dual Core CPU System on Chip: Functional
* Specifications" Doc. No. MV-S109377-00, Rev. A. September 18, 2013.
* Chapter 7 "Boot Sequence"
* CONFIDENTIAL, no public documentation available
* - "88F6810, 88F6811, 88F6821, 88F6W21, 88F6820, and 88F6828: ARMADA(R) 38x
* Family High-Performance Single/Dual CPU System on Chip: Functional
* Specifications" Doc. No. MV-S109094-00, Rev. C. August 2, 2015.
* Chapter 7 "Boot Flow"
* CONFIDENTIAL, no public documentation available
* - "88F6920, 88F6925 and 88F6928: ARMADA(R) 39x High-Performance Dual Core CPU
* System on Chip Functional Specifications" Doc. No. MV-S109896-00, Rev. B.
* December 22, 2015. Chapter 7 "Boot Flow"
* CONFIDENTIAL, no public documentation available
*/
#include "kwbimage.h"
@ -28,6 +53,7 @@
#include <stdint.h>
#include <time.h>
#include <sys/stat.h>
#include <pthread.h>
#ifdef __linux__
#include "termios_linux.h"
@ -35,6 +61,13 @@
#include <termios.h>
#endif
/*
* These functions are in <term.h> header file, but this header file conflicts
* with "termios_linux.h" header file. So declare these functions manually.
*/
extern int setupterm(const char *, int, int *);
extern char *tigetstr(const char *);
/*
* Marvell BootROM UART Sensing
*/
@ -48,11 +81,9 @@ static unsigned char kwboot_msg_debug[] = {
};
/* Defines known to work on Kirkwood */
#define KWBOOT_MSG_REQ_DELAY 10 /* ms */
#define KWBOOT_MSG_RSP_TIMEO 50 /* ms */
/* Defines known to work on Armada XP */
#define KWBOOT_MSG_REQ_DELAY_AXP 1000 /* ms */
#define KWBOOT_MSG_RSP_TIMEO_AXP 1000 /* ms */
/*
@ -285,7 +316,6 @@ static const char kwb_baud_magic[16] = "$baudratechange";
static int kwboot_verbose;
static int msg_req_delay = KWBOOT_MSG_REQ_DELAY;
static int msg_rsp_timeo = KWBOOT_MSG_RSP_TIMEO;
static int blk_rsp_timeo = KWBOOT_BLK_RSP_TIMEO;
@ -720,42 +750,120 @@ out:
return rc;
}
static int
kwboot_bootmsg(int tty, void *msg)
static void *
kwboot_msg_write_handler(void *arg)
{
struct kwboot_block block;
int rc;
char c;
int count;
int tty = *(int *)((void **)arg)[0];
const void *msg = ((void **)arg)[1];
int rsp_timeo = msg_rsp_timeo;
int i, dummy_oldtype;
if (msg == NULL)
kwboot_printv("Please reboot the target into UART boot mode...");
else
kwboot_printv("Sending boot message. Please reboot the target...");
/* allow to cancel this thread at any time */
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &dummy_oldtype);
do {
rc = tcflush(tty, TCIOFLUSH);
if (rc)
break;
for (count = 0; count < 128; count++) {
rc = kwboot_tty_send(tty, msg, 8, 0);
if (rc) {
usleep(msg_req_delay * 1000);
continue;
while (1) {
/* write 128 samples of message pattern into the output queue without waiting */
for (i = 0; i < 128; i++) {
if (kwboot_tty_send(tty, msg, 8, 1) < 0) {
perror("\nFailed to send message pattern");
exit(1);
}
}
/* wait until output queue is transmitted and then make pause */
if (tcdrain(tty) < 0) {
perror("\nFailed to send message pattern");
exit(1);
}
/* BootROM requires pause on UART after it detects message pattern */
usleep(rsp_timeo * 1000);
}
}
rc = kwboot_tty_recv(tty, &c, 1, msg_rsp_timeo);
static int
kwboot_msg_start_thread(pthread_t *thread, int *tty, void *msg)
{
void *arg[2];
int rc;
arg[0] = tty;
arg[1] = msg;
rc = pthread_create(thread, NULL, kwboot_msg_write_handler, arg);
if (rc) {
errno = rc;
return -1;
}
return 0;
}
static int
kwboot_msg_stop_thread(pthread_t thread)
{
int rc;
rc = pthread_cancel(thread);
if (rc) {
errno = rc;
return -1;
}
rc = pthread_join(thread, NULL);
if (rc) {
errno = rc;
return -1;
}
return 0;
}
static int
kwboot_bootmsg(int tty)
{
struct kwboot_block block;
pthread_t write_thread;
int rc, err;
char c;
/* flush input and output queue */
tcflush(tty, TCIOFLUSH);
rc = kwboot_msg_start_thread(&write_thread, &tty, kwboot_msg_boot);
if (rc) {
perror("Failed to start write thread");
return rc;
}
kwboot_printv("Sending boot message. Please reboot the target...");
err = 0;
while (1) {
kwboot_spinner();
} while (rc || c != NAK);
rc = kwboot_tty_recv(tty, &c, 1, msg_rsp_timeo);
if (rc && errno == ETIMEDOUT) {
continue;
} else if (rc) {
err = errno;
break;
}
if (c == NAK)
break;
}
kwboot_printv("\n");
if (rc)
rc = kwboot_msg_stop_thread(write_thread);
if (rc) {
perror("Failed to stop write thread");
return rc;
}
if (err) {
errno = err;
perror("Failed to read response for boot message pattern");
return -1;
}
/*
* At this stage we have sent more boot message patterns and BootROM
@ -772,11 +880,19 @@ kwboot_bootmsg(int tty, void *msg)
*/
/* flush output queue with remaining boot message patterns */
tcflush(tty, TCOFLUSH);
rc = tcflush(tty, TCOFLUSH);
if (rc) {
perror("Failed to flush output queue");
return rc;
}
/* send one xmodem packet with 0xff bytes to force BootROM to re-sync */
memset(&block, 0xff, sizeof(block));
kwboot_tty_send(tty, &block, sizeof(block), 0);
rc = kwboot_tty_send(tty, &block, sizeof(block), 0);
if (rc) {
perror("Failed to send sync sequence");
return rc;
}
/*
* Sending 132 bytes via 115200B/8-N-1 takes 11.45 ms, reading 132 bytes
@ -785,40 +901,151 @@ kwboot_bootmsg(int tty, void *msg)
usleep(30 * 1000);
/* flush remaining NAK replies from input queue */
tcflush(tty, TCIFLUSH);
rc = tcflush(tty, TCIFLUSH);
if (rc) {
perror("Failed to flush input queue");
return rc;
}
return 0;
}
static int
kwboot_debugmsg(int tty, void *msg)
kwboot_debugmsg(int tty)
{
int rc;
unsigned char buf[8192];
pthread_t write_thread;
int rc, err, i, pos;
size_t off;
/* flush input and output queue */
tcflush(tty, TCIOFLUSH);
rc = kwboot_msg_start_thread(&write_thread, &tty, kwboot_msg_debug);
if (rc) {
perror("Failed to start write thread");
return rc;
}
kwboot_printv("Sending debug message. Please reboot the target...");
kwboot_spinner();
do {
char buf[16];
rc = tcflush(tty, TCIOFLUSH);
if (rc)
break;
rc = kwboot_tty_send(tty, msg, 8, 0);
if (rc) {
usleep(msg_req_delay * 1000);
err = 0;
off = 0;
while (1) {
/* Read immediately all bytes in queue without waiting */
rc = read(tty, buf + off, sizeof(buf) - off);
if ((rc < 0 && errno == EINTR) || rc == 0) {
continue;
} else if (rc < 0) {
err = errno;
break;
}
rc = kwboot_tty_recv(tty, buf, 16, msg_rsp_timeo);
off += rc - 1;
kwboot_spinner();
} while (rc);
/*
* Check if we received at least 4 debug message patterns
* (console echo from BootROM) in cyclic buffer
*/
for (pos = 0; pos < sizeof(kwboot_msg_debug); pos++)
if (buf[off] == kwboot_msg_debug[(pos + off) % sizeof(kwboot_msg_debug)])
break;
for (i = off; i >= 0; i--)
if (buf[i] != kwboot_msg_debug[(pos + i) % sizeof(kwboot_msg_debug)])
break;
off -= i;
if (off >= 4 * sizeof(kwboot_msg_debug))
break;
/* If not move valid suffix from end of the buffer to the beginning of buffer */
memmove(buf, buf + i + 1, off);
}
kwboot_printv("\n");
return rc;
rc = kwboot_msg_stop_thread(write_thread);
if (rc) {
perror("Failed to stop write thread");
return rc;
}
if (err) {
errno = err;
perror("Failed to read response for debug message pattern");
return -1;
}
/* flush output queue with remaining debug message patterns */
rc = tcflush(tty, TCOFLUSH);
if (rc) {
perror("Failed to flush output queue");
return rc;
}
kwboot_printv("Clearing input buffer...\n");
/*
* Wait until BootROM transmit all remaining echo characters.
* Experimentally it was measured that for Armada 385 BootROM
* it is required to wait at least 0.415s. So wait 0.5s.
*/
usleep(500 * 1000);
/*
* In off variable is stored number of characters received after the
* successful detection of echo reply. So these characters are console
* echo for other following debug message patterns. BootROM may have in
* its output queue other echo characters which were being transmitting
* before above sleep call. So read remaining number of echo characters
* sent by the BootROM now.
*/
while ((rc = kwboot_tty_recv(tty, &buf[0], 1, 0)) == 0)
off++;
if (errno != ETIMEDOUT) {
perror("Failed to read response");
return rc;
}
/*
* Clear every echo character set by the BootROM by backspace byte.
* This is required prior writing any command to the BootROM debug
* because BootROM command line buffer has limited size. If length
* of the command is larger than buffer size then it looks like
* that Armada 385 BootROM crashes after sending ENTER. So erase it.
* Experimentally it was measured that for Armada 385 BootROM it is
* required to send at least 3 backspace bytes for one echo character.
* This is unknown why. But lets do it.
*/
off *= 3;
memset(buf, '\x08', sizeof(buf));
while (off > sizeof(buf)) {
rc = kwboot_tty_send(tty, buf, sizeof(buf), 1);
if (rc) {
perror("Failed to send clear sequence");
return rc;
}
off -= sizeof(buf);
}
rc = kwboot_tty_send(tty, buf, off, 0);
if (rc) {
perror("Failed to send clear sequence");
return rc;
}
usleep(msg_rsp_timeo * 1000);
rc = tcflush(tty, TCIFLUSH);
if (rc) {
perror("Failed to flush input queue");
return rc;
}
return 0;
}
static size_t
@ -1181,37 +1408,84 @@ kwboot_xmodem(int tty, const void *_img, size_t size, int baudrate)
}
static int
kwboot_term_pipe(int in, int out, const char *quit, int *s)
kwboot_term_pipe(int in, int out, const char *quit, int *s, const char *kbs, int *k)
{
char buf[128];
ssize_t nin;
ssize_t nin, noff;
nin = read(in, buf, sizeof(buf));
if (nin <= 0)
return -1;
if (quit) {
noff = 0;
if (quit || kbs) {
int i;
for (i = 0; i < nin; i++) {
if (buf[i] == quit[*s]) {
if ((quit || kbs) &&
(!quit || buf[i] != quit[*s]) &&
(!kbs || buf[i] != kbs[*k])) {
const char *prefix;
int plen;
if (quit && kbs) {
prefix = (*s >= *k) ? quit : kbs;
plen = (*s >= *k) ? *s : *k;
} else if (quit) {
prefix = quit;
plen = *s;
} else {
prefix = kbs;
plen = *k;
}
if (plen > i && kwboot_write(out, prefix, plen - i) < 0)
return -1;
}
if (quit && buf[i] == quit[*s]) {
(*s)++;
if (!quit[*s]) {
nin = i - *s;
nin = (i > *s) ? (i - *s) : 0;
break;
}
} else {
if (*s > i && kwboot_write(out, quit, *s - i) < 0)
return -1;
} else if (quit) {
*s = 0;
}
if (kbs && buf[i] == kbs[*k]) {
(*k)++;
if (!kbs[*k]) {
if (i > *k + noff &&
kwboot_write(out, buf + noff, i - *k - noff) < 0)
return -1;
/*
* Replace backspace key by '\b' (0x08)
* byte which is the only recognized
* backspace byte by Marvell BootROM.
*/
if (write(out, "\x08", 1) < 0)
return -1;
noff = i + 1;
*k = 0;
}
} else if (kbs) {
*k = 0;
}
}
if (i == nin)
nin -= *s;
if (i == nin) {
i = 0;
if (quit && i < *s)
i = *s;
if (kbs && i < *k)
i = *k;
nin -= (nin > i) ? i : nin;
}
}
if (kwboot_write(out, buf, nin) < 0)
if (nin > noff && kwboot_write(out, buf + noff, nin - noff) < 0)
return -1;
return 0;
@ -1220,7 +1494,8 @@ kwboot_term_pipe(int in, int out, const char *quit, int *s)
static int
kwboot_terminal(int tty)
{
int rc, in, s;
int rc, in, s, k;
const char *kbs = NULL;
const char *quit = "\34c";
struct termios otio, tio;
@ -1239,6 +1514,33 @@ kwboot_terminal(int tty)
goto out;
}
/*
* Get sequence for backspace key used by the current
* terminal. Every occurrence of this sequence will be
* replaced by '\b' byte which is the only recognized
* backspace byte by Marvell BootROM.
*
* Note that we cannot read this sequence from termios
* c_cc[VERASE] as VERASE is valid only when ICANON is
* set in termios c_lflag, which is not case for us.
*
* Also most terminals do not set termios c_cc[VERASE]
* as c_cc[VERASE] can specify only one-byte sequence
* and instead let applications to read (possible
* multi-byte) sequence for backspace key from "kbs"
* terminfo database based on $TERM env variable.
*
* So read "kbs" from terminfo database via tigetstr()
* call after successful setupterm(). Most terminals
* use byte 0x7F for backspace key, so replacement with
* '\b' is required.
*/
if (setupterm(NULL, STDOUT_FILENO, &rc) == 0) {
kbs = tigetstr("kbs");
if (kbs == (char *)-1)
kbs = NULL;
}
kwboot_printv("[Type Ctrl-%c + %c to quit]\r\n",
quit[0] | 0100, quit[1]);
} else
@ -1246,6 +1548,7 @@ kwboot_terminal(int tty)
rc = 0;
s = 0;
k = 0;
do {
fd_set rfds;
@ -1265,13 +1568,13 @@ kwboot_terminal(int tty)
break;
if (FD_ISSET(tty, &rfds)) {
rc = kwboot_term_pipe(tty, STDOUT_FILENO, NULL, NULL);
rc = kwboot_term_pipe(tty, STDOUT_FILENO, NULL, NULL, NULL, NULL);
if (rc)
break;
}
if (in >= 0 && FD_ISSET(in, &rfds)) {
rc = kwboot_term_pipe(in, tty, quit, &s);
rc = kwboot_term_pipe(in, tty, quit, &s, kbs, &k);
if (rc)
break;
}
@ -1708,16 +2011,16 @@ static void
kwboot_usage(FILE *stream, char *progname)
{
fprintf(stream,
"Usage: %s [OPTIONS] [-b <image> | -D <image> ] [-B <baud> ] <TTY>\n",
"Usage: %s [OPTIONS] [-b <image> | -D <image> | -b | -d ] [-B <baud> ] [-t] <TTY>\n",
progname);
fprintf(stream, "\n");
fprintf(stream,
" -b <image>: boot <image> with preamble (Kirkwood, Armada 370/XP)\n");
" -b <image>: boot <image> with preamble (Kirkwood, Avanta, Armada 370/XP/375/38x/39x)\n");
fprintf(stream,
" -D <image>: boot <image> without preamble (Dove)\n");
fprintf(stream, " -d: enter debug mode\n");
fprintf(stream, " -b: enter xmodem boot mode\n");
fprintf(stream, " -d: enter console debug mode\n");
fprintf(stream, " -a: use timings for Armada XP\n");
fprintf(stream, " -q <req-delay>: use specific request-delay\n");
fprintf(stream, " -s <resp-timeo>: use specific response-timeout\n");
fprintf(stream,
" -o <block-timeo>: use specific xmodem block timeout\n");
@ -1733,8 +2036,8 @@ main(int argc, char **argv)
{
const char *ttypath, *imgpath;
int rv, rc, tty, term;
void *bootmsg;
void *debugmsg;
int bootmsg;
int debugmsg;
void *img;
size_t size;
size_t after_img_rsv;
@ -1744,8 +2047,8 @@ main(int argc, char **argv)
rv = 1;
tty = -1;
bootmsg = NULL;
debugmsg = NULL;
bootmsg = 0;
debugmsg = 0;
imgpath = NULL;
img = NULL;
term = 0;
@ -1767,24 +2070,25 @@ main(int argc, char **argv)
case 'b':
if (imgpath || bootmsg || debugmsg)
goto usage;
bootmsg = kwboot_msg_boot;
bootmsg = 1;
if (prev_optind == optind)
goto usage;
if (optind < argc - 1 && argv[optind] && argv[optind][0] != '-')
/* Option -b could have optional argument which specify image path */
if (optind < argc && argv[optind] && argv[optind][0] != '-')
imgpath = argv[optind++];
break;
case 'D':
if (imgpath || bootmsg || debugmsg)
goto usage;
bootmsg = NULL;
bootmsg = 0;
imgpath = optarg;
break;
case 'd':
if (imgpath || bootmsg || debugmsg)
goto usage;
debugmsg = kwboot_msg_debug;
debugmsg = 1;
break;
case 'p':
@ -1796,12 +2100,11 @@ main(int argc, char **argv)
break;
case 'a':
msg_req_delay = KWBOOT_MSG_REQ_DELAY_AXP;
msg_rsp_timeo = KWBOOT_MSG_RSP_TIMEO_AXP;
break;
case 'q':
msg_req_delay = atoi(optarg);
/* nop, for backward compatibility */
break;
case 's':
@ -1826,17 +2129,44 @@ main(int argc, char **argv)
if (!bootmsg && !term && !debugmsg && !imgpath)
goto usage;
ttypath = argv[optind++];
if (optind != argc)
/*
* If there is no remaining argument but optional imgpath was parsed
* then it means that optional imgpath was eaten by getopt parser.
* Reassing imgpath to required ttypath argument.
*/
if (optind == argc && imgpath) {
ttypath = imgpath;
imgpath = NULL;
} else if (optind + 1 == argc) {
ttypath = argv[optind];
} else {
goto usage;
}
tty = kwboot_open_tty(ttypath, imgpath ? 115200 : baudrate);
/* boot and debug message use baudrate 115200 */
if (((bootmsg && !imgpath) || debugmsg) && baudrate != 115200) {
fprintf(stderr, "Baudrate other than 115200 cannot be used for this operation.\n");
goto usage;
}
tty = kwboot_open_tty(ttypath, baudrate);
if (tty < 0) {
perror(ttypath);
goto out;
}
/*
* initial baudrate for image transfer is always 115200,
* the change to different baudrate is done only after the header is sent
*/
if (imgpath && baudrate != 115200) {
rc = kwboot_tty_change_baudrate(tty, 115200);
if (rc) {
perror(ttypath);
goto out;
}
}
if (baudrate == 115200)
/* do not change baudrate during Xmodem to the same value */
baudrate = 0;
@ -1866,17 +2196,13 @@ main(int argc, char **argv)
}
if (debugmsg) {
rc = kwboot_debugmsg(tty, debugmsg);
if (rc) {
perror("debugmsg");
rc = kwboot_debugmsg(tty);
if (rc)
goto out;
}
} else if (bootmsg) {
rc = kwboot_bootmsg(tty, bootmsg);
if (rc) {
perror("bootmsg");
rc = kwboot_bootmsg(tty);
if (rc)
goto out;
}
}
if (img) {

View File

@ -381,6 +381,11 @@ int main(int argc, char **argv)
}
if (params.fflag){
if (!tparams) {
fprintf(stderr, "%s: Missing FIT support\n",
params.cmdname);
exit (EXIT_FAILURE);
}
if (tparams->fflag_handle)
/*
* in some cases, some additional processing needs
@ -391,7 +396,7 @@ int main(int argc, char **argv)
retval = tparams->fflag_handle(&params);
if (retval != EXIT_SUCCESS)
exit (retval);
usage("Bad parameters for FIT image type");
}
if (params.lflag || params.fflag) {

View File

@ -230,19 +230,25 @@ static int pblimage_verify_header(unsigned char *ptr, int image_size,
struct image_tool_params *params)
{
struct pbl_header *pbl_hdr = (struct pbl_header *) ptr;
uint32_t rcwheader;
if (params->arch == IH_ARCH_ARM)
rcwheader = RCW_ARM_HEADER;
else
rcwheader = RCW_PPC_HEADER;
/* Only a few checks can be done: search for magic numbers */
if (ENDIANNESS == 'l') {
if (pbl_hdr->preamble != reverse_byte(RCW_PREAMBLE))
return -FDT_ERR_BADSTRUCTURE;
if (pbl_hdr->rcwheader != reverse_byte(RCW_HEADER))
if (pbl_hdr->rcwheader != reverse_byte(rcwheader))
return -FDT_ERR_BADSTRUCTURE;
} else {
if (pbl_hdr->preamble != RCW_PREAMBLE)
return -FDT_ERR_BADSTRUCTURE;
if (pbl_hdr->rcwheader != RCW_HEADER)
if (pbl_hdr->rcwheader != rcwheader)
return -FDT_ERR_BADSTRUCTURE;
}
return 0;

View File

@ -8,7 +8,8 @@
#define RCW_BYTES 64
#define RCW_PREAMBLE 0xaa55aa55
#define RCW_HEADER 0x010e0100
#define RCW_ARM_HEADER 0x01ee0100
#define RCW_PPC_HEADER 0x010e0100
struct pbl_header {
uint32_t preamble;