diff options
Diffstat (limited to 'drivers')
68 files changed, 1892 insertions, 1062 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 15d19d0c8a..58be410135 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -18,7 +18,6 @@ obj-$(CONFIG_$(SPL_TPL_)INPUT) += input/ obj-$(CONFIG_$(SPL_TPL_)LED) += led/ obj-$(CONFIG_$(SPL_TPL_)MMC) += mmc/ obj-y += mtd/ -obj-$(CONFIG_$(SPL_)MULTIPLEXER) += mux/ obj-$(CONFIG_$(SPL_TPL_)ETH) += net/ obj-$(CONFIG_$(SPL_TPL_)PCH) += pch/ obj-$(CONFIG_$(SPL_TPL_)PCI) += pci/ @@ -87,6 +86,7 @@ obj-$(CONFIG_FASTBOOT) += fastboot/ obj-$(CONFIG_FWU_MDATA) += fwu-mdata/ obj-y += misc/ obj-$(CONFIG_MMC) += mmc/ +obj-$(CONFIG_MULTIPLEXER) += mux/ obj-$(CONFIG_NVME) += nvme/ obj-$(CONFIG_PCI_ENDPOINT) += pci_endpoint/ obj-y += dfu/ diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 09aa97ee8c..42280cbf83 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -185,7 +185,7 @@ config CLK_VERSACLOCK config CLK_VERSAL bool "Enable clock driver support for Versal" depends on (ARCH_VERSAL || ARCH_VERSAL_NET) - select ZYNQMP_FIRMWARE + imply ZYNQMP_FIRMWARE help This clock driver adds support for clock realted settings for Versal platform. @@ -219,7 +219,7 @@ config CLK_ZYNQ config CLK_ZYNQMP bool "Enable clock driver support for ZynqMP" depends on ARCH_ZYNQMP - select ZYNQMP_FIRMWARE + imply ZYNQMP_FIRMWARE help This clock driver adds support for clock realted settings for ZynqMP platform. diff --git a/drivers/clk/aspeed/clk_ast2600.c b/drivers/clk/aspeed/clk_ast2600.c index 0df1dc3718..e5ada5b6d4 100644 --- a/drivers/clk/aspeed/clk_ast2600.c +++ b/drivers/clk/aspeed/clk_ast2600.c @@ -538,7 +538,7 @@ static uint32_t ast2600_configure_pll(struct ast2600_scu *scu, } p_cfg->reg.b.bypass = 0; - p_cfg->reg.b.off = 1; + p_cfg->reg.b.off = 0; p_cfg->reg.b.reset = 1; reg = readl(addr); @@ -549,7 +549,6 @@ static uint32_t ast2600_configure_pll(struct ast2600_scu *scu, /* write extend parameter */ writel(p_cfg->ext_reg, addr_ext); udelay(100); - p_cfg->reg.b.off = 0; p_cfg->reg.b.reset = 0; reg &= ~GENMASK(25, 0); reg |= p_cfg->reg.w; diff --git a/drivers/clk/renesas/clk-rcar-gen3.c b/drivers/clk/renesas/clk-rcar-gen3.c index c121d82de7..1697867ff0 100644 --- a/drivers/clk/renesas/clk-rcar-gen3.c +++ b/drivers/clk/renesas/clk-rcar-gen3.c @@ -55,6 +55,7 @@ static int gen3_clk_get_parent(struct gen3_clk_priv *priv, struct clk *clk, struct cpg_mssr_info *info, struct clk *parent) { const struct cpg_core_clk *core; + u8 shift; int ret; if (!renesas_clk_is_mod(clk)) { @@ -63,8 +64,9 @@ static int gen3_clk_get_parent(struct gen3_clk_priv *priv, struct clk *clk, return ret; if (core->type == CLK_TYPE_GEN3_MDSEL) { + shift = priv->cpg_mode & BIT(core->offset) ? 16 : 0; parent->dev = clk->dev; - parent->id = core->parent >> (priv->sscg ? 16 : 0); + parent->id = core->parent >> shift; parent->id &= 0xffff; return 0; } @@ -183,6 +185,7 @@ static u64 gen3_clk_get_rate64(struct clk *clk) priv->cpg_pll_config; u32 value, div; u64 rate = 0; + u8 shift; int ret; debug("%s[%i] Clock: id=%lu\n", __func__, __LINE__, clk->id); @@ -277,11 +280,11 @@ static u64 gen3_clk_get_rate64(struct clk *clk) "FIXED"); case CLK_TYPE_GEN3_MDSEL: - div = (core->div >> (priv->sscg ? 16 : 0)) & 0xffff; + shift = priv->cpg_mode & BIT(core->offset) ? 16 : 0; + div = (core->div >> shift) & 0xffff; rate = gen3_clk_get_rate64(&parent) / div; debug("%s[%i] PE clk: parent=%i div=%u => rate=%llu\n", - __func__, __LINE__, - (core->parent >> (priv->sscg ? 16 : 0)) & 0xffff, + __func__, __LINE__, (core->parent >> shift) & 0xffff, div, rate); return rate; @@ -407,7 +410,6 @@ static int gen3_clk_probe(struct udevice *dev) struct cpg_mssr_info *info = (struct cpg_mssr_info *)dev_get_driver_data(dev); fdt_addr_t rst_base; - u32 cpg_mode; int ret; priv->base = dev_read_addr_ptr(dev); @@ -423,15 +425,13 @@ static int gen3_clk_probe(struct udevice *dev) if (rst_base == FDT_ADDR_T_NONE) return -EINVAL; - cpg_mode = readl(rst_base + info->reset_modemr_offset); + priv->cpg_mode = readl(rst_base + info->reset_modemr_offset); priv->cpg_pll_config = - (struct rcar_gen3_cpg_pll_config *)info->get_pll_config(cpg_mode); + (struct rcar_gen3_cpg_pll_config *)info->get_pll_config(priv->cpg_mode); if (!priv->cpg_pll_config->extal_div) return -EINVAL; - priv->sscg = !(cpg_mode & BIT(12)); - if (info->reg_layout == CLK_REG_LAYOUT_RCAR_GEN2_AND_GEN3) { priv->info->status_regs = mstpsr; priv->info->control_regs = smstpcr; diff --git a/drivers/clk/renesas/rcar-gen3-cpg.h b/drivers/clk/renesas/rcar-gen3-cpg.h index 200e4adb90..894e376549 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.h +++ b/drivers/clk/renesas/rcar-gen3-cpg.h @@ -132,7 +132,7 @@ struct gen3_clk_priv { struct cpg_mssr_info *info; struct clk clk_extal; struct clk clk_extalr; - bool sscg; + u32 cpg_mode; const struct rcar_gen3_cpg_pll_config *cpg_pll_config; }; diff --git a/drivers/clk/uniphier/clk-uniphier-sys.c b/drivers/clk/uniphier/clk-uniphier-sys.c index ff5d364f59..3b8595fe61 100644 --- a/drivers/clk/uniphier/clk-uniphier-sys.c +++ b/drivers/clk/uniphier/clk-uniphier-sys.c @@ -28,7 +28,10 @@ const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[] = { UNIPHIER_CLK_GATE_SIMPLE(14, 0x2104, 16), /* usb30 (Pro4, Pro5, PXs2) */ UNIPHIER_CLK_GATE_SIMPLE(15, 0x2104, 17), /* usb31 (Pro4, Pro5, PXs2) */ UNIPHIER_CLK_GATE_SIMPLE(16, 0x2104, 19), /* usb30-phy (PXs2) */ + UNIPHIER_CLK_RATE(17, 25000000), /* usb30-phy2 (PXs2) */ + UNIPHIER_CLK_RATE(18, 25000000), /* usb30-phy3 (PXs2) */ UNIPHIER_CLK_GATE_SIMPLE(20, 0x2104, 20), /* usb31-phy (PXs2) */ + UNIPHIER_CLK_RATE(21, 25000000), /* usb31-phy2 (PXs2) */ UNIPHIER_CLK_GATE_SIMPLE(24, 0x2108, 2), /* pcie (Pro5) */ { /* sentinel */ } #endif @@ -44,6 +47,8 @@ const struct uniphier_clk_data uniphier_ld20_sys_clk_data[] = { UNIPHIER_CLK_GATE_SIMPLE(14, 0x210c, 14), /* usb30 (LD20) */ UNIPHIER_CLK_GATE_SIMPLE(16, 0x210c, 12), /* usb30-phy0 (LD20) */ UNIPHIER_CLK_GATE_SIMPLE(17, 0x210c, 13), /* usb30-phy1 (LD20) */ + UNIPHIER_CLK_RATE(18, 25000000), /* usb30-phy2 (LD20) */ + UNIPHIER_CLK_RATE(19, 25000000), /* usb30-phy3 (LD20) */ UNIPHIER_CLK_GATE_SIMPLE(24, 0x210c, 4), /* pcie */ { /* sentinel */ } #endif diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index 6fc8854b57..0f755aa702 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -301,6 +301,13 @@ config SPL_SIMPLE_BUS Supports the 'simple-bus' driver, which is used on some systems in SPL. +config TPL_SIMPLE_BUS + bool "Support simple-bus driver in TPL" + depends on TPL_DM && TPL_OF_CONTROL + help + Supports the 'simple-bus' driver, which is used on some systems + in TPL. + config SIMPLE_BUS_CORRECT_RANGE bool "Decode the 'simple-bus' <range> by honoring the #address-cells and #size-cells" depends on SIMPLE_BUS diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index d08578e9c4..f49ee493d3 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -1312,24 +1312,36 @@ bool ofnode_pre_reloc(ofnode node) { #if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD) /* for SPL and TPL the remaining nodes after the fdtgrep 1st pass - * had property dm-pre-reloc or u-boot,dm-spl/tpl. + * had property bootph-all or bootph-pre-sram/bootph-pre-ram. * They are removed in final dtb (fdtgrep 2nd pass) */ return true; #else - if (ofnode_read_bool(node, "u-boot,dm-pre-reloc")) + if (ofnode_read_bool(node, "bootph-all")) return true; - if (ofnode_read_bool(node, "u-boot,dm-pre-proper")) + if (ofnode_read_bool(node, "bootph-some-ram")) return true; /* * In regular builds individual spl and tpl handling both * count as handled pre-relocation for later second init. */ - if (ofnode_read_bool(node, "u-boot,dm-spl") || - ofnode_read_bool(node, "u-boot,dm-tpl")) + if (ofnode_read_bool(node, "bootph-pre-ram") || + ofnode_read_bool(node, "bootph-pre-sram")) return true; + if (IS_ENABLED(CONFIG_OF_TAG_MIGRATE)) { + /* detect and handle old tags */ + if (ofnode_read_bool(node, "u-boot,dm-pre-reloc") || + ofnode_read_bool(node, "u-boot,dm-pre-proper") || + ofnode_read_bool(node, "u-boot,dm-spl") || + ofnode_read_bool(node, "u-boot,dm-tpl") || + ofnode_read_bool(node, "u-boot,dm-vpl")) { + gd->flags |= GD_FLG_OF_TAG_MIGRATE; + return true; + } + } + return false; #endif } diff --git a/drivers/ddr/marvell/a38x/ddr3_init.h b/drivers/ddr/marvell/a38x/ddr3_init.h index ba9f7881d5..6854bb49de 100644 --- a/drivers/ddr/marvell/a38x/ddr3_init.h +++ b/drivers/ddr/marvell/a38x/ddr3_init.h @@ -9,7 +9,6 @@ #include "ddr_ml_wrapper.h" #include "mv_ddr_plat.h" -#include "seq_exec.h" #include "ddr3_logging_def.h" #include "ddr3_training_hw_algo.h" #include "ddr3_training_ip.h" diff --git a/drivers/ddr/marvell/a38x/seq_exec.h b/drivers/ddr/marvell/a38x/seq_exec.h deleted file mode 100644 index fe0cb8f75d..0000000000 --- a/drivers/ddr/marvell/a38x/seq_exec.h +++ /dev/null @@ -1,64 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) Marvell International Ltd. and its affiliates - */ - -#ifndef _SEQ_EXEC_H -#define _SEQ_EXEC_H - -#define NA 0xff -#define DEFAULT_PARAM 0 -#define MV_BOARD_TCLK_ERROR 0xffffffff - -#define NO_DATA 0xffffffff -#define MAX_DATA_ARRAY 5 -#define FIRST_CELL 0 - -/* Operation types */ -enum mv_op { - WRITE_OP, - DELAY_OP, - POLL_OP, -}; - -/* Operation parameters */ -struct op_params { - u32 unit_base_reg; - u32 unit_offset; - u32 mask; - u32 data[MAX_DATA_ARRAY]; /* data array */ - u8 wait_time; /* msec */ - u16 num_of_loops; /* for polling only */ -}; - -/* - * Sequence parameters. Each sequence contains: - * 1. Sequence id. - * 2. Sequence size (total amount of operations during the sequence) - * 3. a series of operations. operations can be write, poll or delay - * 4. index in the data array (the entry where the relevant data sits) - */ -struct cfg_seq { - struct op_params *op_params_ptr; - u8 cfg_seq_size; - u8 data_arr_idx; -}; - -extern struct cfg_seq serdes_seq_db[]; - -/* - * A generic function type for executing an operation (write, poll or delay) - */ -typedef int (*op_execute_func_ptr)(u32 serdes_num, struct op_params *params, - u32 data_arr_idx); - -/* Specific functions for executing each operation */ -int write_op_execute(u32 serdes_num, struct op_params *params, - u32 data_arr_idx); -int delay_op_execute(u32 serdes_num, struct op_params *params, - u32 data_arr_idx); -int poll_op_execute(u32 serdes_num, struct op_params *params, u32 data_arr_idx); -enum mv_op get_cfg_seq_op(struct op_params *params); -int mv_seq_exec(u32 serdes_num, u32 seq_id); - -#endif /*_SEQ_EXEC_H*/ diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 61490d6d8d..62cb77b098 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -75,7 +75,7 @@ config FPGA_XILINX config FPGA_ZYNQMPPL bool "Enable Xilinx FPGA driver for ZynqMP" - depends on FPGA_XILINX + depends on FPGA_XILINX && ZYNQMP_FIRMWARE help Enable FPGA driver for loading bitstream in BIT and BIN format on Xilinx Zynq UltraScale+ (ZynqMP) device. diff --git a/drivers/fpga/zynqmppl.c b/drivers/fpga/zynqmppl.c index d1491da02c..7b5128fe27 100644 --- a/drivers/fpga/zynqmppl.c +++ b/drivers/fpga/zynqmppl.c @@ -332,10 +332,16 @@ static int zynqmp_loads(xilinx_desc *desc, const void *buf, size_t bsize, buf_lo = lower_32_bits((ulong)buf); buf_hi = upper_32_bits((ulong)buf); - ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo, + if ((u32)(uintptr_t)fpga_sec_info->userkey_addr) + ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo, buf_hi, - (u32)(uintptr_t)fpga_sec_info->userkey_addr, - flag, ret_payload); + (u32)(uintptr_t)fpga_sec_info->userkey_addr, + flag, ret_payload); + else + ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo, + buf_hi, (u32)bsize, + flag, ret_payload); + if (ret) puts("PL FPGA LOAD fail\n"); else diff --git a/drivers/gpio/sh_pfc.c b/drivers/gpio/sh_pfc.c index 988f7e9bba..92522b63bb 100644 --- a/drivers/gpio/sh_pfc.c +++ b/drivers/gpio/sh_pfc.c @@ -568,10 +568,10 @@ static int sh_gpio_get_value(struct pinmux_info *gpioc, unsigned gpio) if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) return -1; -#if defined(CONFIG_RCAR_GEN3) - if ((gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE) == PINMUX_TYPE_INPUT) + + if (IS_ENABLED(CONFIG_RCAR_GEN3) && + ((gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE) == PINMUX_TYPE_INPUT)) offset += 4; -#endif return gpio_read_bit(dr, offset, bit); } diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 3279fef1eb..2eae33cd54 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -47,6 +47,16 @@ config SPL_DM_I2C device (bus child) info is kept as parent platdata. The interface is defined in include/i2c.h. +config TPL_DM_I2C + bool "Enable Driver Model for I2C drivers in TPL" + depends on TPL_DM && DM_I2C + help + Enable driver model for I2C. The I2C uclass interface: probe, read, + write and speed, is implemented with the bus drivers operations, + which provide methods for bus setting and data transfer. Each chip + device (bus child) info is kept as parent platdata. The interface + is defined in include/i2c.h. + config VPL_DM_I2C bool "Enable Driver Model for I2C drivers in VPL" depends on VPL_DM && DM_I2C @@ -486,13 +496,13 @@ config SYS_I2C_OMAP24XX config SYS_I2C_RCAR_I2C bool "Renesas RCar I2C driver" - depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C + depends on (RCAR_GEN2 || RCAR_GEN3) && DM_I2C help Support for Renesas RCar I2C controller. config SYS_I2C_RCAR_IIC bool "Renesas RCar Gen3 IIC driver" - depends on (RCAR_GEN3 || RCAR_GEN2) && DM_I2C + depends on (RCAR_GEN2 || RCAR_GEN3) && DM_I2C help Support for Renesas RCar Gen3 IIC controller. @@ -508,6 +518,16 @@ config SYS_I2C_ROCKCHIP config SYS_I2C_SANDBOX bool "Sandbox I2C driver" depends on SANDBOX && DM_I2C + default y + help + Enable I2C support for sandbox. This is an emulation of a real I2C + bus. Devices can be attached to the bus using the device tree + which specifies the driver to use. See sandbox.dts as an example. + +config SPL_SYS_I2C_SANDBOX + bool "Sandbox I2C driver (SPL)" + depends on SPL && SANDBOX && DM_I2C + default y help Enable I2C support for sandbox. This is an emulation of a real I2C bus. Devices can be attached to the bus using the device tree diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 14c0ea7325..71f315adf6 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -14,5 +14,4 @@ obj-$(CONFIG_APPLE_SPI_KEYB) += apple_spi_kbd.o obj-$(CONFIG_I8042_KEYB) += i8042.o obj-$(CONFIG_TEGRA_KEYBOARD) += input.o tegra-kbc.o obj-$(CONFIG_TWL4030_INPUT) += twl4030.o -obj-$(CONFIG_TWL6030_INPUT) += twl6030.o endif diff --git a/drivers/input/twl6030.c b/drivers/input/twl6030.c deleted file mode 100644 index 76bd3488fc..0000000000 --- a/drivers/input/twl6030.c +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * TWL6030 input - * - * Copyright (C) 2016 Paul Kocialkowski <contact@paulk.fr> - */ - -#include <twl6030.h> - -int twl6030_input_power_button(void) -{ - u8 value; - - twl6030_i2c_read_u8(TWL6030_CHIP_PM, TWL6030_STS_HW_CONDITIONS, &value); - - /* Power button is active low. */ - if (value & TWL6030_STS_HW_CONDITIONS_PWRON) - return 0; - - return 1; -} - -int twl6030_input_charger(void) -{ - u8 value; - - twl6030_i2c_read_u8(TWL6030_CHIP_CHARGER, TWL6030_CONTROLLER_STAT1, - &value); - - if (value & TWL6030_CONTROLLER_STAT1_VAC_DET) - return 1; - - return 0; -} - -int twl6030_input_usb(void) -{ - u8 value; - - twl6030_i2c_read_u8(TWL6030_CHIP_CHARGER, TWL6030_CONTROLLER_STAT1, - &value); - - if (value & TWL6030_CONTROLLER_STAT1_VBUS_DET) - return 1; - - return 0; -} diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 878f867c62..80641e1393 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -667,18 +667,6 @@ config MMC_SDHCI_S5P If unsure, say N. -config MMC_SDHCI_SPEAR - bool "SDHCI support on ST SPEAr platform" - depends on MMC_SDHCI - help - This selects the Secure Digital Host Controller Interface (SDHCI) - often referrered to as the HSMMC block in some of the ST SPEAR range - of SoC - - If you have a controller with this interface, say Y here. - - If unsure, say N. - config MMC_SDHCI_STI bool "SDHCI support for STMicroelectronics SoC" depends on MMC_SDHCI && OF_CONTROL diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 3dc757108d..2c65c4765a 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -70,7 +70,6 @@ obj-$(CONFIG_MMC_SDHCI_NPCM) += npcm_sdhci.o obj-$(CONFIG_MMC_SDHCI_PIC32) += pic32_sdhci.o obj-$(CONFIG_MMC_SDHCI_ROCKCHIP) += rockchip_sdhci.o obj-$(CONFIG_MMC_SDHCI_S5P) += s5p_sdhci.o -obj-$(CONFIG_MMC_SDHCI_SPEAR) += spear_sdhci.o obj-$(CONFIG_MMC_SDHCI_STI) += sti_sdhci.o obj-$(CONFIG_MMC_SDHCI_TANGIER) += tangier_sdhci.o obj-$(CONFIG_MMC_SDHCI_TEGRA) += tegra_mmc.o diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 91e309d275..9dc310663f 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -14,6 +14,7 @@ #include "mmc_private.h" #include <log.h> #include <reset.h> +#include <asm/arch/sys_proto.h> #include <dm/device_compat.h> #include <linux/err.h> #include <linux/libfdt.h> @@ -988,7 +989,7 @@ static const struct sdhci_ops arasan_ops = { }; #endif -#if defined(CONFIG_ARCH_ZYNQMP) +#if defined(CONFIG_ARCH_ZYNQMP) && defined(CONFIG_ZYNQMP_FIRMWARE) static int sdhci_zynqmp_set_dynamic_config(struct arasan_sdhci_priv *priv, struct udevice *dev) { @@ -1090,7 +1091,7 @@ static int arasan_sdhci_probe(struct udevice *dev) host = priv->host; -#if defined(CONFIG_ARCH_ZYNQMP) +#if defined(CONFIG_ARCH_ZYNQMP) && defined(CONFIG_ZYNQMP_FIRMWARE) if (device_is_compatible(dev, "xlnx,zynqmp-8.9a")) { ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_SET_SD_CONFIG); diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 5b35da45f5..5c7b0d9dcc 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -628,7 +628,8 @@ comment "Generic NAND options" config SYS_NAND_BLOCK_SIZE hex "NAND chip eraseblock size" - depends on ARCH_SUNXI || SPL_NAND_SUPPORT || TPL_NAND_SUPPORT + depends on ARCH_SUNXI || SPL_NAND_SUPPORT || TPL_NAND_SUPPORT || \ + MVEBU_SPL_BOOT_DEVICE_NAND depends on !NAND_MXS && !NAND_DENALI_DT && !NAND_LPC32XX_MLC && \ !NAND_FSL_IFC && !NAND_MT7621 help @@ -655,6 +656,7 @@ config SYS_NAND_PAGE_SIZE hex "NAND chip page size" depends on ARCH_SUNXI || NAND_OMAP_GPMC || NAND_LPC32XX_SLC || \ SPL_NAND_SIMPLE || (NAND_MXC && SPL_NAND_SUPPORT) || \ + MVEBU_SPL_BOOT_DEVICE_NAND || \ (NAND_ATMEL && SPL_NAND_SUPPORT) || SPL_GENERATE_ATMEL_PMECC_HEADER depends on !NAND_MXS && !NAND_DENALI_DT && !NAND_LPC32XX_MLC && !NAND_MT7621 help diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index 666323e221..add2b4cf65 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -56,7 +56,6 @@ obj-$(CONFIG_NAND_DENALI) += denali.o obj-$(CONFIG_NAND_DENALI_DT) += denali_dt.o obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o -obj-$(CONFIG_NAND_KB9202) += kb9202_nand.o obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o obj-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o obj-$(CONFIG_NAND_LPC32XX_MLC) += lpc32xx_nand_mlc.o diff --git a/drivers/mtd/nand/raw/arasan_nfc.c b/drivers/mtd/nand/raw/arasan_nfc.c index 4621bfb03e..99e2681c14 100644 --- a/drivers/mtd/nand/raw/arasan_nfc.c +++ b/drivers/mtd/nand/raw/arasan_nfc.c @@ -1230,12 +1230,16 @@ static int arasan_probe(struct udevice *dev) struct nand_drv *info = &arasan->nand_ctrl; struct nand_config *nand = &info->config; struct mtd_info *mtd; + ofnode child; int err = -1; info->reg = (struct nand_regs *)dev_read_addr(dev); mtd = nand_to_mtd(nand_chip); nand_set_controller_data(nand_chip, &arasan->nand_ctrl); + ofnode_for_each_subnode(child, dev_ofnode(dev)) + nand_set_flash_node(nand_chip, child); + #ifdef CONFIG_SYS_NAND_NO_SUBPAGE_WRITE nand_chip->options |= NAND_NO_SUBPAGE_WRITE; #endif @@ -1248,7 +1252,6 @@ static int arasan_probe(struct udevice *dev) /* Buffer read/write routines */ nand_chip->read_buf = arasan_nand_read_buf; nand_chip->write_buf = arasan_nand_write_buf; - nand_chip->bbt_options = NAND_BBT_USE_FLASH; writel(0x0, &info->reg->cmd_reg); writel(0x0, &info->reg->pgm_reg); diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c b/drivers/mtd/nand/raw/brcmnand/brcmnand.c index 74c9348f7f..efbf9a3120 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c @@ -86,6 +86,12 @@ struct brcm_nand_dma_desc { #define FLASH_DMA_ECC_ERROR (1 << 8) #define FLASH_DMA_CORR_ERROR (1 << 9) +/* Bitfields for DMA_MODE */ +#define FLASH_DMA_MODE_STOP_ON_ERROR BIT(1) /* stop in Uncorr ECC error */ +#define FLASH_DMA_MODE_MODE BIT(0) /* link list */ +#define FLASH_DMA_MODE_MASK (FLASH_DMA_MODE_STOP_ON_ERROR | \ + FLASH_DMA_MODE_MODE) + /* 512B flash cache in the NAND controller HW */ #define FC_SHIFT 9U #define FC_BYTES 512U @@ -98,6 +104,65 @@ struct brcm_nand_dma_desc { #define NAND_CTRL_RDY (INTFC_CTLR_READY | INTFC_FLASH_READY) #define NAND_POLL_STATUS_TIMEOUT_MS 100 +/* flash_dma registers */ +enum flash_dma_reg { + FLASH_DMA_REVISION = 0, + FLASH_DMA_FIRST_DESC, + FLASH_DMA_FIRST_DESC_EXT, + FLASH_DMA_CTRL, + FLASH_DMA_MODE, + FLASH_DMA_STATUS, + FLASH_DMA_INTERRUPT_DESC, + FLASH_DMA_INTERRUPT_DESC_EXT, + FLASH_DMA_ERROR_STATUS, + FLASH_DMA_CURRENT_DESC, + FLASH_DMA_CURRENT_DESC_EXT, +}; + +#ifndef __UBOOT__ +/* flash_dma registers v0*/ +static const u16 flash_dma_regs_v0[] = { + [FLASH_DMA_REVISION] = 0x00, + [FLASH_DMA_FIRST_DESC] = 0x04, + [FLASH_DMA_CTRL] = 0x08, + [FLASH_DMA_MODE] = 0x0c, + [FLASH_DMA_STATUS] = 0x10, + [FLASH_DMA_INTERRUPT_DESC] = 0x14, + [FLASH_DMA_ERROR_STATUS] = 0x18, + [FLASH_DMA_CURRENT_DESC] = 0x1c, +}; + +/* flash_dma registers v1*/ +static const u16 flash_dma_regs_v1[] = { + [FLASH_DMA_REVISION] = 0x00, + [FLASH_DMA_FIRST_DESC] = 0x04, + [FLASH_DMA_FIRST_DESC_EXT] = 0x08, + [FLASH_DMA_CTRL] = 0x0c, + [FLASH_DMA_MODE] = 0x10, + [FLASH_DMA_STATUS] = 0x14, + [FLASH_DMA_INTERRUPT_DESC] = 0x18, + [FLASH_DMA_INTERRUPT_DESC_EXT] = 0x1c, + [FLASH_DMA_ERROR_STATUS] = 0x20, + [FLASH_DMA_CURRENT_DESC] = 0x24, + [FLASH_DMA_CURRENT_DESC_EXT] = 0x28, +}; + +/* flash_dma registers v4 */ +static const u16 flash_dma_regs_v4[] = { + [FLASH_DMA_REVISION] = 0x00, + [FLASH_DMA_FIRST_DESC] = 0x08, + [FLASH_DMA_FIRST_DESC_EXT] = 0x0c, + [FLASH_DMA_CTRL] = 0x10, + [FLASH_DMA_MODE] = 0x14, + [FLASH_DMA_STATUS] = 0x18, + [FLASH_DMA_INTERRUPT_DESC] = 0x20, + [FLASH_DMA_INTERRUPT_DESC_EXT] = 0x24, + [FLASH_DMA_ERROR_STATUS] = 0x28, + [FLASH_DMA_CURRENT_DESC] = 0x30, + [FLASH_DMA_CURRENT_DESC_EXT] = 0x34, +}; +#endif /* __UBOOT__ */ + /* Controller feature flags */ enum { BRCMNAND_HAS_1K_SECTORS = BIT(0), @@ -135,6 +200,8 @@ struct brcmnand_controller { /* List of NAND hosts (one for each chip-select) */ struct list_head host_list; + /* flash_dma reg */ + const u16 *flash_dma_offsets; struct brcm_nand_dma_desc *dma_desc; dma_addr_t dma_pa; @@ -150,6 +217,7 @@ struct brcmnand_controller { const unsigned int *block_sizes; unsigned int max_page_size; const unsigned int *page_sizes; + unsigned int page_size_shift; unsigned int max_oob; u32 features; @@ -226,8 +294,38 @@ enum brcmnand_reg { BRCMNAND_FC_BASE, }; -/* BRCMNAND v4.0 */ -static const u16 brcmnand_regs_v40[] = { +/* BRCMNAND v2.1-v2.2 */ +static const u16 brcmnand_regs_v21[] = { + [BRCMNAND_CMD_START] = 0x04, + [BRCMNAND_CMD_EXT_ADDRESS] = 0x08, + [BRCMNAND_CMD_ADDRESS] = 0x0c, + [BRCMNAND_INTFC_STATUS] = 0x5c, + [BRCMNAND_CS_SELECT] = 0x14, + [BRCMNAND_CS_XOR] = 0x18, + [BRCMNAND_LL_OP] = 0, + [BRCMNAND_CS0_BASE] = 0x40, + [BRCMNAND_CS1_BASE] = 0, + [BRCMNAND_CORR_THRESHOLD] = 0, + [BRCMNAND_CORR_THRESHOLD_EXT] = 0, + [BRCMNAND_UNCORR_COUNT] = 0, + [BRCMNAND_CORR_COUNT] = 0, + [BRCMNAND_CORR_EXT_ADDR] = 0x60, + [BRCMNAND_CORR_ADDR] = 0x64, + [BRCMNAND_UNCORR_EXT_ADDR] = 0x68, + [BRCMNAND_UNCORR_ADDR] = 0x6c, + [BRCMNAND_SEMAPHORE] = 0x50, + [BRCMNAND_ID] = 0x54, + [BRCMNAND_ID_EXT] = 0, + [BRCMNAND_LL_RDATA] = 0, + [BRCMNAND_OOB_READ_BASE] = 0x20, + [BRCMNAND_OOB_READ_10_BASE] = 0, + [BRCMNAND_OOB_WRITE_BASE] = 0x30, + [BRCMNAND_OOB_WRITE_10_BASE] = 0, + [BRCMNAND_FC_BASE] = 0x200, +}; + +/* BRCMNAND v3.3-v4.0 */ +static const u16 brcmnand_regs_v33[] = { [BRCMNAND_CMD_START] = 0x04, [BRCMNAND_CMD_EXT_ADDRESS] = 0x08, [BRCMNAND_CMD_ADDRESS] = 0x0c, @@ -424,6 +522,9 @@ enum { CFG_BUS_WIDTH = BIT(CFG_BUS_WIDTH_SHIFT), CFG_DEVICE_SIZE_SHIFT = 24, + /* Only for v2.1 */ + CFG_PAGE_SIZE_SHIFT_v2_1 = 30, + /* Only for pre-v7.1 (with no CFG_EXT register) */ CFG_PAGE_SIZE_SHIFT = 20, CFG_BLK_SIZE_SHIFT = 28, @@ -459,12 +560,16 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl) { static const unsigned int block_sizes_v6[] = { 8, 16, 128, 256, 512, 1024, 2048, 0 }; static const unsigned int block_sizes_v4[] = { 16, 128, 8, 512, 256, 1024, 2048, 0 }; - static const unsigned int page_sizes[] = { 512, 2048, 4096, 8192, 0 }; + static const unsigned int block_sizes_v2_2[] = { 16, 128, 8, 512, 256, 0 }; + static const unsigned int block_sizes_v2_1[] = { 16, 128, 8, 512, 0 }; + static const unsigned int page_sizes_v3_4[] = { 512, 2048, 4096, 8192, 0 }; + static const unsigned int page_sizes_v2_2[] = { 512, 2048, 4096, 0 }; + static const unsigned int page_sizes_v2_1[] = { 512, 2048, 0 }; ctrl->nand_version = nand_readreg(ctrl, 0) & 0xffff; - /* Only support v4.0+? */ - if (ctrl->nand_version < 0x0400) { + /* Only support v2.1+ */ + if (ctrl->nand_version < 0x0201) { dev_err(ctrl->dev, "version %#x not supported\n", ctrl->nand_version); return -ENODEV; @@ -473,14 +578,16 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl) /* Register offsets */ if (ctrl->nand_version >= 0x0702) ctrl->reg_offsets = brcmnand_regs_v72; - else if (ctrl->nand_version >= 0x0701) + else if (ctrl->nand_version == 0x0701) ctrl->reg_offsets = brcmnand_regs_v71; else if (ctrl->nand_version >= 0x0600) ctrl->reg_offsets = brcmnand_regs_v60; else if (ctrl->nand_version >= 0x0500) ctrl->reg_offsets = brcmnand_regs_v50; - else if (ctrl->nand_version >= 0x0400) - ctrl->reg_offsets = brcmnand_regs_v40; + else if (ctrl->nand_version >= 0x0303) + ctrl->reg_offsets = brcmnand_regs_v33; + else if (ctrl->nand_version >= 0x0201) + ctrl->reg_offsets = brcmnand_regs_v21; /* Chip-select stride */ if (ctrl->nand_version >= 0x0701) @@ -494,8 +601,9 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl) } else { ctrl->cs_offsets = brcmnand_cs_offsets; - /* v5.0 and earlier has a different CS0 offset layout */ - if (ctrl->nand_version <= 0x0500) + /* v3.3-5.0 have a different CS0 offset layout */ + if (ctrl->nand_version >= 0x0303 && + ctrl->nand_version <= 0x0500) ctrl->cs0_offsets = brcmnand_cs_offsets_cs0; } @@ -505,20 +613,38 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl) ctrl->max_page_size = 16 * 1024; ctrl->max_block_size = 2 * 1024 * 1024; } else { - ctrl->page_sizes = page_sizes; + if (ctrl->nand_version >= 0x0304) + ctrl->page_sizes = page_sizes_v3_4; + else if (ctrl->nand_version >= 0x0202) + ctrl->page_sizes = page_sizes_v2_2; + else + ctrl->page_sizes = page_sizes_v2_1; + + if (ctrl->nand_version >= 0x0202) + ctrl->page_size_shift = CFG_PAGE_SIZE_SHIFT; + else + ctrl->page_size_shift = CFG_PAGE_SIZE_SHIFT_v2_1; + if (ctrl->nand_version >= 0x0600) ctrl->block_sizes = block_sizes_v6; - else + else if (ctrl->nand_version >= 0x0400) ctrl->block_sizes = block_sizes_v4; + else if (ctrl->nand_version >= 0x0202) + ctrl->block_sizes = block_sizes_v2_2; + else + ctrl->block_sizes = block_sizes_v2_1; if (ctrl->nand_version < 0x0400) { - ctrl->max_page_size = 4096; + if (ctrl->nand_version < 0x0202) + ctrl->max_page_size = 2048; + else + ctrl->max_page_size = 4096; ctrl->max_block_size = 512 * 1024; } } /* Maximum spare area sector size (per 512B) */ - if (ctrl->nand_version >= 0x0702) + if (ctrl->nand_version == 0x0702) ctrl->max_oob = 128; else if (ctrl->nand_version >= 0x0600) ctrl->max_oob = 64; @@ -553,6 +679,19 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl) return 0; } +#ifndef __UBOOT__ +static void brcmnand_flash_dma_revision_init(struct brcmnand_controller *ctrl) +{ + /* flash_dma register offsets */ + if (ctrl->nand_version >= 0x0703) + ctrl->flash_dma_offsets = flash_dma_regs_v4; + else if (ctrl->nand_version == 0x0602) + ctrl->flash_dma_offsets = flash_dma_regs_v0; + else + ctrl->flash_dma_offsets = flash_dma_regs_v1; +} +#endif /* __UBOOT__ */ + static inline u32 brcmnand_read_reg(struct brcmnand_controller *ctrl, enum brcmnand_reg reg) { @@ -595,6 +734,54 @@ static inline void brcmnand_write_fc(struct brcmnand_controller *ctrl, __raw_writel(val, ctrl->nand_fc + word * 4); } +static void brcmnand_clear_ecc_addr(struct brcmnand_controller *ctrl) +{ + + /* Clear error addresses */ + brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_ADDR, 0); + brcmnand_write_reg(ctrl, BRCMNAND_CORR_ADDR, 0); + brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_EXT_ADDR, 0); + brcmnand_write_reg(ctrl, BRCMNAND_CORR_EXT_ADDR, 0); +} + +static u64 brcmnand_get_uncorrecc_addr(struct brcmnand_controller *ctrl) +{ + u64 err_addr; + + err_addr = brcmnand_read_reg(ctrl, BRCMNAND_UNCORR_ADDR); + err_addr |= ((u64)(brcmnand_read_reg(ctrl, + BRCMNAND_UNCORR_EXT_ADDR) + & 0xffff) << 32); + + return err_addr; +} + +static u64 brcmnand_get_correcc_addr(struct brcmnand_controller *ctrl) +{ + u64 err_addr; + + err_addr = brcmnand_read_reg(ctrl, BRCMNAND_CORR_ADDR); + err_addr |= ((u64)(brcmnand_read_reg(ctrl, + BRCMNAND_CORR_EXT_ADDR) + & 0xffff) << 32); + + return err_addr; +} + +static void brcmnand_set_cmd_addr(struct mtd_info *mtd, u64 addr) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct brcmnand_host *host = nand_get_controller_data(chip); + struct brcmnand_controller *ctrl = host->ctrl; + + brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS, + (host->cs << 16) | ((addr >> 32) & 0xffff)); + (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS); + brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS, + lower_32_bits(addr)); + (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS); +} + static inline u16 brcmnand_cs_offset(struct brcmnand_controller *ctrl, int cs, enum brcmnand_cs_reg reg) { @@ -627,7 +814,10 @@ static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val) enum brcmnand_reg reg = BRCMNAND_CORR_THRESHOLD; int cs = host->cs; - if (ctrl->nand_version >= 0x0702) + if (!ctrl->reg_offsets[reg]) + return; + + if (ctrl->nand_version == 0x0702) bits = 7; else if (ctrl->nand_version >= 0x0600) bits = 6; @@ -681,12 +871,14 @@ enum { static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl) { - if (ctrl->nand_version >= 0x0702) + if (ctrl->nand_version == 0x0702) return GENMASK(7, 0); else if (ctrl->nand_version >= 0x0600) return GENMASK(6, 0); - else + else if (ctrl->nand_version >= 0x0303) return GENMASK(5, 0); + else + return GENMASK(4, 0); } #define NAND_ACC_CONTROL_ECC_SHIFT 16 @@ -829,20 +1021,6 @@ static inline void brcmnand_set_wp(struct brcmnand_controller *ctrl, bool en) * Flash DMA ***********************************************************************/ -enum flash_dma_reg { - FLASH_DMA_REVISION = 0x00, - FLASH_DMA_FIRST_DESC = 0x04, - FLASH_DMA_FIRST_DESC_EXT = 0x08, - FLASH_DMA_CTRL = 0x0c, - FLASH_DMA_MODE = 0x10, - FLASH_DMA_STATUS = 0x14, - FLASH_DMA_INTERRUPT_DESC = 0x18, - FLASH_DMA_INTERRUPT_DESC_EXT = 0x1c, - FLASH_DMA_ERROR_STATUS = 0x20, - FLASH_DMA_CURRENT_DESC = 0x24, - FLASH_DMA_CURRENT_DESC_EXT = 0x28, -}; - static inline bool has_flash_dma(struct brcmnand_controller *ctrl) { return ctrl->flash_dma_base; @@ -858,14 +1036,19 @@ static inline bool flash_dma_buf_ok(const void *buf) #endif /* __UBOOT__ */ } -static inline void flash_dma_writel(struct brcmnand_controller *ctrl, u8 offs, - u32 val) +static inline void flash_dma_writel(struct brcmnand_controller *ctrl, + enum flash_dma_reg dma_reg, u32 val) { + u16 offs = ctrl->flash_dma_offsets[dma_reg]; + brcmnand_writel(val, ctrl->flash_dma_base + offs); } -static inline u32 flash_dma_readl(struct brcmnand_controller *ctrl, u8 offs) +static inline u32 flash_dma_readl(struct brcmnand_controller *ctrl, + enum flash_dma_reg dma_reg) { + u16 offs = ctrl->flash_dma_offsets[dma_reg]; + return brcmnand_readl(ctrl->flash_dma_base + offs); } @@ -1190,9 +1373,12 @@ static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd) { struct brcmnand_controller *ctrl = host->ctrl; int ret; + u64 cmd_addr; + + cmd_addr = brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS); + + dev_dbg(ctrl->dev, "send native cmd %d addr 0x%llx\n", cmd, cmd_addr); - dev_dbg(ctrl->dev, "send native cmd %d addr_lo 0x%x\n", cmd, - brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS)); BUG_ON(ctrl->cmd_pending != 0); ctrl->cmd_pending = cmd; @@ -1365,12 +1551,7 @@ static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command, if (!native_cmd) return; - brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS, - (host->cs << 16) | ((addr >> 32) & 0xffff)); - (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS); - brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS, lower_32_bits(addr)); - (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS); - + brcmnand_set_cmd_addr(mtd, addr); brcmnand_send_cmd(host, native_cmd); brcmnand_waitfunc(mtd, chip); @@ -1542,8 +1723,11 @@ static void brcmnand_dma_run(struct brcmnand_host *host, dma_addr_t desc) flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC, lower_32_bits(desc)); (void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC); - flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC_EXT, upper_32_bits(desc)); - (void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC_EXT); + if (ctrl->nand_version > 0x0602) { + flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC_EXT, + upper_32_bits(desc)); + (void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC_EXT); + } /* Start FLASH_DMA engine */ ctrl->dma_pending = true; @@ -1600,20 +1784,10 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip, struct brcmnand_controller *ctrl = host->ctrl; int i, j, ret = 0; - /* Clear error addresses */ - brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_ADDR, 0); - brcmnand_write_reg(ctrl, BRCMNAND_CORR_ADDR, 0); - brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_EXT_ADDR, 0); - brcmnand_write_reg(ctrl, BRCMNAND_CORR_EXT_ADDR, 0); - - brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS, - (host->cs << 16) | ((addr >> 32) & 0xffff)); - (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS); + brcmnand_clear_ecc_addr(ctrl); for (i = 0; i < trans; i++, addr += FC_BYTES) { - brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS, - lower_32_bits(addr)); - (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS); + brcmnand_set_cmd_addr(mtd, addr); /* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */ brcmnand_send_cmd(host, CMD_PAGE_READ); brcmnand_waitfunc(mtd, chip); @@ -1633,21 +1807,15 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip, host->hwcfg.sector_size_1k); if (ret != -EBADMSG) { - *err_addr = brcmnand_read_reg(ctrl, - BRCMNAND_UNCORR_ADDR) | - ((u64)(brcmnand_read_reg(ctrl, - BRCMNAND_UNCORR_EXT_ADDR) - & 0xffff) << 32); + *err_addr = brcmnand_get_uncorrecc_addr(ctrl); + if (*err_addr) ret = -EBADMSG; } if (!ret) { - *err_addr = brcmnand_read_reg(ctrl, - BRCMNAND_CORR_ADDR) | - ((u64)(brcmnand_read_reg(ctrl, - BRCMNAND_CORR_EXT_ADDR) - & 0xffff) << 32); + *err_addr = brcmnand_get_correcc_addr(ctrl); + if (*err_addr) ret = -EUCLEAN; } @@ -1673,11 +1841,13 @@ static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip, static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd, struct nand_chip *chip, void *buf, u64 addr) { - int i, sas; - void *oob = chip->oob_poi; + struct mtd_oob_region ecc; + int i; int bitflips = 0; int page = addr >> chip->page_shift; int ret; + void *ecc_bytes; + void *ecc_chunk; if (!buf) { #ifndef __UBOOT__ @@ -1689,16 +1859,20 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd, chip->pagebuf = -1; } - sas = mtd->oobsize / chip->ecc.steps; - /* read without ecc for verification */ ret = chip->ecc.read_page_raw(mtd, chip, buf, true, page); if (ret) return ret; - for (i = 0; i < chip->ecc.steps; i++, oob += sas) { - ret = nand_check_erased_ecc_chunk(buf, chip->ecc.size, - oob, sas, NULL, 0, + for (i = 0; i < chip->ecc.steps; i++) { + ecc_chunk = buf + chip->ecc.size * i; + + mtd_ooblayout_ecc(mtd, i, &ecc); + ecc_bytes = chip->oob_poi + ecc.offset; + + ret = nand_check_erased_ecc_chunk(ecc_chunk, chip->ecc.size, + ecc_bytes, ecc.length, + NULL, 0, chip->ecc.strength); if (ret < 0) return ret; @@ -1721,7 +1895,7 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip, dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf); try_dmaread: - brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_COUNT, 0); + brcmnand_clear_ecc_addr(ctrl); #ifndef __UBOOT__ if (has_flash_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) { @@ -1875,15 +2049,9 @@ static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip, } #endif /* __UBOOT__ */ - brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS, - (host->cs << 16) | ((addr >> 32) & 0xffff)); - (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS); - for (i = 0; i < trans; i++, addr += FC_BYTES) { /* full address MUST be set before populating FC */ - brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS, - lower_32_bits(addr)); - (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS); + brcmnand_set_cmd_addr(mtd, addr); if (buf) { brcmnand_soc_data_bus_prepare(ctrl->soc, false); @@ -2044,7 +2212,7 @@ static int brcmnand_set_cfg(struct brcmnand_host *host, (!!(cfg->device_width == 16) << CFG_BUS_WIDTH_SHIFT) | (device_size << CFG_DEVICE_SIZE_SHIFT); if (cfg_offs == cfg_ext_offs) { - tmp |= (page_size << CFG_PAGE_SIZE_SHIFT) | + tmp |= (page_size << ctrl->page_size_shift) | (block_size << CFG_BLK_SIZE_SHIFT); nand_writereg(ctrl, cfg_offs, tmp); } else { @@ -2056,9 +2224,11 @@ static int brcmnand_set_cfg(struct brcmnand_host *host, tmp = nand_readreg(ctrl, acc_control_offs); tmp &= ~brcmnand_ecc_level_mask(ctrl); - tmp |= cfg->ecc_level << NAND_ACC_CONTROL_ECC_SHIFT; tmp &= ~brcmnand_spare_area_mask(ctrl); - tmp |= cfg->spare_area_size; + if (ctrl->nand_version >= 0x0302) { + tmp |= cfg->ecc_level << NAND_ACC_CONTROL_ECC_SHIFT; + tmp |= cfg->spare_area_size; + } nand_writereg(ctrl, acc_control_offs, tmp); brcmnand_set_sector_size_1k(host, cfg->sector_size_1k); @@ -2345,6 +2515,12 @@ static int brcmnand_init_cs(struct brcmnand_host *host, ofnode dn) ret = nand_register(0, mtd); #endif /* __UBOOT__ */ + /* If OOB is written with ECC enabled it will cause ECC errors */ + if (is_hamming_ecc(host->ctrl, &host->hwcfg)) { + chip->ecc.write_oob = brcmnand_write_oob_raw; + chip->ecc.read_oob = brcmnand_read_oob_raw; + } + return ret; } @@ -2438,6 +2614,8 @@ const struct dev_pm_ops brcmnand_pm_ops = { EXPORT_SYMBOL_GPL(brcmnand_pm_ops); static const struct of_device_id brcmnand_of_match[] = { + { .compatible = "brcm,brcmnand-v2.1" }, + { .compatible = "brcm,brcmnand-v2.2" }, { .compatible = "brcm,brcmnand-v4.0" }, { .compatible = "brcm,brcmnand-v5.0" }, { .compatible = "brcm,brcmnand-v6.0" }, @@ -2446,6 +2624,7 @@ static const struct of_device_id brcmnand_of_match[] = { { .compatible = "brcm,brcmnand-v7.0" }, { .compatible = "brcm,brcmnand-v7.1" }, { .compatible = "brcm,brcmnand-v7.2" }, + { .compatible = "brcm,brcmnand-v7.3" }, {}, }; MODULE_DEVICE_TABLE(of, brcmnand_of_match); @@ -2576,7 +2755,11 @@ int brcmnand_probe(struct udevice *dev, struct brcmnand_soc *soc) goto err; } - flash_dma_writel(ctrl, FLASH_DMA_MODE, 1); /* linked-list */ + /* initialize the dma version */ + brcmnand_flash_dma_revision_init(ctrl); + + /* linked-list and stop on error */ + flash_dma_writel(ctrl, FLASH_DMA_MODE, FLASH_DMA_MODE_MASK); flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0); /* Allocate descriptor(s) */ diff --git a/drivers/mtd/nand/raw/kb9202_nand.c b/drivers/mtd/nand/raw/kb9202_nand.c deleted file mode 100644 index 9d26532c78..0000000000 --- a/drivers/mtd/nand/raw/kb9202_nand.c +++ /dev/null @@ -1,134 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2006 - * KwikByte <kb9200_dev@kwikbyte.com> - * - * (C) Copyright 2009 - * Matthias Kaehlcke <matthias@kaehlcke.net> - */ - -#include <common.h> -#include <linux/mtd/rawnand.h> -#include <asm/io.h> -#include <asm/arch/AT91RM9200.h> -#include <asm/arch/hardware.h> - -#include <nand.h> - -/* - * hardware specific access to control-lines - */ - -#define MASK_ALE (1 << 22) /* our ALE is A22 */ -#define MASK_CLE (1 << 21) /* our CLE is A21 */ - -#define KB9202_NAND_NCE (1 << 28) /* EN* on D28 */ -#define KB9202_NAND_BUSY (1 << 29) /* RB* on D29 */ - -#define KB9202_SMC2_NWS (1 << 2) -#define KB9202_SMC2_TDF (1 << 8) -#define KB9202_SMC2_RWSETUP (1 << 24) -#define KB9202_SMC2_RWHOLD (1 << 29) - -/* - * Board-specific function to access device control signals - */ -static void kb9202_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - struct nand_chip *this = mtd_to_nand(mtd); - - if (ctrl & NAND_CTRL_CHANGE) { - ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; - - /* clear ALE and CLE bits */ - IO_ADDR_W &= ~(MASK_ALE | MASK_CLE); - - if (ctrl & NAND_CLE) - IO_ADDR_W |= MASK_CLE; - - if (ctrl & NAND_ALE) - IO_ADDR_W |= MASK_ALE; - - this->IO_ADDR_W = (void *) IO_ADDR_W; - - if (ctrl & NAND_NCE) - writel(KB9202_NAND_NCE, AT91C_PIOC_CODR); - else - writel(KB9202_NAND_NCE, AT91C_PIOC_SODR); - } - - if (cmd != NAND_CMD_NONE) - writeb(cmd, this->IO_ADDR_W); -} - - -/* - * Board-specific function to access the device ready signal. - */ -static int kb9202_nand_ready(struct mtd_info *mtd) -{ - return readl(AT91C_PIOC_PDSR) & KB9202_NAND_BUSY; -} - - -/* - * Board-specific NAND init. Copied from include/linux/mtd/nand.h for reference. - * - * struct nand_chip - NAND Private Flash Chip Data - * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device - * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device - * @hwcontrol: [BOARDSPECIFIC] hardwarespecific function for accesing control-lines - * @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing device ready/busy line - * If set to NULL no access to ready/busy is available and the ready/busy information - * is read from the chip status register - * @enable_hwecc: [BOARDSPECIFIC] function to enable (reset) hardware ecc generator. Must only - * be provided if a hardware ECC is available - * @eccmode: [BOARDSPECIFIC] mode of ecc, see defines - * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR) - * @options: [BOARDSPECIFIC] various chip options. They can partly be set to inform nand_scan about - * special functionality. See the defines for further explanation -*/ -/* - * This routine initializes controller and GPIOs. - */ -int board_nand_init(struct nand_chip *nand) -{ - unsigned int value; - - nand->ecc.mode = NAND_ECC_SOFT; - nand->cmd_ctrl = kb9202_nand_hwcontrol; - nand->dev_ready = kb9202_nand_ready; - - /* in case running outside of bootloader */ - writel(1 << AT91C_ID_PIOC, AT91C_PMC_PCER); - - /* setup nand flash access (allow ample margin) */ - /* 4 wait states, 1 setup, 1 hold, 1 float for 8-bit device */ - writel(AT91C_SMC2_WSEN | KB9202_SMC2_NWS | KB9202_SMC2_TDF | - AT91C_SMC2_DBW_8 | KB9202_SMC2_RWSETUP | KB9202_SMC2_RWHOLD, - AT91C_SMC_CSR3); - - /* enable internal NAND controller */ - value = readl(AT91C_EBI_CSA); - value |= AT91C_EBI_CS3A_SMC_SmartMedia; - writel(value, AT91C_EBI_CSA); - - /* enable SMOE/SMWE */ - writel(AT91C_PC1_BFRDY_SMOE | AT91C_PC3_BFBAA_SMWE, AT91C_PIOC_ASR); - writel(AT91C_PC1_BFRDY_SMOE | AT91C_PC3_BFBAA_SMWE, AT91C_PIOC_PDR); - writel(AT91C_PC1_BFRDY_SMOE | AT91C_PC3_BFBAA_SMWE, AT91C_PIOC_OER); - - /* set NCE to high */ - writel(KB9202_NAND_NCE, AT91C_PIOC_SODR); - - /* disable output on pin connected to the busy line of the NAND */ - writel(KB9202_NAND_BUSY, AT91C_PIOC_ODR); - - /* enable the PIO to control NCE and BUSY */ - writel(KB9202_NAND_NCE | KB9202_NAND_BUSY, AT91C_PIOC_PER); - - /* enable output for NCE */ - writel(KB9202_NAND_NCE, AT91C_PIOC_OER); - - return (0); -} diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c index 911472e91e..cd451870a6 100644 --- a/drivers/mtd/nand/raw/nand_bbt.c +++ b/drivers/mtd/nand/raw/nand_bbt.c @@ -1330,6 +1330,7 @@ int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs) * @mtd: MTD device structure * @offs: offset in the device * @allowbbt: allow access to bad block table region + * Return: 0 - good block, 1- bad block, 2 - reserved block */ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) { @@ -1348,7 +1349,7 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) case BBT_BLOCK_WORN: return 1; case BBT_BLOCK_RESERVED: - return allowbbt ? 0 : 1; + return allowbbt ? 0 : 2; } return 1; } diff --git a/drivers/mtd/nand/raw/nand_util.c b/drivers/mtd/nand/raw/nand_util.c index b2345dca7f..72cc24f403 100644 --- a/drivers/mtd/nand/raw/nand_util.c +++ b/drivers/mtd/nand/raw/nand_util.c @@ -113,9 +113,10 @@ int nand_erase_opts(struct mtd_info *mtd, int ret = mtd_block_isbad(mtd, erase.addr); if (ret > 0) { if (!opts->quiet) - printf("\rSkipping bad block at " + printf("\rSkipping %s at " "0x%08llx " " \n", + ret == 1 ? "bad block" : "bbt reserved", erase.addr); if (!opts->spread) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 134bf22c80..70d8ae531e 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -979,8 +979,9 @@ static int spinand_detect(struct spinand_device *spinand) ret = spinand_manufacturer_detect(spinand); if (ret) { - dev_err(spinand->slave->dev, "unknown raw ID %*phN\n", - SPINAND_MAX_ID_LEN, spinand->id.data); + dev_err(spinand->slave->dev, "unknown raw ID %02x %02x %02x %02x\n", + spinand->id.data[0], spinand->id.data[1], + spinand->id.data[2], spinand->id.data[3]); return ret; } diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile index 78ebf04c7a..d4e24789d3 100644 --- a/drivers/mux/Makefile +++ b/drivers/mux/Makefile @@ -3,5 +3,5 @@ # (C) Copyright 2019 # Jean-Jacques Hiblot <jjhiblot@ti.com> -obj-$(CONFIG_$(SPL_)MULTIPLEXER) += mux-uclass.o +obj-$(CONFIG_MULTIPLEXER) += mux-uclass.o obj-$(CONFIG_$(SPL_)MUX_MMIO) += mmio.o diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c index 0fbfad11d4..24933473fa 100644 --- a/drivers/net/mvneta.c +++ b/drivers/net/mvneta.c @@ -815,7 +815,7 @@ static void mvneta_defaults_set(struct mvneta_port *pp) mvreg_write(pp, MVNETA_SDMA_CONFIG, val); /* Enable PHY polling in hardware if not in fixed-link mode */ - if (!CONFIG_IS_ENABLED(PHY_FIXED) || + if (!IS_ENABLED(CONFIG_PHY_FIXED) || pp->phydev->phy_id != PHY_FIXED_ID) { mvreg_write(pp, MVNETA_PHY_ADDR, pp->phydev->addr); @@ -1176,7 +1176,7 @@ static void mvneta_adjust_link(struct udevice *dev) * be added). Also, why is ADVERT_FC enabled if we don't enable * inband AN at all? */ - if (CONFIG_IS_ENABLED(PHY_FIXED) && + if (IS_ENABLED(CONFIG_PHY_FIXED) && pp->phydev->phy_id == PHY_FIXED_ID) val = MVNETA_GMAC_IB_BYPASS_AN_EN | MVNETA_GMAC_SET_FC_EN | diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 5eaff053a0..6806e3c090 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -106,6 +106,9 @@ config PHY_AQUANTIA_FW_NAME config PHY_ATHEROS bool "Atheros Ethernet PHYs support" +config SPL_PHY_ATHEROS + bool "Atheros Ethernet PHYs support (SPL)" + config PHY_BROADCOM bool "Broadcom Ethernet PHYs support" diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c index 5a835cc06f..0bc50dc733 100644 --- a/drivers/net/ravb.c +++ b/drivers/net/ravb.c @@ -310,7 +310,7 @@ static int ravb_phy_config(struct udevice *dev) struct ravb_priv *eth = dev_get_priv(dev); struct eth_pdata *pdata = dev_get_plat(dev); struct phy_device *phydev; - int mask = 0xffffffff, reg; + int reg; if (dm_gpio_is_valid(ð->reset_gpio)) { dm_gpio_set_value(ð->reset_gpio, 1); @@ -319,12 +319,10 @@ static int ravb_phy_config(struct udevice *dev) mdelay(1); } - phydev = phy_find_by_mask(eth->bus, mask); + phydev = phy_connect(eth->bus, -1, dev, pdata->phy_interface); if (!phydev) return -ENODEV; - phy_connect_dev(phydev, dev, pdata->phy_interface); - eth->phydev = phydev; phydev->supported &= SUPPORTED_100baseT_Full | diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index cc49788012..211b2c6e55 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -738,7 +738,7 @@ static int gem_zynqmp_set_dynamic_config(struct udevice *dev) u32 pm_info[2]; int ret; - if (IS_ENABLED(CONFIG_ARCH_ZYNQMP)) { + if (IS_ENABLED(CONFIG_ARCH_ZYNQMP) && IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) { if (!zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_SET_GEM_CONFIG)) { ret = ofnode_read_u32_array(dev_ofnode(dev), diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c index 47b6e6e5bc..f0dfe63149 100644 --- a/drivers/pci/pci_rom.c +++ b/drivers/pci/pci_rom.c @@ -325,7 +325,7 @@ err: return ret; } -int vesa_setup_video_priv(struct vesa_mode_info *vesa, +int vesa_setup_video_priv(struct vesa_mode_info *vesa, u64 fb, struct video_priv *uc_priv, struct video_uc_plat *plat) { @@ -348,9 +348,9 @@ int vesa_setup_video_priv(struct vesa_mode_info *vesa, /* Use double buffering if enabled */ if (IS_ENABLED(CONFIG_VIDEO_COPY) && plat->base) - plat->copy_base = vesa->phys_base_ptr; + plat->copy_base = fb; else - plat->base = vesa->phys_base_ptr; + plat->base = fb; log_debug("base = %lx, copy_base = %lx\n", plat->base, plat->copy_base); plat->size = vesa->bytes_per_scanline * vesa->y_resolution; @@ -377,7 +377,9 @@ int vesa_setup_video(struct udevice *dev, int (*int15_handler)(void)) return ret; } - ret = vesa_setup_video_priv(&mode_info.vesa, uc_priv, plat); + ret = vesa_setup_video_priv(&mode_info.vesa, + mode_info.vesa.phys_base_ptr, uc_priv, + plat); if (ret) { if (ret == -ENFILE) { /* diff --git a/drivers/phy/phy-mtk-tphy.c b/drivers/phy/phy-mtk-tphy.c index 2dd964f7b2..1883f9f83e 100644 --- a/drivers/phy/phy-mtk-tphy.c +++ b/drivers/phy/phy-mtk-tphy.c @@ -14,6 +14,7 @@ #include <asm/io.h> #include <dm/device_compat.h> #include <dm/devres.h> +#include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/delay.h> @@ -43,19 +44,21 @@ #define U3P_USBPHYACR0 0x000 #define PA0_RG_U2PLL_FORCE_ON BIT(15) +#define PA0_USB20_PLL_PREDIV GENMASK(7, 6) #define PA0_RG_USB20_INTR_EN BIT(5) +#define U3P_USBPHYACR2 0x008 +#define PA2_RG_U2PLL_BW GENMASK(21, 19) + #define U3P_USBPHYACR5 0x014 #define PA5_RG_U2_HSTX_SRCAL_EN BIT(15) #define PA5_RG_U2_HSTX_SRCTRL GENMASK(14, 12) -#define PA5_RG_U2_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12) #define PA5_RG_U2_HS_100U_U3_EN BIT(11) #define U3P_USBPHYACR6 0x018 #define PA6_RG_U2_BC11_SW_EN BIT(23) #define PA6_RG_U2_OTG_VBUSCMP_EN BIT(20) #define PA6_RG_U2_SQTH GENMASK(3, 0) -#define PA6_RG_U2_SQTH_VAL(x) (0xf & (x)) #define U3P_U2PHYACR4 0x020 #define P2C_RG_USB20_GPIO_CTL BIT(9) @@ -63,6 +66,14 @@ #define P2C_U2_GPIO_CTR_MSK \ (P2C_RG_USB20_GPIO_CTL | P2C_USB20_GPIO_MODE) +#define U3P_U2PHYA_RESV 0x030 +#define P2R_RG_U2PLL_FBDIV_26M 0x1bb13b +#define P2R_RG_U2PLL_FBDIV_48M 0x3c0000 + +#define U3P_U2PHYA_RESV1 0x044 +#define P2R_RG_U2PLL_REFCLK_SEL BIT(5) +#define P2R_RG_U2PLL_FRA_EN BIT(3) + #define U3P_U2PHYDTM0 0x068 #define P2C_FORCE_UART_EN BIT(26) #define P2C_FORCE_DATAIN BIT(23) @@ -72,11 +83,9 @@ #define P2C_FORCE_SUSPENDM BIT(18) #define P2C_FORCE_TERMSEL BIT(17) #define P2C_RG_DATAIN GENMASK(13, 10) -#define P2C_RG_DATAIN_VAL(x) ((0xf & (x)) << 10) #define P2C_RG_DMPULLDOWN BIT(7) #define P2C_RG_DPPULLDOWN BIT(6) #define P2C_RG_XCVRSEL GENMASK(5, 4) -#define P2C_RG_XCVRSEL_VAL(x) ((0x3 & (x)) << 4) #define P2C_RG_SUSPENDM BIT(3) #define P2C_RG_TERMSEL BIT(2) #define P2C_DTM0_PART_MASK \ @@ -104,72 +113,53 @@ #define U3P_U3_PHYA_REG0 0x000 #define P3A_RG_CLKDRV_OFF GENMASK(3, 2) -#define P3A_RG_CLKDRV_OFF_VAL(x) ((0x3 & (x)) << 2) #define U3P_U3_PHYA_REG1 0x004 #define P3A_RG_CLKDRV_AMP GENMASK(31, 29) -#define P3A_RG_CLKDRV_AMP_VAL(x) ((0x7 & (x)) << 29) #define U3P_U3_PHYA_REG6 0x018 #define P3A_RG_TX_EIDLE_CM GENMASK(31, 28) -#define P3A_RG_TX_EIDLE_CM_VAL(x) ((0xf & (x)) << 28) #define U3P_U3_PHYA_REG9 0x024 #define P3A_RG_RX_DAC_MUX GENMASK(5, 1) -#define P3A_RG_RX_DAC_MUX_VAL(x) ((0x1f & (x)) << 1) #define U3P_U3_PHYA_DA_REG0 0x100 #define P3A_RG_XTAL_EXT_PE2H GENMASK(17, 16) -#define P3A_RG_XTAL_EXT_PE2H_VAL(x) ((0x3 & (x)) << 16) #define P3A_RG_XTAL_EXT_PE1H GENMASK(13, 12) -#define P3A_RG_XTAL_EXT_PE1H_VAL(x) ((0x3 & (x)) << 12) #define P3A_RG_XTAL_EXT_EN_U3 GENMASK(11, 10) -#define P3A_RG_XTAL_EXT_EN_U3_VAL(x) ((0x3 & (x)) << 10) #define U3P_U3_PHYA_DA_REG4 0x108 #define P3A_RG_PLL_DIVEN_PE2H GENMASK(21, 19) #define P3A_RG_PLL_BC_PE2H GENMASK(7, 6) -#define P3A_RG_PLL_BC_PE2H_VAL(x) ((0x3 & (x)) << 6) #define U3P_U3_PHYA_DA_REG5 0x10c #define P3A_RG_PLL_BR_PE2H GENMASK(29, 28) -#define P3A_RG_PLL_BR_PE2H_VAL(x) ((0x3 & (x)) << 28) #define P3A_RG_PLL_IC_PE2H GENMASK(15, 12) -#define P3A_RG_PLL_IC_PE2H_VAL(x) ((0xf & (x)) << 12) #define U3P_U3_PHYA_DA_REG6 0x110 #define P3A_RG_PLL_IR_PE2H GENMASK(19, 16) -#define P3A_RG_PLL_IR_PE2H_VAL(x) ((0xf & (x)) << 16) #define U3P_U3_PHYA_DA_REG7 0x114 #define P3A_RG_PLL_BP_PE2H GENMASK(19, 16) -#define P3A_RG_PLL_BP_PE2H_VAL(x) ((0xf & (x)) << 16) #define U3P_U3_PHYA_DA_REG20 0x13c #define P3A_RG_PLL_DELTA1_PE2H GENMASK(31, 16) -#define P3A_RG_PLL_DELTA1_PE2H_VAL(x) ((0xffff & (x)) << 16) #define U3P_U3_PHYA_DA_REG25 0x148 #define P3A_RG_PLL_DELTA_PE2H GENMASK(15, 0) -#define P3A_RG_PLL_DELTA_PE2H_VAL(x) (0xffff & (x)) #define U3P_U3_PHYD_LFPS1 0x00c #define P3D_RG_FWAKE_TH GENMASK(21, 16) -#define P3D_RG_FWAKE_TH_VAL(x) ((0x3f & (x)) << 16) #define U3P_U3_PHYD_CDR1 0x05c #define P3D_RG_CDR_BIR_LTD1 GENMASK(28, 24) -#define P3D_RG_CDR_BIR_LTD1_VAL(x) ((0x1f & (x)) << 24) #define P3D_RG_CDR_BIR_LTD0 GENMASK(12, 8) -#define P3D_RG_CDR_BIR_LTD0_VAL(x) ((0x1f & (x)) << 8) #define U3P_U3_PHYD_RXDET1 0x128 #define P3D_RG_RXDET_STB2_SET GENMASK(17, 9) -#define P3D_RG_RXDET_STB2_SET_VAL(x) ((0x1ff & (x)) << 9) #define U3P_U3_PHYD_RXDET2 0x12c #define P3D_RG_RXDET_STB2_SET_P3 GENMASK(8, 0) -#define P3D_RG_RXDET_STB2_SET_P3_VAL(x) (0x1ff & (x)) #define U3P_SPLLC_XTALCTL3 0x018 #define XC3_RG_U3_XTAL_RX_PWD BIT(9) @@ -179,66 +169,62 @@ #define PHYD_CTRL_SIGNAL_MODE4 0x1c /* CDR Charge Pump P-path current adjustment */ #define RG_CDR_BICLTD1_GEN1_MSK GENMASK(23, 20) -#define RG_CDR_BICLTD1_GEN1_VAL(x) ((0xf & (x)) << 20) #define RG_CDR_BICLTD0_GEN1_MSK GENMASK(11, 8) -#define RG_CDR_BICLTD0_GEN1_VAL(x) ((0xf & (x)) << 8) #define PHYD_DESIGN_OPTION2 0x24 /* Symbol lock count selection */ #define RG_LOCK_CNT_SEL_MSK GENMASK(5, 4) -#define RG_LOCK_CNT_SEL_VAL(x) ((0x3 & (x)) << 4) #define PHYD_DESIGN_OPTION9 0x40 /* COMWAK GAP width window */ #define RG_TG_MAX_MSK GENMASK(20, 16) -#define RG_TG_MAX_VAL(x) ((0x1f & (x)) << 16) /* COMINIT GAP width window */ #define RG_T2_MAX_MSK GENMASK(13, 8) -#define RG_T2_MAX_VAL(x) ((0x3f & (x)) << 8) /* COMWAK GAP width window */ #define RG_TG_MIN_MSK GENMASK(7, 5) -#define RG_TG_MIN_VAL(x) ((0x7 & (x)) << 5) /* COMINIT GAP width window */ #define RG_T2_MIN_MSK GENMASK(4, 0) -#define RG_T2_MIN_VAL(x) (0x1f & (x)) #define ANA_RG_CTRL_SIGNAL1 0x4c /* TX driver tail current control for 0dB de-empahsis mdoe for Gen1 speed */ #define RG_IDRV_0DB_GEN1_MSK GENMASK(13, 8) -#define RG_IDRV_0DB_GEN1_VAL(x) ((0x3f & (x)) << 8) #define ANA_RG_CTRL_SIGNAL4 0x58 #define RG_CDR_BICLTR_GEN1_MSK GENMASK(23, 20) -#define RG_CDR_BICLTR_GEN1_VAL(x) ((0xf & (x)) << 20) /* Loop filter R1 resistance adjustment for Gen1 speed */ #define RG_CDR_BR_GEN2_MSK GENMASK(10, 8) -#define RG_CDR_BR_GEN2_VAL(x) ((0x7 & (x)) << 8) #define ANA_RG_CTRL_SIGNAL6 0x60 /* I-path capacitance adjustment for Gen1 */ #define RG_CDR_BC_GEN1_MSK GENMASK(28, 24) -#define RG_CDR_BC_GEN1_VAL(x) ((0x1f & (x)) << 24) #define RG_CDR_BIRLTR_GEN1_MSK GENMASK(4, 0) -#define RG_CDR_BIRLTR_GEN1_VAL(x) (0x1f & (x)) #define ANA_EQ_EYE_CTRL_SIGNAL1 0x6c /* RX Gen1 LEQ tuning step */ #define RG_EQ_DLEQ_LFI_GEN1_MSK GENMASK(11, 8) -#define RG_EQ_DLEQ_LFI_GEN1_VAL(x) ((0xf & (x)) << 8) #define ANA_EQ_EYE_CTRL_SIGNAL4 0xd8 #define RG_CDR_BIRLTD0_GEN1_MSK GENMASK(20, 16) -#define RG_CDR_BIRLTD0_GEN1_VAL(x) ((0x1f & (x)) << 16) #define ANA_EQ_EYE_CTRL_SIGNAL5 0xdc #define RG_CDR_BIRLTD0_GEN3_MSK GENMASK(4, 0) -#define RG_CDR_BIRLTD0_GEN3_VAL(x) (0x1f & (x)) enum mtk_phy_version { MTK_TPHY_V1 = 1, MTK_TPHY_V2, }; +struct tphy_pdata { + enum mtk_phy_version version; + + /* + * workaround only for mt8195: + * u2phy should use integer mode instead of fractional mode of + * 48M PLL, fix it by switching PLL to 26M from default 48M + */ + bool sw_pll_48m_to_26m; +}; + struct u2phy_banks { void __iomem *misc; void __iomem *fmreg; @@ -269,11 +255,32 @@ struct mtk_phy_instance { struct mtk_tphy { struct udevice *dev; void __iomem *sif_base; - enum mtk_phy_version version; + const struct tphy_pdata *pdata; struct mtk_phy_instance **phys; int nphys; }; +/* workaround only for mt8195 */ +static void u2_phy_pll_26m_set(struct mtk_tphy *tphy, + struct mtk_phy_instance *instance) +{ + struct u2phy_banks *u2_banks = &instance->u2_banks; + + if (!tphy->pdata->sw_pll_48m_to_26m) + return; + + clrsetbits_le32(u2_banks->com + U3P_USBPHYACR0, PA0_USB20_PLL_PREDIV, + FIELD_PREP(PA0_USB20_PLL_PREDIV, 0)); + + clrsetbits_le32(u2_banks->com + U3P_USBPHYACR2, PA2_RG_U2PLL_BW, + FIELD_PREP(PA2_RG_U2PLL_BW, 3)); + + writel(P2R_RG_U2PLL_FBDIV_26M, u2_banks->com + U3P_U2PHYA_RESV); + + setbits_le32(u2_banks->com + U3P_U2PHYA_RESV1, + P2R_RG_U2PLL_FRA_EN | P2R_RG_U2PLL_REFCLK_SEL); +} + static void u2_phy_instance_init(struct mtk_tphy *tphy, struct mtk_phy_instance *instance) { @@ -282,7 +289,8 @@ static void u2_phy_instance_init(struct mtk_tphy *tphy, /* switch to USB function, and enable usb pll */ clrsetbits_le32(u2_banks->com + U3P_U2PHYDTM0, P2C_FORCE_UART_EN | P2C_FORCE_SUSPENDM, - P2C_RG_XCVRSEL_VAL(1) | P2C_RG_DATAIN_VAL(0)); + FIELD_PREP(P2C_RG_XCVRSEL, 1) | + FIELD_PREP(P2C_RG_DATAIN, 0)); clrbits_le32(u2_banks->com + U3P_U2PHYDTM1, P2C_RG_UART_EN); setbits_le32(u2_banks->com + U3P_USBPHYACR0, PA0_RG_USB20_INTR_EN); @@ -295,11 +303,14 @@ static void u2_phy_instance_init(struct mtk_tphy *tphy, /* DP/DM BC1.1 path Disable */ clrsetbits_le32(u2_banks->com + U3P_USBPHYACR6, PA6_RG_U2_BC11_SW_EN | PA6_RG_U2_SQTH, - PA6_RG_U2_SQTH_VAL(2)); + FIELD_PREP(PA6_RG_U2_SQTH, 2)); /* set HS slew rate */ clrsetbits_le32(u2_banks->com + U3P_USBPHYACR5, - PA5_RG_U2_HSTX_SRCTRL, PA5_RG_U2_HSTX_SRCTRL_VAL(4)); + PA5_RG_U2_HSTX_SRCTRL, + FIELD_PREP(PA5_RG_U2_HSTX_SRCTRL, 4)); + + u2_phy_pll_26m_set(tphy, instance); dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index); } @@ -351,28 +362,31 @@ static void u3_phy_instance_init(struct mtk_tphy *tphy, /* gating XSQ */ clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG0, - P3A_RG_XTAL_EXT_EN_U3, P3A_RG_XTAL_EXT_EN_U3_VAL(2)); + P3A_RG_XTAL_EXT_EN_U3, + FIELD_PREP(P3A_RG_XTAL_EXT_EN_U3, 2)); clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_REG9, - P3A_RG_RX_DAC_MUX, P3A_RG_RX_DAC_MUX_VAL(4)); + P3A_RG_RX_DAC_MUX, FIELD_PREP(P3A_RG_RX_DAC_MUX, 4)); clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_REG6, - P3A_RG_TX_EIDLE_CM, P3A_RG_TX_EIDLE_CM_VAL(0xe)); + P3A_RG_TX_EIDLE_CM, + FIELD_PREP(P3A_RG_TX_EIDLE_CM, 0xe)); clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_CDR1, P3D_RG_CDR_BIR_LTD0 | P3D_RG_CDR_BIR_LTD1, - P3D_RG_CDR_BIR_LTD0_VAL(0xc) | - P3D_RG_CDR_BIR_LTD1_VAL(0x3)); + FIELD_PREP(P3D_RG_CDR_BIR_LTD0, 0xc) | + FIELD_PREP(P3D_RG_CDR_BIR_LTD1, 0x3)); clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_LFPS1, - P3D_RG_FWAKE_TH, P3D_RG_FWAKE_TH_VAL(0x34)); + P3D_RG_FWAKE_TH, FIELD_PREP(P3D_RG_FWAKE_TH, 0x34)); clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_RXDET1, - P3D_RG_RXDET_STB2_SET, P3D_RG_RXDET_STB2_SET_VAL(0x10)); + P3D_RG_RXDET_STB2_SET, + FIELD_PREP(P3D_RG_RXDET_STB2_SET, 0x10)); clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_RXDET2, P3D_RG_RXDET_STB2_SET_P3, - P3D_RG_RXDET_STB2_SET_P3_VAL(0x10)); + FIELD_PREP(P3D_RG_RXDET_STB2_SET_P3, 0x10)); dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index); } @@ -382,50 +396,52 @@ static void pcie_phy_instance_init(struct mtk_tphy *tphy, { struct u3phy_banks *u3_banks = &instance->u3_banks; - if (tphy->version != MTK_TPHY_V1) + if (tphy->pdata->version != MTK_TPHY_V1) return; clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG0, P3A_RG_XTAL_EXT_PE1H | P3A_RG_XTAL_EXT_PE2H, - P3A_RG_XTAL_EXT_PE1H_VAL(0x2) | - P3A_RG_XTAL_EXT_PE2H_VAL(0x2)); + FIELD_PREP(P3A_RG_XTAL_EXT_PE1H, 0x2) | + FIELD_PREP(P3A_RG_XTAL_EXT_PE2H, 0x2)); /* ref clk drive */ clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_REG1, P3A_RG_CLKDRV_AMP, - P3A_RG_CLKDRV_AMP_VAL(0x4)); + FIELD_PREP(P3A_RG_CLKDRV_AMP, 0x4)); clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_REG0, P3A_RG_CLKDRV_OFF, - P3A_RG_CLKDRV_OFF_VAL(0x1)); + FIELD_PREP(P3A_RG_CLKDRV_OFF, 0x1)); /* SSC delta -5000ppm */ clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG20, P3A_RG_PLL_DELTA1_PE2H, - P3A_RG_PLL_DELTA1_PE2H_VAL(0x3c)); + FIELD_PREP(P3A_RG_PLL_DELTA1_PE2H, 0x3c)); clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG25, P3A_RG_PLL_DELTA_PE2H, - P3A_RG_PLL_DELTA_PE2H_VAL(0x36)); + FIELD_PREP(P3A_RG_PLL_DELTA_PE2H, 0x36)); /* change pll BW 0.6M */ clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG5, P3A_RG_PLL_BR_PE2H | P3A_RG_PLL_IC_PE2H, - P3A_RG_PLL_BR_PE2H_VAL(0x1) | - P3A_RG_PLL_IC_PE2H_VAL(0x1)); + FIELD_PREP(P3A_RG_PLL_BR_PE2H, 0x1) | + FIELD_PREP(P3A_RG_PLL_IC_PE2H, 0x1)); clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG4, P3A_RG_PLL_DIVEN_PE2H | P3A_RG_PLL_BC_PE2H, - P3A_RG_PLL_BC_PE2H_VAL(0x3)); + FIELD_PREP(P3A_RG_PLL_BC_PE2H, 0x3)); clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG6, - P3A_RG_PLL_IR_PE2H, P3A_RG_PLL_IR_PE2H_VAL(0x2)); + P3A_RG_PLL_IR_PE2H, + FIELD_PREP(P3A_RG_PLL_IR_PE2H, 0x2)); clrsetbits_le32(u3_banks->phya + U3P_U3_PHYA_DA_REG7, - P3A_RG_PLL_BP_PE2H, P3A_RG_PLL_BP_PE2H_VAL(0xa)); + P3A_RG_PLL_BP_PE2H, + FIELD_PREP(P3A_RG_PLL_BP_PE2H, 0xa)); /* Tx Detect Rx Timing: 10us -> 5us */ clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_RXDET1, P3D_RG_RXDET_STB2_SET, - P3D_RG_RXDET_STB2_SET_VAL(0x10)); + FIELD_PREP(P3D_RG_RXDET_STB2_SET, 0x10)); clrsetbits_le32(u3_banks->phyd + U3P_U3_PHYD_RXDET2, P3D_RG_RXDET_STB2_SET_P3, - P3D_RG_RXDET_STB2_SET_P3_VAL(0x10)); + FIELD_PREP(P3D_RG_RXDET_STB2_SET_P3, 0x10)); /* wait for PCIe subsys register to active */ udelay(3000); @@ -438,36 +454,38 @@ static void sata_phy_instance_init(struct mtk_tphy *tphy, clrsetbits_le32(u3_banks->phyd + ANA_RG_CTRL_SIGNAL6, RG_CDR_BIRLTR_GEN1_MSK | RG_CDR_BC_GEN1_MSK, - RG_CDR_BIRLTR_GEN1_VAL(0x6) | - RG_CDR_BC_GEN1_VAL(0x1a)); + FIELD_PREP(RG_CDR_BIRLTR_GEN1_MSK, 0x6) | + FIELD_PREP(RG_CDR_BC_GEN1_MSK, 0x1a)); clrsetbits_le32(u3_banks->phyd + ANA_EQ_EYE_CTRL_SIGNAL4, RG_CDR_BIRLTD0_GEN1_MSK, - RG_CDR_BIRLTD0_GEN1_VAL(0x18)); + FIELD_PREP(RG_CDR_BIRLTD0_GEN1_MSK, 0x18)); clrsetbits_le32(u3_banks->phyd + ANA_EQ_EYE_CTRL_SIGNAL5, RG_CDR_BIRLTD0_GEN3_MSK, - RG_CDR_BIRLTD0_GEN3_VAL(0x06)); + FIELD_PREP(RG_CDR_BIRLTD0_GEN3_MSK, 0x06)); clrsetbits_le32(u3_banks->phyd + ANA_RG_CTRL_SIGNAL4, RG_CDR_BICLTR_GEN1_MSK | RG_CDR_BR_GEN2_MSK, - RG_CDR_BICLTR_GEN1_VAL(0x0c) | - RG_CDR_BR_GEN2_VAL(0x07)); + FIELD_PREP(RG_CDR_BICLTR_GEN1_MSK, 0x0c) | + FIELD_PREP(RG_CDR_BR_GEN2_MSK, 0x07)); clrsetbits_le32(u3_banks->phyd + PHYD_CTRL_SIGNAL_MODE4, RG_CDR_BICLTD0_GEN1_MSK | RG_CDR_BICLTD1_GEN1_MSK, - RG_CDR_BICLTD0_GEN1_VAL(0x08) | - RG_CDR_BICLTD1_GEN1_VAL(0x02)); + FIELD_PREP(RG_CDR_BICLTD0_GEN1_MSK, 0x08) | + FIELD_PREP(RG_CDR_BICLTD1_GEN1_MSK, 0x02)); clrsetbits_le32(u3_banks->phyd + PHYD_DESIGN_OPTION2, RG_LOCK_CNT_SEL_MSK, - RG_LOCK_CNT_SEL_VAL(0x02)); + FIELD_PREP(RG_LOCK_CNT_SEL_MSK, 0x02)); clrsetbits_le32(u3_banks->phyd + PHYD_DESIGN_OPTION9, RG_T2_MIN_MSK | RG_TG_MIN_MSK | RG_T2_MAX_MSK | RG_TG_MAX_MSK, - RG_T2_MIN_VAL(0x12) | RG_TG_MIN_VAL(0x04) | - RG_T2_MAX_VAL(0x31) | RG_TG_MAX_VAL(0x0e)); + FIELD_PREP(RG_T2_MIN_MSK, 0x12) | + FIELD_PREP(RG_TG_MIN_MSK, 0x04) | + FIELD_PREP(RG_T2_MAX_MSK, 0x31) | + FIELD_PREP(RG_TG_MAX_MSK, 0x0e)); clrsetbits_le32(u3_banks->phyd + ANA_RG_CTRL_SIGNAL1, RG_IDRV_0DB_GEN1_MSK, - RG_IDRV_0DB_GEN1_VAL(0x20)); + FIELD_PREP(RG_IDRV_0DB_GEN1_MSK, 0x20)); clrsetbits_le32(u3_banks->phyd + ANA_EQ_EYE_CTRL_SIGNAL1, RG_EQ_DLEQ_LFI_GEN1_MSK, - RG_EQ_DLEQ_LFI_GEN1_VAL(0x03)); + FIELD_PREP(RG_EQ_DLEQ_LFI_GEN1_MSK, 0x03)); } static void pcie_phy_instance_power_on(struct mtk_tphy *tphy, @@ -662,11 +680,14 @@ static int mtk_phy_xlate(struct phy *phy, return -EINVAL; } - if (tphy->version == MTK_TPHY_V1) { + switch (tphy->pdata->version) { + case MTK_TPHY_V1: phy_v1_banks_init(tphy, instance); - } else if (tphy->version == MTK_TPHY_V2) { + break; + case MTK_TPHY_V2: phy_v2_banks_init(tphy, instance); - } else { + break; + default: dev_err(phy->dev, "phy version is not supported\n"); return -EINVAL; } @@ -696,13 +717,12 @@ static int mtk_tphy_probe(struct udevice *dev) return -ENOMEM; tphy->dev = dev; - tphy->version = dev_get_driver_data(dev); + tphy->pdata = (void *)dev_get_driver_data(dev); /* v1 has shared banks for usb/pcie mode, */ /* but not for sata mode */ - if (tphy->version == MTK_TPHY_V1) { + if (tphy->pdata->version == MTK_TPHY_V1) tphy->sif_base = dev_read_addr_ptr(dev); - } dev_for_each_subnode(subnode, dev) { struct mtk_phy_instance *instance; @@ -737,9 +757,32 @@ static int mtk_tphy_probe(struct udevice *dev) return 0; } +static struct tphy_pdata tphy_v1_pdata = { + .version = MTK_TPHY_V1, +}; + +static struct tphy_pdata tphy_v2_pdata = { + .version = MTK_TPHY_V2, +}; + +static struct tphy_pdata mt8195_pdata = { + .version = MTK_TPHY_V2, + .sw_pll_48m_to_26m = true, +}; + static const struct udevice_id mtk_tphy_id_table[] = { - { .compatible = "mediatek,generic-tphy-v1", .data = MTK_TPHY_V1, }, - { .compatible = "mediatek,generic-tphy-v2", .data = MTK_TPHY_V2, }, + { + .compatible = "mediatek,generic-tphy-v1", + .data = (ulong)&tphy_v1_pdata, + }, + { + .compatible = "mediatek,generic-tphy-v2", + .data = (ulong)&tphy_v2_pdata, + }, + { + .compatible = "mediatek,mt8195-tphy", + .data = (ulong)&mt8195_pdata, + }, { } }; diff --git a/drivers/phy/socionext/Kconfig b/drivers/phy/socionext/Kconfig index bcd579e98e..de87d5b010 100644 --- a/drivers/phy/socionext/Kconfig +++ b/drivers/phy/socionext/Kconfig @@ -10,3 +10,11 @@ config PHY_UNIPHIER_PCIE help Enable this to support PHY implemented in PCIe controller on UniPhier SoCs. + +config PHY_UNIPHIER_USB3 + bool "UniPhier USB3 PHY driver" + depends on PHY && ARCH_UNIPHIER + imply REGMAP + help + Enable this to support PHY implemented in USB3 controller + on UniPhier SoCs. diff --git a/drivers/phy/socionext/Makefile b/drivers/phy/socionext/Makefile index 5484360b70..94d3aa68cf 100644 --- a/drivers/phy/socionext/Makefile +++ b/drivers/phy/socionext/Makefile @@ -4,3 +4,4 @@ # obj-$(CONFIG_PHY_UNIPHIER_PCIE) += phy-uniphier-pcie.o +obj-$(CONFIG_PHY_UNIPHIER_USB3) += phy-uniphier-usb3.o diff --git a/drivers/phy/socionext/phy-uniphier-usb3.c b/drivers/phy/socionext/phy-uniphier-usb3.c new file mode 100644 index 0000000000..1d65b0b08f --- /dev/null +++ b/drivers/phy/socionext/phy-uniphier-usb3.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * phy_uniphier_usb3.c - Socionext UniPhier Usb3 PHY driver + * Copyright 2019-2023 Socionext, Inc. + */ + +#include <common.h> +#include <dm.h> +#include <generic-phy.h> + +#include <clk.h> +#include <reset.h> + +struct uniphier_usb3phy_priv { + struct clk *clk_link, *clk_phy, *clk_parent, *clk_phyext; + struct reset_ctl *rst_link, *rst_phy, *rst_parent; +}; + +static int uniphier_usb3phy_init(struct phy *phy) +{ + struct uniphier_usb3phy_priv *priv = dev_get_priv(phy->dev); + int ret; + + ret = clk_enable(priv->clk_phy); + if (ret) + return ret; + + ret = reset_deassert(priv->rst_phy); + if (ret) + goto out_clk; + + if (priv->clk_phyext) { + ret = clk_enable(priv->clk_phyext); + if (ret) + goto out_rst; + } + + return 0; + +out_rst: + reset_assert(priv->rst_phy); +out_clk: + clk_disable(priv->clk_phy); + + return ret; +} + +static int uniphier_usb3phy_exit(struct phy *phy) +{ + struct uniphier_usb3phy_priv *priv = dev_get_priv(phy->dev); + + if (priv->clk_phyext) + clk_disable(priv->clk_phyext); + + reset_assert(priv->rst_phy); + clk_disable(priv->clk_phy); + + return 0; +} + +static int uniphier_usb3phy_probe(struct udevice *dev) +{ + struct uniphier_usb3phy_priv *priv = dev_get_priv(dev); + int ret; + + priv->clk_link = devm_clk_get(dev, "link"); + if (IS_ERR(priv->clk_link)) { + printf("Failed to get link clock\n"); + return PTR_ERR(priv->clk_link); + } + + priv->clk_phy = devm_clk_get(dev, "phy"); + if (IS_ERR(priv->clk_link)) { + printf("Failed to get phy clock\n"); + return PTR_ERR(priv->clk_link); + } + + priv->clk_parent = devm_clk_get_optional(dev, "gio"); + if (IS_ERR(priv->clk_parent)) { + printf("Failed to get parent clock\n"); + return PTR_ERR(priv->clk_parent); + } + + priv->clk_phyext = devm_clk_get_optional(dev, "phy-ext"); + if (IS_ERR(priv->clk_phyext)) { + printf("Failed to get external phy clock\n"); + return PTR_ERR(priv->clk_phyext); + } + + priv->rst_link = devm_reset_control_get(dev, "link"); + if (IS_ERR(priv->rst_link)) { + printf("Failed to get link reset\n"); + return PTR_ERR(priv->rst_link); + } + + priv->rst_phy = devm_reset_control_get(dev, "phy"); + if (IS_ERR(priv->rst_phy)) { + printf("Failed to get phy reset\n"); + return PTR_ERR(priv->rst_phy); + } + + priv->rst_parent = devm_reset_control_get_optional(dev, "gio"); + if (IS_ERR(priv->rst_parent)) { + printf("Failed to get parent reset\n"); + return PTR_ERR(priv->rst_parent); + } + + if (priv->clk_parent) { + ret = clk_enable(priv->clk_parent); + if (ret) + return ret; + } + if (priv->rst_parent) { + ret = reset_deassert(priv->rst_parent); + if (ret) + goto out_clk_parent; + } + + ret = clk_enable(priv->clk_link); + if (ret) + goto out_rst_parent; + + ret = reset_deassert(priv->rst_link); + if (ret) + goto out_clk; + + return 0; + +out_clk: + clk_disable(priv->clk_link); +out_rst_parent: + if (priv->rst_parent) + reset_assert(priv->rst_parent); +out_clk_parent: + if (priv->clk_parent) + clk_disable(priv->clk_parent); + + return ret; +} + +static struct phy_ops uniphier_usb3phy_ops = { + .init = uniphier_usb3phy_init, + .exit = uniphier_usb3phy_exit, +}; + +static const struct udevice_id uniphier_usb3phy_ids[] = { + { .compatible = "socionext,uniphier-pro4-usb3-ssphy" }, + { .compatible = "socionext,uniphier-pro5-usb3-hsphy" }, + { .compatible = "socionext,uniphier-pro5-usb3-ssphy" }, + { .compatible = "socionext,uniphier-pxs2-usb3-hsphy" }, + { .compatible = "socionext,uniphier-pxs2-usb3-ssphy" }, + { .compatible = "socionext,uniphier-ld20-usb3-hsphy" }, + { .compatible = "socionext,uniphier-ld20-usb3-ssphy" }, + { .compatible = "socionext,uniphier-pxs3-usb3-hsphy" }, + { .compatible = "socionext,uniphier-pxs3-usb3-ssphy" }, + { .compatible = "socionext,uniphier-nx1-usb3-hsphy" }, + { .compatible = "socionext,uniphier-nx1-usb3-ssphy" }, + { } +}; + +U_BOOT_DRIVER(uniphier_usb3_phy) = { + .name = "uniphier-usb3-phy", + .id = UCLASS_PHY, + .of_match = uniphier_usb3phy_ids, + .ops = &uniphier_usb3phy_ops, + .probe = uniphier_usb3phy_probe, + .priv_auto = sizeof(struct uniphier_usb3phy_priv), +}; diff --git a/drivers/ram/aspeed/sdram_ast2600.c b/drivers/ram/aspeed/sdram_ast2600.c index 1876755412..d463933363 100644 --- a/drivers/ram/aspeed/sdram_ast2600.c +++ b/drivers/ram/aspeed/sdram_ast2600.c @@ -1089,13 +1089,13 @@ static int ast2600_sdrammc_probe(struct udevice *dev) } reg = readl(&priv->scu->mpll); - reg &= ~(SCU_PLL_BYPASS | SCU_PLL_DIV_MASK | + reg &= ~(SCU_PLL_BYPASS | SCU_PLL_OFF | SCU_PLL_DIV_MASK | SCU_PLL_DENUM_MASK | SCU_PLL_NUM_MASK); - reg |= (SCU_PLL_RST | SCU_PLL_OFF | SCU_MPLL_FREQ_CFG); + reg |= (SCU_PLL_RST | SCU_MPLL_FREQ_CFG); writel(reg, &priv->scu->mpll); writel(SCU_MPLL_EXT_CFG, &priv->scu->mpll_ext); udelay(100); - reg &= ~(SCU_PLL_RST | SCU_PLL_OFF); + reg &= ~SCU_PLL_RST; writel(reg, &priv->scu->mpll); while ((readl(&priv->scu->mpll_ext) & BIT(31)) == 0) diff --git a/drivers/reset/reset-uniphier.c b/drivers/reset/reset-uniphier.c index 7adae51873..35e3ccebd7 100644 --- a/drivers/reset/reset-uniphier.c +++ b/drivers/reset/reset-uniphier.c @@ -2,6 +2,7 @@ /* * Copyright (C) 2016 Socionext Inc. * Author: Masahiro Yamada <yamada.masahiro@socionext.com> + * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> */ #include <common.h> @@ -9,6 +10,8 @@ #include <log.h> #include <malloc.h> #include <reset-uclass.h> +#include <clk.h> +#include <reset.h> #include <dm/device_compat.h> #include <linux/bitops.h> #include <linux/io.h> @@ -178,10 +181,17 @@ static const struct uniphier_reset_data uniphier_pro4_peri_reset_data[] = { UNIPHIER_RESET_END, }; +/* Glue reset data */ +static const struct uniphier_reset_data uniphier_pro4_usb3_reset_data[] = { + UNIPHIER_RESETX(15, 0, 15) +}; + /* core implementaton */ struct uniphier_reset_priv { void __iomem *base; const struct uniphier_reset_data *data; + struct clk_bulk clks; + struct reset_ctl_bulk rsts; }; static int uniphier_reset_update(struct reset_ctl *reset_ctl, int assert) @@ -233,10 +243,47 @@ static const struct reset_ops uniphier_reset_ops = { .rst_deassert = uniphier_reset_deassert, }; +static int uniphier_reset_rst_init(struct udevice *dev) +{ + struct uniphier_reset_priv *priv = dev_get_priv(dev); + int ret; + + ret = reset_get_bulk(dev, &priv->rsts); + if (ret == -ENOSYS || ret == -ENOENT) + return 0; + else if (ret) + return ret; + + ret = reset_deassert_bulk(&priv->rsts); + if (ret) + reset_release_bulk(&priv->rsts); + + return ret; +} + +static int uniphier_reset_clk_init(struct udevice *dev) +{ + struct uniphier_reset_priv *priv = dev_get_priv(dev); + int ret; + + ret = clk_get_bulk(dev, &priv->clks); + if (ret == -ENOSYS || ret == -ENOENT) + return 0; + if (ret) + return ret; + + ret = clk_enable_bulk(&priv->clks); + if (ret) + clk_release_bulk(&priv->clks); + + return ret; +} + static int uniphier_reset_probe(struct udevice *dev) { struct uniphier_reset_priv *priv = dev_get_priv(dev); fdt_addr_t addr; + int ret; addr = dev_read_addr(dev->parent); if (addr == FDT_ADDR_T_NONE) @@ -248,7 +295,11 @@ static int uniphier_reset_probe(struct udevice *dev) priv->data = (void *)dev_get_driver_data(dev); - return 0; + ret = uniphier_reset_clk_init(dev); + if (ret) + return ret; + + return uniphier_reset_rst_init(dev); } static const struct udevice_id uniphier_reset_match[] = { @@ -355,6 +406,31 @@ static const struct udevice_id uniphier_reset_match[] = { .compatible = "socionext,uniphier-pxs3-peri-reset", .data = (ulong)uniphier_pro4_peri_reset_data, }, + /* USB glue reset */ + { + .compatible = "socionext,uniphier-pro4-usb3-reset", + .data = (ulong)uniphier_pro4_usb3_reset_data, + }, + { + .compatible = "socionext,uniphier-pro5-usb3-reset", + .data = (ulong)uniphier_pro4_usb3_reset_data, + }, + { + .compatible = "socionext,uniphier-pxs2-usb3-reset", + .data = (ulong)uniphier_pro4_usb3_reset_data, + }, + { + .compatible = "socionext,uniphier-ld20-usb3-reset", + .data = (ulong)uniphier_pro4_usb3_reset_data, + }, + { + .compatible = "socionext,uniphier-pxs3-usb3-reset", + .data = (ulong)uniphier_pro4_usb3_reset_data, + }, + { + .compatible = "socionext,uniphier-nx1-usb3-reset", + .data = (ulong)uniphier_pro4_usb3_reset_data, + }, { /* sentinel */ } }; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 35b6ed4d7c..fcfda2847c 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -231,6 +231,24 @@ config RTC_M41T62 Enable driver for ST's M41T62 compatible RTC devices (like RV-4162). It is a serial (I2C) real-time clock (RTC) with alarm. +config RTC_SANDBOX + bool "Enable sandbox RTC driver" + depends on SANDBOX && DM_RTC + default y + help + Enable the sandbox RTC driver. This driver connects to the RTC + emulator and is used to test the RTC uclasses and associated code, + as well as the I2C subsystem. + +config SPL_RTC_SANDBOX + bool "Enable sandbox RTC driver (SPL)" + depends on SANDBOX && SPL_DM_RTC + default y + help + Enable the sandbox RTC driver. This driver connects to the RTC + emulator and is used to test the RTC uclasses and associated code, + as well as the I2C subsystem. + config RTC_STM32 bool "Enable STM32 RTC driver" depends on DM_RTC diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 447551e15a..b6c9029c8f 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -16,7 +16,7 @@ obj-$(CONFIG_RTC_DS3231) += ds3231.o obj-$(CONFIG_RTC_DS3232) += ds3232.o obj-$(CONFIG_RTC_EMULATION) += emul_rtc.o obj-$(CONFIG_RTC_HT1380) += ht1380.o -obj-$(CONFIG_SANDBOX) += i2c_rtc_emul.o +obj-$(CONFIG_$(SPL_TPL_)RTC_SANDBOX) += i2c_rtc_emul.o obj-$(CONFIG_RTC_ISL1208) += isl1208.o obj-$(CONFIG_RTC_M41T62) += m41t62.o obj-$(CONFIG_RTC_MC13XXX) += mc13xxx-rtc.o @@ -35,6 +35,6 @@ obj-$(CONFIG_RTC_RX8025) += rx8025.o obj-$(CONFIG_RTC_RX8010SJ) += rx8010sj.o obj-$(CONFIG_RTC_S35392A) += s35392a.o obj-$(CONFIG_RTC_STM32) += stm32_rtc.o -obj-$(CONFIG_SANDBOX) += sandbox_rtc.o +obj-$(CONFIG_$(SPL_TPL_)RTC_SANDBOX) += sandbox_rtc.o obj-$(CONFIG_RTC_ABX80X) += abx80x.o obj-$(CONFIG_RTC_ZYNQMP) += zynqmp_rtc.o diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index bb5083201b..10d07daf27 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -415,6 +415,14 @@ config DEBUG_UART_SEMIHOSTING start up driver model. The driver will be available until the real driver model serial is running. +config DEBUG_UART_SCIF + bool "Renesas SCIF UART" + depends on SH || ARCH_RMOBILE + help + Select this to enable a debug UART using the serial_sh driver. You + will need to provide parameters to make this work. The driver will + be available until the real driver-model serial is running. + config DEBUG_UART_SIFIVE bool "SiFive UART" depends on SIFIVE_SERIAL diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c index 4671217b59..e08bdcadc9 100644 --- a/drivers/serial/serial_sh.c +++ b/drivers/serial/serial_sh.c @@ -249,9 +249,40 @@ U_BOOT_DRIVER(serial_sh) = { #endif .priv_auto = sizeof(struct uart_port), }; +#endif -#else /* CONFIG_DM_SERIAL */ +#if !CONFIG_IS_ENABLED(DM_SERIAL) || IS_ENABLED(CONFIG_DEBUG_UART_SCIF) +#if defined(CFG_SCIF_A) + #define SCIF_BASE_PORT PORT_SCIFA +#elif defined(CFG_SCI) + #define SCIF_BASE_PORT PORT_SCI +#else + #define SCIF_BASE_PORT PORT_SCIF +#endif + +static void sh_serial_init_nodm(struct uart_port *port) +{ + sh_serial_init_generic(port); + serial_setbrg(); +} + +static void sh_serial_putc_nondm(struct uart_port *port, const char c) +{ + if (c == '\n') { + while (1) { + if (serial_raw_putc(port, '\r') != -EAGAIN) + break; + } + } + while (1) { + if (serial_raw_putc(port, c) != -EAGAIN) + break; + } +} +#endif + +#if !CONFIG_IS_ENABLED(DM_SERIAL) #if defined(CONFIG_CONS_SCIF0) # define SCIF_BASE SCIF0_BASE #elif defined(CONFIG_CONS_SCIF1) @@ -274,19 +305,11 @@ U_BOOT_DRIVER(serial_sh) = { # error "Default SCIF doesn't set....." #endif -#if defined(CFG_SCIF_A) - #define SCIF_BASE_PORT PORT_SCIFA -#elif defined(CONFIG_SCI) - #define SCIF_BASE_PORT PORT_SCI -#else - #define SCIF_BASE_PORT PORT_SCIF -#endif - static struct uart_port sh_sci = { .membase = (unsigned char *)SCIF_BASE, .mapbase = SCIF_BASE, .type = SCIF_BASE_PORT, -#ifdef CONFIG_SCIF_USE_EXT_CLK +#ifdef CFG_SCIF_USE_EXT_CLK .clk_mode = EXT_CLK, #endif }; @@ -301,28 +324,14 @@ static void sh_serial_setbrg(void) static int sh_serial_init(void) { - struct uart_port *port = &sh_sci; - - sh_serial_init_generic(port); - serial_setbrg(); + sh_serial_init_nodm(&sh_sci); return 0; } static void sh_serial_putc(const char c) { - struct uart_port *port = &sh_sci; - - if (c == '\n') { - while (1) { - if (serial_raw_putc(port, '\r') != -EAGAIN) - break; - } - } - while (1) { - if (serial_raw_putc(port, c) != -EAGAIN) - break; - } + sh_serial_putc_nondm(&sh_sci, c); } static int sh_serial_tstc(void) @@ -367,3 +376,29 @@ __weak struct serial_device *default_serial_console(void) return &sh_serial_drv; } #endif /* CONFIG_DM_SERIAL */ + +#ifdef CONFIG_DEBUG_UART_SCIF +#include <debug_uart.h> + +static struct uart_port debug_uart_sci = { + .membase = (unsigned char *)CONFIG_DEBUG_UART_BASE, + .mapbase = CONFIG_DEBUG_UART_BASE, + .type = SCIF_BASE_PORT, +#ifdef CFG_SCIF_USE_EXT_CLK + .clk_mode = EXT_CLK, +#endif +}; + +static inline void _debug_uart_init(void) +{ + sh_serial_init_nodm(&debug_uart_sci); +} + +static inline void _debug_uart_putc(int c) +{ + sh_serial_putc_nondm(&debug_uart_sci, c); +} + +DEBUG_UART_FUNCS + +#endif diff --git a/drivers/serial/serial_sh.h b/drivers/serial/serial_sh.h index 660aaab663..eb8523dde5 100644 --- a/drivers/serial/serial_sh.h +++ b/drivers/serial/serial_sh.h @@ -406,13 +406,13 @@ SCIF_FNS(SCSPTR, 0, 0, 0x24, 16) SCIF_FNS(SCLSR, 0, 0, 0x28, 16) #else -SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) +SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) #if defined(CONFIG_CPU_SH7722) -SCIF_FNS(SCSPTR, 0, 0, 0, 0) +SCIF_FNS(SCSPTR, 0, 0, 0, 0) #else -SCIF_FNS(SCSPTR, 0, 0, 0x20, 16) +SCIF_FNS(SCSPTR, 0, 0, 0x20, 16) #endif -SCIF_FNS(SCLSR, 0, 0, 0x24, 16) +SCIF_FNS(SCLSR, 0, 0, 0x24, 16) #endif SCIF_FNS(DL, 0, 0, 0x0, 0) /* dummy */ #endif diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index 4e9115dafe..9e6255a172 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -112,10 +112,9 @@ struct xilinx_spi_priv { static int xilinx_spi_probe(struct udevice *bus) { struct xilinx_spi_priv *priv = dev_get_priv(bus); - struct xilinx_spi_regs *regs = priv->regs; - - priv->regs = (struct xilinx_spi_regs *)dev_read_addr(bus); + struct xilinx_spi_regs *regs; + regs = priv->regs = (struct xilinx_spi_regs *)dev_read_addr(bus); priv->fifo_depth = dev_read_u32_default(bus, "fifo-size", 0); writel(SPISSR_RESET_VALUE, ®s->srr); diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c index 335b458cb9..c4aee279aa 100644 --- a/drivers/spi/zynqmp_gqspi.c +++ b/drivers/spi/zynqmp_gqspi.c @@ -183,6 +183,11 @@ struct zynqmp_qspi_priv { const struct spi_mem_op *op; }; +__weak int zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value) +{ + return 0; +} + static int zynqmp_qspi_of_to_plat(struct udevice *bus) { struct zynqmp_qspi_plat *plat = dev_get_plat(bus); diff --git a/drivers/sysreset/sysreset_mpc83xx.c b/drivers/sysreset/sysreset_mpc83xx.c index c9a0326659..ca48328f7b 100644 --- a/drivers/sysreset/sysreset_mpc83xx.c +++ b/drivers/sysreset/sysreset_mpc83xx.c @@ -107,7 +107,7 @@ static int print_83xx_arb_event(bool force, char *buf, int size) if (!force && !gd->arch.arbiter_event_address) return 0; - if (CONFIG_IS_ENABLED(DISPLAY_AER_FULL)) { + if (IS_ENABLED(CONFIG_DISPLAY_AER_FULL)) { res = snprintf(buf, size, "Arbiter Event Status:\n" " %s: 0x%08lX\n" @@ -184,7 +184,7 @@ static int mpc83xx_sysreset_get_status(struct udevice *dev, char *buf, int size) * TODO(mario.six@gdsys.cc): Move this into a dedicated * arbiter driver */ - if (CONFIG_IS_ENABLED(DISPLAY_AER_FULL) || + if (IS_ENABLED(CONFIG_DISPLAY_AER_FULL) || IS_ENABLED(CONFIG_DISPLAY_AER_BRIEF)) { /* * If there was a bus monitor reset event, we force the arbiter diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index f32bd16227..915b2af160 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -145,6 +145,13 @@ config DESIGNWARE_APB_TIMER Enables support for the Designware APB Timer driver. This timer is present on Altera SoCFPGA SoCs. +config FTTMR010_TIMER + bool "Faraday Technology timer support" + depends on TIMER + help + Select this to enable support for the timer found on + devices using Faraday Technology's IP. + config GXP_TIMER bool "HPE GXP Timer" depends on TIMER diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index 3c92113fc6..cdc20f5e94 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_$(SPL_)ATMEL_PIT_TIMER) += atmel_pit_timer.o obj-$(CONFIG_$(SPL_)ATMEL_TCB_TIMER) += atmel_tcb_timer.o obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence-ttc.o obj-$(CONFIG_DESIGNWARE_APB_TIMER) += dw-apb-timer.o +obj-$(CONFIG_FTTMR010_TIMER) += fttmr010_timer.o obj-$(CONFIG_GXP_TIMER) += gxp-timer.o obj-$(CONFIG_MPC83XX_TIMER) += mpc83xx_timer.o obj-$(CONFIG_NOMADIK_MTU_TIMER) += nomadik-mtu-timer.o diff --git a/drivers/timer/fttmr010_timer.c b/drivers/timer/fttmr010_timer.c new file mode 100644 index 0000000000..b6289e6461 --- /dev/null +++ b/drivers/timer/fttmr010_timer.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2009 Faraday Technology + * Po-Yu Chuang <ratbert@faraday-tech.com> + * + * 23/08/2022 Port to DM + */ +#include <common.h> +#include <dm.h> +#include <log.h> +#include <timer.h> +#include <asm/io.h> +#include <dm/ofnode.h> +#include <faraday/fttmr010.h> +#include <asm/global_data.h> + +#define TIMER_LOAD_VAL 0xffffffff + +struct fttmr010_timer_priv { + struct fttmr010 __iomem *regs; +}; + +static u64 fttmr010_timer_get_count(struct udevice *dev) +{ + struct fttmr010_timer_priv *priv = dev_get_priv(dev); + struct fttmr010 *tmr = priv->regs; + u32 now = TIMER_LOAD_VAL - readl(&tmr->timer3_counter); + + /* increment tbu if tbl has rolled over */ + if (now < gd->arch.tbl) + gd->arch.tbu++; + gd->arch.tbl = now; + + return ((u64)gd->arch.tbu << 32) | gd->arch.tbl; +} + +static int fttmr010_timer_probe(struct udevice *dev) +{ + struct fttmr010_timer_priv *priv = dev_get_priv(dev); + struct fttmr010 *tmr; + unsigned int cr; + + priv->regs = dev_read_addr_ptr(dev); + if (!priv->regs) + return -EINVAL; + tmr = priv->regs; + + debug("Faraday FTTMR010 timer revision 0x%08X\n", readl(&tmr->revision)); + + /* disable timers */ + writel(0, &tmr->cr); + + /* setup timer */ + writel(TIMER_LOAD_VAL, &tmr->timer3_load); + writel(TIMER_LOAD_VAL, &tmr->timer3_counter); + writel(0, &tmr->timer3_match1); + writel(0, &tmr->timer3_match2); + + /* we don't want timer to issue interrupts */ + writel(FTTMR010_TM3_MATCH1 | + FTTMR010_TM3_MATCH2 | + FTTMR010_TM3_OVERFLOW, + &tmr->interrupt_mask); + + cr = readl(&tmr->cr); + cr |= FTTMR010_TM3_CLOCK; /* use external clock */ + cr |= FTTMR010_TM3_ENABLE; + writel(cr, &tmr->cr); + + gd->arch.tbl = 0; + gd->arch.tbu = 0; + + return 0; +} + +static const struct timer_ops fttmr010_timer_ops = { + .get_count = fttmr010_timer_get_count, +}; + +static const struct udevice_id fttmr010_timer_ids[] = { + { .compatible = "faraday,fttmr010-timer" }, + {} +}; + +U_BOOT_DRIVER(fttmr010_timer) = { + .name = "fttmr010_timer", + .id = UCLASS_TIMER, + .of_match = fttmr010_timer_ids, + .priv_auto = sizeof(struct fttmr010_timer_priv), + .probe = fttmr010_timer_probe, + .ops = &fttmr010_timer_ops, +}; diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c index 192c7b71a5..f86a0b8692 100644 --- a/drivers/timer/tsc_timer.c +++ b/drivers/timer/tsc_timer.c @@ -404,6 +404,15 @@ static void tsc_timer_ensure_setup(bool early) if (!gd->arch.clock_rate) { unsigned long fast_calibrate; + /** + * There is no obvious way to obtain this information from EFI + * boot services. This value was measured on a Framework Laptop + * which has a 12th Gen Intel Core + */ + if (IS_ENABLED(CONFIG_EFI_APP)) { + fast_calibrate = 2750; + goto done; + } fast_calibrate = native_calibrate_tsc(); if (fast_calibrate) goto done; diff --git a/drivers/tpm/tpm2_tis_sandbox.c b/drivers/tpm/tpm2_tis_sandbox.c index dd94bdc31f..e4004cfcca 100644 --- a/drivers/tpm/tpm2_tis_sandbox.c +++ b/drivers/tpm/tpm2_tis_sandbox.c @@ -810,7 +810,7 @@ static int sandbox_tpm2_open(struct udevice *dev) struct sandbox_tpm2 *tpm = dev_get_priv(dev); if (tpm->init_done) - return -EIO; + return -EBUSY; tpm->init_done = true; diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index f010291d02..c0c8c16fd9 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -40,7 +40,7 @@ config SPL_USB_DWC3_GENERIC config USB_DWC3_MESON_G12A bool "Amlogic Meson G12A USB wrapper" depends on DM_USB && USB_DWC3 && ARCH_MESON - imply PHY + select PHY help Select this for Amlogic Meson G12A Platforms. This wrapper supports Host and Peripheral operation modes. @@ -48,14 +48,17 @@ config USB_DWC3_MESON_G12A config USB_DWC3_MESON_GXL bool "Amlogic Meson GXL USB wrapper" depends on DM_USB && USB_DWC3 && ARCH_MESON - imply PHY + select PHY help Select this for Amlogic Meson GXL and GXM Platforms. This wrapper supports Host and Peripheral operation modes. config USB_DWC3_UNIPHIER bool "DesignWare USB3 Host Support on UniPhier Platforms" - depends on ARCH_UNIPHIER && USB_XHCI_DWC3 + depends on ARCH_UNIPHIER && USB_DWC3 + select USB_DWC3_GENERIC + select PHY + select PHY_UNIPHIER_USB3 help Support of USB2/3 functionality in Socionext UniPhier platforms. Say 'Y' here if you have one such device. diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index ed1b9b630e..66da5a8d6f 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -28,11 +28,7 @@ #include <usb/xhci.h> #include <asm/gpio.h> -struct dwc3_glue_data { - struct clk_bulk clks; - struct reset_ctl_bulk resets; - fdt_addr_t regs; -}; +#include "dwc3-generic.h" struct dwc3_generic_plat { fdt_addr_t base; @@ -68,10 +64,27 @@ static int dwc3_generic_probe(struct udevice *dev, #if CONFIG_IS_ENABLED(OF_CONTROL) dwc3_of_parse(dwc3); + /* + * There are currently four disparate placement possibilities of DWC3 + * reference clock phandle in SoC DTs: + * - in top level glue node, with generic subnode without clock (ZynqMP) + * - in top level generic node, with no subnode (i.MX8MQ) + * - in generic subnode, with other clock in top level node (i.MX8MP) + * - in both top level node and generic subnode (Rockchip) + * Cover all the possibilities here by looking into both nodes, start + * with the top level node as that seems to be used in majority of DTs + * to reference the clock. + */ node = dev_ofnode(dev->parent); index = ofnode_stringlist_search(node, "clock-names", "ref"); if (index < 0) index = ofnode_stringlist_search(node, "clock-names", "ref_clk"); + if (index < 0) { + node = dev_ofnode(dev); + index = ofnode_stringlist_search(node, "clock-names", "ref"); + if (index < 0) + index = ofnode_stringlist_search(node, "clock-names", "ref_clk"); + } if (index >= 0) dwc3->ref_clk = &glue->clks.clks[index]; #endif @@ -258,11 +271,6 @@ U_BOOT_DRIVER(dwc3_generic_host) = { }; #endif -struct dwc3_glue_ops { - void (*glue_configure)(struct udevice *dev, int index, - enum usb_dr_mode mode); -}; - void dwc3_imx8mp_glue_configure(struct udevice *dev, int index, enum usb_dr_mode mode) { @@ -398,54 +406,74 @@ struct dwc3_glue_ops ti_ops = { .glue_configure = dwc3_ti_glue_configure, }; -static int dwc3_glue_bind(struct udevice *parent) +static int dwc3_glue_bind_common(struct udevice *parent, ofnode node) { - ofnode node; - int ret; + const char *name = ofnode_get_name(node); + const char *driver = NULL; enum usb_dr_mode dr_mode; + struct udevice *dev; + int ret; - dr_mode = usb_get_dr_mode(dev_ofnode(parent)); - - ofnode_for_each_subnode(node, dev_ofnode(parent)) { - const char *name = ofnode_get_name(node); - struct udevice *dev; - const char *driver = NULL; - - debug("%s: subnode name: %s\n", __func__, name); + debug("%s: subnode name: %s\n", __func__, name); - /* if the parent node doesn't have a mode check the leaf */ - if (!dr_mode) - dr_mode = usb_get_dr_mode(node); + /* if the parent node doesn't have a mode check the leaf */ + dr_mode = usb_get_dr_mode(dev_ofnode(parent)); + if (!dr_mode) + dr_mode = usb_get_dr_mode(node); - switch (dr_mode) { - case USB_DR_MODE_PERIPHERAL: - case USB_DR_MODE_OTG: + switch (dr_mode) { + case USB_DR_MODE_PERIPHERAL: + case USB_DR_MODE_OTG: #if CONFIG_IS_ENABLED(DM_USB_GADGET) - debug("%s: dr_mode: OTG or Peripheral\n", __func__); - driver = "dwc3-generic-peripheral"; + debug("%s: dr_mode: OTG or Peripheral\n", __func__); + driver = "dwc3-generic-peripheral"; #endif - break; + break; #if defined(CONFIG_SPL_USB_HOST) || !defined(CONFIG_SPL_BUILD) - case USB_DR_MODE_HOST: - debug("%s: dr_mode: HOST\n", __func__); - driver = "dwc3-generic-host"; - break; + case USB_DR_MODE_HOST: + debug("%s: dr_mode: HOST\n", __func__); + driver = "dwc3-generic-host"; + break; #endif - default: - debug("%s: unsupported dr_mode\n", __func__); - return -ENODEV; - }; + default: + debug("%s: unsupported dr_mode\n", __func__); + return -ENODEV; + }; - if (!driver) - continue; + if (!driver) + return -ENXIO; + + ret = device_bind_driver_to_node(parent, driver, name, + node, &dev); + if (ret) { + debug("%s: not able to bind usb device mode\n", + __func__); + return ret; + } + + return 0; +} - ret = device_bind_driver_to_node(parent, driver, name, - node, &dev); - if (ret) { - debug("%s: not able to bind usb device mode\n", - __func__); +int dwc3_glue_bind(struct udevice *parent) +{ + struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(parent); + ofnode node; + int ret; + + if (ops && ops->glue_get_ctrl_dev) { + ret = ops->glue_get_ctrl_dev(parent, &node); + if (ret) + return ret; + + return dwc3_glue_bind_common(parent, node); + } + + ofnode_for_each_subnode(node, dev_ofnode(parent)) { + ret = dwc3_glue_bind_common(parent, node); + if (ret == -ENXIO) + continue; + if (ret) return ret; - } } return 0; @@ -493,7 +521,7 @@ static int dwc3_glue_clk_init(struct udevice *dev, return 0; } -static int dwc3_glue_probe(struct udevice *dev) +int dwc3_glue_probe(struct udevice *dev) { struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(dev); struct dwc3_glue_data *glue = dev_get_plat(dev); @@ -514,7 +542,7 @@ static int dwc3_glue_probe(struct udevice *dev) phy.dev = NULL; } - glue->regs = dev_read_addr(dev); + glue->regs = dev_read_addr_size_index(dev, 0, &glue->size); ret = dwc3_glue_clk_init(dev, glue); if (ret) @@ -534,6 +562,12 @@ static int dwc3_glue_probe(struct udevice *dev) if (ret) return ret; + if (glue->clks.count == 0) { + ret = dwc3_glue_clk_init(child, glue); + if (ret) + return ret; + } + if (glue->resets.count == 0) { ret = dwc3_glue_reset_init(child, glue); if (ret) @@ -553,7 +587,7 @@ static int dwc3_glue_probe(struct udevice *dev) return 0; } -static int dwc3_glue_remove(struct udevice *dev) +int dwc3_glue_remove(struct udevice *dev) { struct dwc3_glue_data *glue = dev_get_plat(dev); diff --git a/drivers/usb/dwc3/dwc3-generic.h b/drivers/usb/dwc3/dwc3-generic.h new file mode 100644 index 0000000000..40902c8923 --- /dev/null +++ b/drivers/usb/dwc3/dwc3-generic.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * dwc3-generic.h - Generic DWC3 Glue layer header + * + * Copyright (C) 2016 - 2018 Xilinx, Inc. + * Copyright (C) 2023 Socionext Inc. + */ + +#ifndef __DRIVERS_USB_DWC3_GENERIC_H +#define __DRIVERS_USB_DWC3_GENERIC_H + +#include <clk.h> +#include <reset.h> +#include <dwc3-uboot.h> + +struct dwc3_glue_data { + struct clk_bulk clks; + struct reset_ctl_bulk resets; + fdt_addr_t regs; + fdt_size_t size; +}; + +struct dwc3_glue_ops { + int (*glue_get_ctrl_dev)(struct udevice *parent, ofnode *node); + void (*glue_configure)(struct udevice *dev, int index, + enum usb_dr_mode mode); +}; + +int dwc3_glue_bind(struct udevice *parent); +int dwc3_glue_probe(struct udevice *dev); +int dwc3_glue_remove(struct udevice *dev); + +#endif diff --git a/drivers/usb/dwc3/dwc3-uniphier.c b/drivers/usb/dwc3/dwc3-uniphier.c index 54b52dcd66..ab85428a70 100644 --- a/drivers/usb/dwc3/dwc3-uniphier.c +++ b/drivers/usb/dwc3/dwc3-uniphier.c @@ -4,14 +4,17 @@ * * Copyright (C) 2016-2017 Socionext Inc. * Author: Masahiro Yamada <yamada.masahiro@socionext.com> + * Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> */ #include <dm.h> -#include <dm/device_compat.h> +#include <dm/lists.h> #include <linux/bitops.h> -#include <linux/errno.h> -#include <linux/io.h> -#include <linux/sizes.h> +#include <linux/usb/gadget.h> + +#include "core.h" +#include "gadget.h" +#include "dwc3-generic.h" #define UNIPHIER_PRO4_DWC3_RESET 0x40 #define UNIPHIER_PRO4_DWC3_RESET_XIOMMU BIT(5) @@ -27,8 +30,11 @@ #define UNIPHIER_PXS2_DWC3_RESET 0x00 #define UNIPHIER_PXS2_DWC3_RESET_XLINK BIT(15) -static int uniphier_pro4_dwc3_init(void __iomem *regs) +static void uniphier_pro4_dwc3_init(struct udevice *dev, int index, + enum usb_dr_mode mode) { + struct dwc3_glue_data *glue = dev_get_plat(dev); + void *regs = map_physmem(glue->regs, glue->size, MAP_NOCACHE); u32 tmp; tmp = readl(regs + UNIPHIER_PRO4_DWC3_RESET); @@ -36,11 +42,14 @@ static int uniphier_pro4_dwc3_init(void __iomem *regs) tmp |= UNIPHIER_PRO4_DWC3_RESET_XIOMMU | UNIPHIER_PRO4_DWC3_RESET_XLINK; writel(tmp, regs + UNIPHIER_PRO4_DWC3_RESET); - return 0; + unmap_physmem(regs, MAP_NOCACHE); } -static int uniphier_pro5_dwc3_init(void __iomem *regs) +static void uniphier_pro5_dwc3_init(struct udevice *dev, int index, + enum usb_dr_mode mode) { + struct dwc3_glue_data *glue = dev_get_plat(dev); + void *regs = map_physmem(glue->regs, glue->size, MAP_NOCACHE); u32 tmp; tmp = readl(regs + UNIPHIER_PRO5_DWC3_RESET); @@ -49,72 +58,97 @@ static int uniphier_pro5_dwc3_init(void __iomem *regs) tmp |= UNIPHIER_PRO5_DWC3_RESET_XLINK | UNIPHIER_PRO5_DWC3_RESET_XIOMMU; writel(tmp, regs + UNIPHIER_PRO5_DWC3_RESET); - return 0; + unmap_physmem(regs, MAP_NOCACHE); } -static int uniphier_pxs2_dwc3_init(void __iomem *regs) +static void uniphier_pxs2_dwc3_init(struct udevice *dev, int index, + enum usb_dr_mode mode) { + struct dwc3_glue_data *glue = dev_get_plat(dev); + void *regs = map_physmem(glue->regs, glue->size, MAP_NOCACHE); u32 tmp; tmp = readl(regs + UNIPHIER_PXS2_DWC3_RESET); tmp |= UNIPHIER_PXS2_DWC3_RESET_XLINK; writel(tmp, regs + UNIPHIER_PXS2_DWC3_RESET); - return 0; + unmap_physmem(regs, MAP_NOCACHE); } -static int uniphier_dwc3_probe(struct udevice *dev) +static int dwc3_uniphier_glue_get_ctrl_dev(struct udevice *dev, ofnode *node) { - fdt_addr_t base; - void __iomem *regs; - int (*init)(void __iomem *regs); - int ret; + struct udevice *child; + const char *name; + ofnode subnode; + + /* + * "controller reset" belongs to glue logic, and it should be + * accessible in .glue_configure() before access to the controller + * begins. + */ + ofnode_for_each_subnode(subnode, dev_ofnode(dev)) { + name = ofnode_get_name(subnode); + if (!strncmp(name, "reset", 5)) + device_bind_driver_to_node(dev, "uniphier-reset", + name, subnode, &child); + } + + /* Get controller node that is placed separately from the glue node */ + *node = ofnode_by_compatible(dev_ofnode(dev->parent), + "socionext,uniphier-dwc3"); - base = dev_read_addr(dev); - if (base == FDT_ADDR_T_NONE) - return -EINVAL; - - regs = ioremap(base, SZ_32K); - if (!regs) - return -ENOMEM; + return 0; +} - init = (typeof(init))dev_get_driver_data(dev); - ret = init(regs); - if (ret) - dev_err(dev, "failed to init glue layer\n"); +static const struct dwc3_glue_ops uniphier_pro4_dwc3_ops = { + .glue_get_ctrl_dev = dwc3_uniphier_glue_get_ctrl_dev, + .glue_configure = uniphier_pro4_dwc3_init, +}; - iounmap(regs); +static const struct dwc3_glue_ops uniphier_pro5_dwc3_ops = { + .glue_get_ctrl_dev = dwc3_uniphier_glue_get_ctrl_dev, + .glue_configure = uniphier_pro5_dwc3_init, +}; - return ret; -} +static const struct dwc3_glue_ops uniphier_pxs2_dwc3_ops = { + .glue_get_ctrl_dev = dwc3_uniphier_glue_get_ctrl_dev, + .glue_configure = uniphier_pxs2_dwc3_init, +}; static const struct udevice_id uniphier_dwc3_match[] = { { - .compatible = "socionext,uniphier-pro4-dwc3", - .data = (ulong)uniphier_pro4_dwc3_init, + .compatible = "socionext,uniphier-pro4-dwc3-glue", + .data = (ulong)&uniphier_pro4_dwc3_ops, + }, + { + .compatible = "socionext,uniphier-pro5-dwc3-glue", + .data = (ulong)&uniphier_pro5_dwc3_ops, }, { - .compatible = "socionext,uniphier-pro5-dwc3", - .data = (ulong)uniphier_pro5_dwc3_init, + .compatible = "socionext,uniphier-pxs2-dwc3-glue", + .data = (ulong)&uniphier_pxs2_dwc3_ops, }, { - .compatible = "socionext,uniphier-pxs2-dwc3", - .data = (ulong)uniphier_pxs2_dwc3_init, + .compatible = "socionext,uniphier-ld20-dwc3-glue", + .data = (ulong)&uniphier_pxs2_dwc3_ops, }, { - .compatible = "socionext,uniphier-ld20-dwc3", - .data = (ulong)uniphier_pxs2_dwc3_init, + .compatible = "socionext,uniphier-pxs3-dwc3-glue", + .data = (ulong)&uniphier_pxs2_dwc3_ops, }, { - .compatible = "socionext,uniphier-pxs3-dwc3", - .data = (ulong)uniphier_pxs2_dwc3_init, + .compatible = "socionext,uniphier-nx1-dwc3-glue", + .data = (ulong)&uniphier_pxs2_dwc3_ops, }, { /* sentinel */ } }; -U_BOOT_DRIVER(usb_xhci) = { +U_BOOT_DRIVER(dwc3_uniphier_wrapper) = { .name = "uniphier-dwc3", .id = UCLASS_SIMPLE_BUS, .of_match = uniphier_dwc3_match, - .probe = uniphier_dwc3_probe, + .bind = dwc3_glue_bind, + .probe = dwc3_glue_probe, + .remove = dwc3_glue_remove, + .plat_auto = sizeof(struct dwc3_glue_data), }; diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index 3838a990ec..63dfb793c6 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -14,8 +14,9 @@ #include <power/regulator.h> #include <usb.h> #include <usb/xhci.h> -#include <linux/errno.h> +#include <linux/bitfield.h> #include <linux/compat.h> +#include <linux/errno.h> #include <linux/iopoll.h> /* IPPC (IP Port Control) registers */ @@ -50,6 +51,25 @@ #define IPPC_U3_CTRL(p) (IPPC_U3_CTRL_0P + ((p) * 0x08)) #define IPPC_U2_CTRL(p) (IPPC_U2_CTRL_0P + ((p) * 0x08)) +/* xHCI CSR */ +#define LS_EOF_CFG 0x930 +#define LSEOF_OFFSET 0x89 + +#define FS_EOF_CFG 0x934 +#define FSEOF_OFFSET 0x2e + +#define SS_GEN1_EOF_CFG 0x93c +#define SSG1EOF_OFFSET 0x78 + +#define HFCNTR_CFG 0x944 +#define ITP_DELTA_CLK_MASK GENMASK(5, 1) +#define FRMCNT_LEV1_RANG_MASK GENMASK(19, 8) + +#define SS_GEN2_EOF_CFG 0x990 +#define SSG2EOF_OFFSET 0x3c + +#define XSEOF_OFFSET_MASK GENMASK(11, 0) + struct mtk_xhci { struct xhci_ctrl ctrl; /* Needs to come first in this struct! */ struct xhci_hccr *hcd; @@ -65,6 +85,30 @@ struct mtk_xhci { u32 u2p_dis_msk; }; +/* + * workaround for mt8195: + * MT8195 has 4 controllers, the controller1~3's default SOF/ITP interval + * is calculated from the frame counter clock 24M, but in fact, the clock + * is 48M. + */ +static void xhci_mtk_set_frame_interval(struct mtk_xhci *mtk) +{ + void __iomem *mac = (void __iomem *)mtk->hcd; + + if (!ofnode_device_is_compatible(dev_ofnode(mtk->dev), "mediatek,mt8195-xhci")) + return; + + clrsetbits_le32(mac + HFCNTR_CFG, + ITP_DELTA_CLK_MASK | FRMCNT_LEV1_RANG_MASK, + FIELD_PREP(ITP_DELTA_CLK_MASK, 0xa) | + FIELD_PREP(FRMCNT_LEV1_RANG_MASK, 0x12b)); + + clrsetbits_le32(mac + LS_EOF_CFG, XSEOF_OFFSET_MASK, LSEOF_OFFSET); + clrsetbits_le32(mac + FS_EOF_CFG, XSEOF_OFFSET_MASK, FSEOF_OFFSET); + clrsetbits_le32(mac + SS_GEN1_EOF_CFG, XSEOF_OFFSET_MASK, SSG1EOF_OFFSET); + clrsetbits_le32(mac + SS_GEN2_EOF_CFG, XSEOF_OFFSET_MASK, SSG2EOF_OFFSET); +} + static int xhci_mtk_host_enable(struct mtk_xhci *mtk) { int u3_ports_disabed = 0; @@ -278,6 +322,8 @@ static int xhci_mtk_probe(struct udevice *dev) if (ret) goto ssusb_init_err; + xhci_mtk_set_frame_interval(mtk); + mtk->ctrl.quirks = XHCI_MTK_HOST; hcor = (struct xhci_hcor *)((uintptr_t)mtk->hcd + HC_LENGTH(xhci_readl(&mtk->hcd->cr_capbase))); @@ -308,6 +354,7 @@ static int xhci_mtk_remove(struct udevice *dev) static const struct udevice_id xhci_mtk_ids[] = { { .compatible = "mediatek,mtk-xhci" }, + { .compatible = "mediatek,mt8195-xhci" }, { } }; diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 2a76d19cc8..60f4a4bf9c 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -16,6 +16,35 @@ config VIDEO if VIDEO +config VIDEO_FONT_4X6 + bool "4 x 6 font size" + help + Font for video console driver, 4 x 6 pixels. + Provides character bitmap data in header file. + When selecting multiple fonts, you may want to enable CMD_SELECT_FONT too. + +config VIDEO_FONT_8X16 + bool "8 x 16 font size" + default y + help + Font for video console driver, 8 x 16 pixels + Provides character bitmap data in header file. + When selecting multiple fonts, you may want to enable CMD_SELECT_FONT too. + +config VIDEO_FONT_SUN12X22 + bool "12 x 22 font size" + help + Font for video console driver, 12 x 22 pixels + Provides character bitmap data in header file. + When selecting multiple fonts, you may want to enable CMD_SELECT_FONT too. + +config VIDEO_FONT_16X32 + bool "16 x 32 font size" + help + Font for video console driver, 16 x 32 pixels + Provides character bitmap data in header file. + When selecting multiple fonts, you may want to enable CMD_SELECT_FONT too. + config VIDEO_LOGO bool "Show the U-Boot logo on the display" default y if !SPLASH_SCREEN @@ -150,6 +179,7 @@ config CONSOLE_ROTATION config CONSOLE_TRUETYPE bool "Support a console that uses TrueType fonts" + select CMD_SELECT_FONT help TrueTrype fonts can provide outline-drawing capability rather than needing to provide a bitmap for each font and size that is needed. diff --git a/drivers/video/Makefile b/drivers/video/Makefile index cdb7d9a54d..cb3f373645 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -9,6 +9,12 @@ obj-$(CONFIG_BACKLIGHT_GPIO) += backlight_gpio.o obj-$(CONFIG_BACKLIGHT_PWM) += pwm_backlight.o obj-$(CONFIG_CONSOLE_NORMAL) += console_normal.o obj-$(CONFIG_CONSOLE_ROTATION) += console_rotate.o +ifdef CONFIG_CONSOLE_NORMAL +obj-y += console_core.o +else ifdef CONFIG_CONSOLE_ROTATION +obj-y += console_core.o +endif +obj-$(CONFIG_CONSOLE_ROTATION) += console_core.o obj-$(CONFIG_CONSOLE_TRUETYPE) += console_truetype.o fonts/ obj-$(CONFIG_DISPLAY) += display-uclass.o obj-$(CONFIG_VIDEO_MIPI_DSI) += dsi-host-uclass.o diff --git a/drivers/video/console_core.c b/drivers/video/console_core.c new file mode 100644 index 0000000000..d4f79c656a --- /dev/null +++ b/drivers/video/console_core.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2015 Google, Inc + * (C) Copyright 2015 + * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com + * (C) Copyright 2023 Dzmitry Sankouski <dsankouski@gmail.com> + */ + +#include <video.h> +#include <video_console.h> +#include <dm.h> +#include <video_font.h> +#include "vidconsole_internal.h" + +/** + * console_set_font() - prepare vidconsole for chosen font. + * + * @dev vidconsole device + * @fontdata pointer to font data struct + */ +static int console_set_font(struct udevice *dev, struct video_fontdata *fontdata) +{ + struct console_simple_priv *priv = dev_get_priv(dev); + struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); + struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); + + debug("console_simple: setting %s font\n", fontdata->name); + debug("width: %d\n", fontdata->width); + debug("byte width: %d\n", fontdata->byte_width); + debug("height: %d\n", fontdata->height); + + priv->fontdata = fontdata; + vc_priv->x_charsize = fontdata->width; + vc_priv->y_charsize = fontdata->height; + if (vid_priv->rot % 2) { + vc_priv->cols = vid_priv->ysize / fontdata->width; + vc_priv->rows = vid_priv->xsize / fontdata->height; + vc_priv->xsize_frac = VID_TO_POS(vid_priv->ysize); + } else { + vc_priv->cols = vid_priv->xsize / fontdata->width; + vc_priv->rows = vid_priv->ysize / fontdata->height; + } + + return 0; +} + +int check_bpix_support(int bpix) +{ + if (bpix == VIDEO_BPP8 && IS_ENABLED(CONFIG_VIDEO_BPP8)) + return 0; + else if (bpix == VIDEO_BPP16 && IS_ENABLED(CONFIG_VIDEO_BPP16)) + return 0; + else if (bpix == VIDEO_BPP32 && IS_ENABLED(CONFIG_VIDEO_BPP32)) + return 0; + else + return -ENOSYS; +} + +inline void fill_pixel_and_goto_next(void **dstp, u32 value, int pbytes, int step) +{ + u8 *dst_byte = *dstp; + + if (pbytes == 4) { + u32 *dst = *dstp; + *dst = value; + } + if (pbytes == 2) { + u16 *dst = *dstp; + *dst = value; + } + if (pbytes == 1) { + u8 *dst = *dstp; + *dst = value; + } + *dstp = dst_byte + step; +} + +int fill_char_vertically(uchar *pfont, void **line, struct video_priv *vid_priv, + struct video_fontdata *fontdata, bool direction) +{ + int step, line_step, pbytes, bitcount, width_remainder, ret; + void *dst; + + ret = check_bpix_support(vid_priv->bpix); + if (ret) + return ret; + + pbytes = VNBYTES(vid_priv->bpix); + if (direction) { + step = -pbytes; + line_step = -vid_priv->line_length; + } else { + step = pbytes; + line_step = vid_priv->line_length; + } + + width_remainder = fontdata->width % 8; + for (int row = 0; row < fontdata->height; row++) { + uchar bits; + + bitcount = 8; + dst = *line; + for (int col = 0; col < fontdata->byte_width; col++) { + if (width_remainder) { + bool is_last_col = (fontdata->byte_width - col == 1); + + if (is_last_col) + bitcount = width_remainder; + } + bits = pfont[col]; + + for (int bit = 0; bit < bitcount; bit++) { + u32 value = (bits & 0x80) ? + vid_priv->colour_fg : + vid_priv->colour_bg; + + fill_pixel_and_goto_next(&dst, + value, + pbytes, + step + ); + bits <<= 1; + } + } + *line += line_step; + pfont += fontdata->byte_width; + } + return ret; +} + +int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_priv, + struct video_fontdata *fontdata, bool direction) +{ + int step, line_step, pbytes, bitcount = 8, width_remainder, ret; + void *dst; + u8 mask; + + ret = check_bpix_support(vid_priv->bpix); + if (ret) + return ret; + + pbytes = VNBYTES(vid_priv->bpix); + if (direction) { + step = -pbytes; + line_step = vid_priv->line_length; + } else { + step = pbytes; + line_step = -vid_priv->line_length; + } + + width_remainder = fontdata->width % 8; + for (int col = 0; col < fontdata->byte_width; col++) { + mask = 0x80; + if (width_remainder) { + bool is_last_col = (fontdata->byte_width - col == 1); + + if (is_last_col) + bitcount = width_remainder; + } + for (int bit = 0; bit < bitcount; bit++) { + dst = *line; + for (int row = 0; row < fontdata->height; row++) { + u32 value = (pfont[row * fontdata->byte_width + col] + & mask) ? vid_priv->colour_fg : vid_priv->colour_bg; + + fill_pixel_and_goto_next(&dst, + value, + pbytes, + step + ); + } + *line += line_step; + mask >>= 1; + } + } + return ret; +} + +int console_probe(struct udevice *dev) +{ + return console_set_font(dev, fonts); +} + +const char *console_simple_get_font_size(struct udevice *dev, uint *sizep) +{ + struct console_simple_priv *priv = dev_get_priv(dev); + + *sizep = priv->fontdata->width; + + return priv->fontdata->name; +} + +int console_simple_get_font(struct udevice *dev, int seq, struct vidfont_info *info) +{ + info->name = fonts[seq].name; + + return 0; +} + +int console_simple_select_font(struct udevice *dev, const char *name, uint size) +{ + struct video_fontdata *font; + + for (font = fonts; font->name; font++) { + if (!strcmp(name, font->name)) { + console_set_font(dev, font); + return 0; + } + }; + printf("no such font: %s, make sure it's name has <width>x<height> format\n", name); + return -ENOENT; +} diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c index 04f022491e..413c7abee9 100644 --- a/drivers/video/console_normal.c +++ b/drivers/video/console_normal.c @@ -1,10 +1,9 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2015 Google, Inc - * (C) Copyright 2001-2015 - * DENX Software Engineering -- wd@denx.de - * Compulab Ltd - http://compulab.co.il/ + * (C) Copyright 2015 * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com + * (C) Copyright 2023 Dzmitry Sankouski <dsankouski@gmail.com> */ #include <common.h> @@ -12,47 +11,30 @@ #include <video.h> #include <video_console.h> #include <video_font.h> /* Get font data, width and height */ +#include "vidconsole_internal.h" -static int console_normal_set_row(struct udevice *dev, uint row, int clr) +static int console_set_row(struct udevice *dev, uint row, int clr) { struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); - void *line, *end; - int pixels = VIDEO_FONT_HEIGHT * vid_priv->xsize; + struct console_simple_priv *priv = dev_get_priv(dev); + struct video_fontdata *fontdata = priv->fontdata; + void *line, *dst, *end; + int pixels = fontdata->height * vid_priv->xsize; int ret; int i; + int pbytes; + + ret = check_bpix_support(vid_priv->bpix); + if (ret) + return ret; + + line = vid_priv->fb + row * fontdata->height * vid_priv->line_length; + dst = line; + pbytes = VNBYTES(vid_priv->bpix); + for (i = 0; i < pixels; i++) + fill_pixel_and_goto_next(&dst, clr, pbytes, pbytes); + end = dst; - line = vid_priv->fb + row * VIDEO_FONT_HEIGHT * vid_priv->line_length; - switch (vid_priv->bpix) { - case VIDEO_BPP8: - if (IS_ENABLED(CONFIG_VIDEO_BPP8)) { - uint8_t *dst = line; - - for (i = 0; i < pixels; i++) - *dst++ = clr; - end = dst; - break; - } - case VIDEO_BPP16: - if (IS_ENABLED(CONFIG_VIDEO_BPP16)) { - uint16_t *dst = line; - - for (i = 0; i < pixels; i++) - *dst++ = clr; - end = dst; - break; - } - case VIDEO_BPP32: - if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { - uint32_t *dst = line; - - for (i = 0; i < pixels; i++) - *dst++ = clr; - end = dst; - break; - } - default: - return -ENOSYS; - } ret = vidconsole_sync_copy(dev, line, end); if (ret) return ret; @@ -60,18 +42,20 @@ static int console_normal_set_row(struct udevice *dev, uint row, int clr) return 0; } -static int console_normal_move_rows(struct udevice *dev, uint rowdst, - uint rowsrc, uint count) +static int console_move_rows(struct udevice *dev, uint rowdst, + uint rowsrc, uint count) { struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); + struct console_simple_priv *priv = dev_get_priv(dev); + struct video_fontdata *fontdata = priv->fontdata; void *dst; void *src; int size; int ret; - dst = vid_priv->fb + rowdst * VIDEO_FONT_HEIGHT * vid_priv->line_length; - src = vid_priv->fb + rowsrc * VIDEO_FONT_HEIGHT * vid_priv->line_length; - size = VIDEO_FONT_HEIGHT * vid_priv->line_length * count; + dst = vid_priv->fb + rowdst * fontdata->height * vid_priv->line_length; + src = vid_priv->fb + rowsrc * fontdata->height * vid_priv->line_length; + size = fontdata->height * vid_priv->line_length * count; ret = vidconsole_memmove(dev, dst, src, size); if (ret) return ret; @@ -79,100 +63,53 @@ static int console_normal_move_rows(struct udevice *dev, uint rowdst, return 0; } -static int console_normal_putc_xy(struct udevice *dev, uint x_frac, uint y, - char ch) +static int console_putc_xy(struct udevice *dev, uint x_frac, uint y, char ch) { struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); struct udevice *vid = dev->parent; struct video_priv *vid_priv = dev_get_uclass_priv(vid); - int i, row; - void *start; - void *line; - int ret; + struct console_simple_priv *priv = dev_get_priv(dev); + struct video_fontdata *fontdata = priv->fontdata; + int pbytes = VNBYTES(vid_priv->bpix); + int x, linenum, ret; + void *start, *line; + uchar *pfont = fontdata->video_fontdata + + (u8)ch * fontdata->char_pixel_bytes; - start = vid_priv->fb + y * vid_priv->line_length + - VID_TO_PIXEL(x_frac) * VNBYTES(vid_priv->bpix); + if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac) + return -EAGAIN; + linenum = y; + x = VID_TO_PIXEL(x_frac); + start = vid_priv->fb + linenum * vid_priv->line_length + x * pbytes; line = start; if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac) return -EAGAIN; - for (row = 0; row < VIDEO_FONT_HEIGHT; row++) { - unsigned int idx = (u8)ch * VIDEO_FONT_HEIGHT + row; - uchar bits = video_fontdata[idx]; - - switch (vid_priv->bpix) { - case VIDEO_BPP8: - if (IS_ENABLED(CONFIG_VIDEO_BPP8)) { - uint8_t *dst = line; - - for (i = 0; i < VIDEO_FONT_WIDTH; i++) { - *dst++ = (bits & 0x80) ? - vid_priv->colour_fg : - vid_priv->colour_bg; - bits <<= 1; - } - break; - } - case VIDEO_BPP16: - if (IS_ENABLED(CONFIG_VIDEO_BPP16)) { - uint16_t *dst = line; - - for (i = 0; i < VIDEO_FONT_WIDTH; i++) { - *dst++ = (bits & 0x80) ? - vid_priv->colour_fg : - vid_priv->colour_bg; - bits <<= 1; - } - break; - } - case VIDEO_BPP32: - if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { - uint32_t *dst = line; - - for (i = 0; i < VIDEO_FONT_WIDTH; i++) { - *dst++ = (bits & 0x80) ? - vid_priv->colour_fg : - vid_priv->colour_bg; - bits <<= 1; - } - break; - } - default: - return -ENOSYS; - } - line += vid_priv->line_length; - } - ret = vidconsole_sync_copy(dev, start, line); + ret = fill_char_vertically(pfont, &line, vid_priv, fontdata, NORMAL_DIRECTION); if (ret) return ret; - return VID_TO_POS(VIDEO_FONT_WIDTH); -} - -static int console_normal_probe(struct udevice *dev) -{ - struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); - struct udevice *vid_dev = dev->parent; - struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); - - vc_priv->x_charsize = VIDEO_FONT_WIDTH; - vc_priv->y_charsize = VIDEO_FONT_HEIGHT; - vc_priv->cols = vid_priv->xsize / VIDEO_FONT_WIDTH; - vc_priv->rows = vid_priv->ysize / VIDEO_FONT_HEIGHT; + ret = vidconsole_sync_copy(dev, start, line); + if (ret) + return ret; - return 0; + return VID_TO_POS(fontdata->width); } -struct vidconsole_ops console_normal_ops = { - .putc_xy = console_normal_putc_xy, - .move_rows = console_normal_move_rows, - .set_row = console_normal_set_row, +struct vidconsole_ops console_ops = { + .putc_xy = console_putc_xy, + .move_rows = console_move_rows, + .set_row = console_set_row, + .get_font_size = console_simple_get_font_size, + .get_font = console_simple_get_font, + .select_font = console_simple_select_font, }; U_BOOT_DRIVER(vidconsole_normal) = { - .name = "vidconsole0", - .id = UCLASS_VIDEO_CONSOLE, - .ops = &console_normal_ops, - .probe = console_normal_probe, + .name = "vidconsole0", + .id = UCLASS_VIDEO_CONSOLE, + .ops = &console_ops, + .probe = console_probe, + .priv_auto = sizeof(struct console_simple_priv), }; diff --git a/drivers/video/console_rotate.c b/drivers/video/console_rotate.c index 36c8d0609d..65358a1c6e 100644 --- a/drivers/video/console_rotate.c +++ b/drivers/video/console_rotate.c @@ -3,6 +3,7 @@ * Copyright (c) 2015 Google, Inc * (C) Copyright 2015 * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com + * (C) Copyright 2023 Dzmitry Sankouski <dsankouski@gmail.com> */ #include <common.h> @@ -10,47 +11,25 @@ #include <video.h> #include <video_console.h> #include <video_font.h> /* Get font data, width and height */ +#include "vidconsole_internal.h" static int console_set_row_1(struct udevice *dev, uint row, int clr) { struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); + struct console_simple_priv *priv = dev_get_priv(dev); + struct video_fontdata *fontdata = priv->fontdata; int pbytes = VNBYTES(vid_priv->bpix); - void *start, *line; + void *start, *dst, *line; int i, j; int ret; start = vid_priv->fb + vid_priv->line_length - - (row + 1) * VIDEO_FONT_HEIGHT * pbytes; + (row + 1) * fontdata->height * pbytes; line = start; for (j = 0; j < vid_priv->ysize; j++) { - switch (vid_priv->bpix) { - case VIDEO_BPP8: - if (IS_ENABLED(CONFIG_VIDEO_BPP8)) { - uint8_t *dst = line; - - for (i = 0; i < VIDEO_FONT_HEIGHT; i++) - *dst++ = clr; - break; - } - case VIDEO_BPP16: - if (IS_ENABLED(CONFIG_VIDEO_BPP16)) { - uint16_t *dst = line; - - for (i = 0; i < VIDEO_FONT_HEIGHT; i++) - *dst++ = clr; - break; - } - case VIDEO_BPP32: - if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { - uint32_t *dst = line; - - for (i = 0; i < VIDEO_FONT_HEIGHT; i++) - *dst++ = clr; - break; - } - default: - return -ENOSYS; - } + dst = line; + for (i = 0; i < fontdata->height; i++) + fill_pixel_and_goto_next(&dst, clr, pbytes, pbytes); line += vid_priv->line_length; } ret = vidconsole_sync_copy(dev, start, line); @@ -61,22 +40,24 @@ static int console_set_row_1(struct udevice *dev, uint row, int clr) } static int console_move_rows_1(struct udevice *dev, uint rowdst, uint rowsrc, - uint count) + uint count) { struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); + struct console_simple_priv *priv = dev_get_priv(dev); + struct video_fontdata *fontdata = priv->fontdata; int pbytes = VNBYTES(vid_priv->bpix); void *dst; void *src; int j, ret; dst = vid_priv->fb + vid_priv->line_length - - (rowdst + count) * VIDEO_FONT_HEIGHT * pbytes; + (rowdst + count) * fontdata->height * pbytes; src = vid_priv->fb + vid_priv->line_length - - (rowsrc + count) * VIDEO_FONT_HEIGHT * pbytes; + (rowsrc + count) * fontdata->height * pbytes; for (j = 0; j < vid_priv->ysize; j++) { ret = vidconsole_memmove(dev, dst, src, - VIDEO_FONT_HEIGHT * pbytes * count); + fontdata->height * pbytes * count); if (ret) return ret; src += vid_priv->line_length; @@ -91,110 +72,51 @@ static int console_putc_xy_1(struct udevice *dev, uint x_frac, uint y, char ch) struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); struct udevice *vid = dev->parent; struct video_priv *vid_priv = dev_get_uclass_priv(vid); - uchar *pfont = video_fontdata + (u8)ch * VIDEO_FONT_HEIGHT; + struct console_simple_priv *priv = dev_get_priv(dev); + struct video_fontdata *fontdata = priv->fontdata; int pbytes = VNBYTES(vid_priv->bpix); - int i, col, x, linenum, ret; - int mask = 0x80; + int x, linenum, ret; void *start, *line; + uchar *pfont = fontdata->video_fontdata + + (u8)ch * fontdata->char_pixel_bytes; + if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac) + return -EAGAIN; linenum = VID_TO_PIXEL(x_frac) + 1; x = y + 1; start = vid_priv->fb + linenum * vid_priv->line_length - x * pbytes; line = start; - if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac) - return -EAGAIN; - for (col = 0; col < VIDEO_FONT_HEIGHT; col++) { - switch (vid_priv->bpix) { - case VIDEO_BPP8: - if (IS_ENABLED(CONFIG_VIDEO_BPP8)) { - uint8_t *dst = line; - - for (i = 0; i < VIDEO_FONT_HEIGHT; i++) { - *dst-- = (pfont[i] & mask) ? - vid_priv->colour_fg : - vid_priv->colour_bg; - } - break; - } - case VIDEO_BPP16: - if (IS_ENABLED(CONFIG_VIDEO_BPP16)) { - uint16_t *dst = line; - - for (i = 0; i < VIDEO_FONT_HEIGHT; i++) { - *dst-- = (pfont[i] & mask) ? - vid_priv->colour_fg : - vid_priv->colour_bg; - } - break; - } - case VIDEO_BPP32: - if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { - uint32_t *dst = line; - - for (i = 0; i < VIDEO_FONT_HEIGHT; i++) { - *dst-- = (pfont[i] & mask) ? - vid_priv->colour_fg : - vid_priv->colour_bg; - } - break; - } - default: - return -ENOSYS; - } - line += vid_priv->line_length; - mask >>= 1; - } + ret = fill_char_horizontally(pfont, &line, vid_priv, fontdata, FLIPPED_DIRECTION); + if (ret) + return ret; + /* We draw backwards from 'start, so account for the first line */ ret = vidconsole_sync_copy(dev, start - vid_priv->line_length, line); if (ret) return ret; - return VID_TO_POS(VIDEO_FONT_WIDTH); + return VID_TO_POS(fontdata->width); } static int console_set_row_2(struct udevice *dev, uint row, int clr) { struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); - void *start, *line, *end; - int pixels = VIDEO_FONT_HEIGHT * vid_priv->xsize; + struct console_simple_priv *priv = dev_get_priv(dev); + struct video_fontdata *fontdata = priv->fontdata; + void *start, *line, *dst, *end; + int pixels = fontdata->height * vid_priv->xsize; int i, ret; + int pbytes = VNBYTES(vid_priv->bpix); start = vid_priv->fb + vid_priv->ysize * vid_priv->line_length - - (row + 1) * VIDEO_FONT_HEIGHT * vid_priv->line_length; + (row + 1) * fontdata->height * vid_priv->line_length; line = start; - switch (vid_priv->bpix) { - case VIDEO_BPP8: - if (IS_ENABLED(CONFIG_VIDEO_BPP8)) { - uint8_t *dst = line; - - for (i = 0; i < pixels; i++) - *dst++ = clr; - end = dst; - break; - } - case VIDEO_BPP16: - if (IS_ENABLED(CONFIG_VIDEO_BPP16)) { - uint16_t *dst = line; - - for (i = 0; i < pixels; i++) - *dst++ = clr; - end = dst; - break; - } - case VIDEO_BPP32: - if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { - uint32_t *dst = line; - - for (i = 0; i < pixels; i++) - *dst++ = clr; - end = dst; - break; - } - default: - return -ENOSYS; - } + dst = line; + for (i = 0; i < pixels; i++) + fill_pixel_and_goto_next(&dst, clr, pbytes, pbytes); + end = dst; ret = vidconsole_sync_copy(dev, start, end); if (ret) return ret; @@ -206,17 +128,19 @@ static int console_move_rows_2(struct udevice *dev, uint rowdst, uint rowsrc, uint count) { struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); + struct console_simple_priv *priv = dev_get_priv(dev); + struct video_fontdata *fontdata = priv->fontdata; void *dst; void *src; void *end; end = vid_priv->fb + vid_priv->ysize * vid_priv->line_length; - dst = end - (rowdst + count) * VIDEO_FONT_HEIGHT * + dst = end - (rowdst + count) * fontdata->height * vid_priv->line_length; - src = end - (rowsrc + count) * VIDEO_FONT_HEIGHT * + src = end - (rowsrc + count) * fontdata->height * vid_priv->line_length; vidconsole_memmove(dev, dst, src, - VIDEO_FONT_HEIGHT * vid_priv->line_length * count); + fontdata->height * vid_priv->line_length * count); return 0; } @@ -226,9 +150,13 @@ static int console_putc_xy_2(struct udevice *dev, uint x_frac, uint y, char ch) struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); struct udevice *vid = dev->parent; struct video_priv *vid_priv = dev_get_uclass_priv(vid); + struct console_simple_priv *priv = dev_get_priv(dev); + struct video_fontdata *fontdata = priv->fontdata; int pbytes = VNBYTES(vid_priv->bpix); - int i, row, x, linenum, ret; + int linenum, x, ret; void *start, *line; + uchar *pfont = fontdata->video_fontdata + + (u8)ch * fontdata->char_pixel_bytes; if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac) return -EAGAIN; @@ -237,98 +165,33 @@ static int console_putc_xy_2(struct udevice *dev, uint x_frac, uint y, char ch) start = vid_priv->fb + linenum * vid_priv->line_length + x * pbytes; line = start; - for (row = 0; row < VIDEO_FONT_HEIGHT; row++) { - unsigned int idx = (u8)ch * VIDEO_FONT_HEIGHT + row; - uchar bits = video_fontdata[idx]; - - switch (vid_priv->bpix) { - case VIDEO_BPP8: - if (IS_ENABLED(CONFIG_VIDEO_BPP8)) { - uint8_t *dst = line; - - for (i = 0; i < VIDEO_FONT_WIDTH; i++) { - *dst-- = (bits & 0x80) ? - vid_priv->colour_fg : - vid_priv->colour_bg; - bits <<= 1; - } - break; - } - case VIDEO_BPP16: - if (IS_ENABLED(CONFIG_VIDEO_BPP16)) { - uint16_t *dst = line; - - for (i = 0; i < VIDEO_FONT_WIDTH; i++) { - *dst-- = (bits & 0x80) ? - vid_priv->colour_fg : - vid_priv->colour_bg; - bits <<= 1; - } - break; - } - case VIDEO_BPP32: - if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { - uint32_t *dst = line; - - for (i = 0; i < VIDEO_FONT_WIDTH; i++) { - *dst-- = (bits & 0x80) ? - vid_priv->colour_fg : - vid_priv->colour_bg; - bits <<= 1; - } - break; - } - default: - return -ENOSYS; - } - line -= vid_priv->line_length; - } + ret = fill_char_vertically(pfont, &line, vid_priv, fontdata, FLIPPED_DIRECTION); + if (ret) + return ret; + /* Add 4 bytes to allow for the first pixel writen */ ret = vidconsole_sync_copy(dev, start + 4, line); if (ret) return ret; - return VID_TO_POS(VIDEO_FONT_WIDTH); + return VID_TO_POS(fontdata->width); } static int console_set_row_3(struct udevice *dev, uint row, int clr) { struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); + struct console_simple_priv *priv = dev_get_priv(dev); + struct video_fontdata *fontdata = priv->fontdata; int pbytes = VNBYTES(vid_priv->bpix); - void *start, *line; + void *start, *dst, *line; int i, j, ret; - start = vid_priv->fb + row * VIDEO_FONT_HEIGHT * pbytes; + start = vid_priv->fb + row * fontdata->height * pbytes; line = start; for (j = 0; j < vid_priv->ysize; j++) { - switch (vid_priv->bpix) { - case VIDEO_BPP8: - if (IS_ENABLED(CONFIG_VIDEO_BPP8)) { - uint8_t *dst = line; - - for (i = 0; i < VIDEO_FONT_HEIGHT; i++) - *dst++ = clr; - break; - } - case VIDEO_BPP16: - if (IS_ENABLED(CONFIG_VIDEO_BPP16)) { - uint16_t *dst = line; - - for (i = 0; i < VIDEO_FONT_HEIGHT; i++) - *dst++ = clr; - break; - } - case VIDEO_BPP32: - if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { - uint32_t *dst = line; - - for (i = 0; i < VIDEO_FONT_HEIGHT; i++) - *dst++ = clr; - break; - } - default: - return -ENOSYS; - } + dst = line; + for (i = 0; i < fontdata->height; i++) + fill_pixel_and_goto_next(&dst, clr, pbytes, pbytes); line += vid_priv->line_length; } ret = vidconsole_sync_copy(dev, start, line); @@ -342,17 +205,19 @@ static int console_move_rows_3(struct udevice *dev, uint rowdst, uint rowsrc, uint count) { struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); + struct console_simple_priv *priv = dev_get_priv(dev); + struct video_fontdata *fontdata = priv->fontdata; int pbytes = VNBYTES(vid_priv->bpix); void *dst; void *src; int j, ret; - dst = vid_priv->fb + rowdst * VIDEO_FONT_HEIGHT * pbytes; - src = vid_priv->fb + rowsrc * VIDEO_FONT_HEIGHT * pbytes; + dst = vid_priv->fb + rowdst * fontdata->height * pbytes; + src = vid_priv->fb + rowsrc * fontdata->height * pbytes; for (j = 0; j < vid_priv->ysize; j++) { ret = vidconsole_memmove(dev, dst, src, - VIDEO_FONT_HEIGHT * pbytes * count); + fontdata->height * pbytes * count); if (ret) return ret; src += vid_priv->line_length; @@ -367,131 +232,79 @@ static int console_putc_xy_3(struct udevice *dev, uint x_frac, uint y, char ch) struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); struct udevice *vid = dev->parent; struct video_priv *vid_priv = dev_get_uclass_priv(vid); - uchar *pfont = video_fontdata + (u8)ch * VIDEO_FONT_HEIGHT; + struct console_simple_priv *priv = dev_get_priv(dev); + struct video_fontdata *fontdata = priv->fontdata; int pbytes = VNBYTES(vid_priv->bpix); - int i, col, x, ret; - int mask = 0x80; + int linenum, x, ret; void *start, *line; + uchar *pfont = fontdata->video_fontdata + + (u8)ch * fontdata->char_pixel_bytes; if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac) return -EAGAIN; - x = vid_priv->ysize - VID_TO_PIXEL(x_frac) - 1; - start = vid_priv->fb + x * vid_priv->line_length + y * pbytes; + x = y; + linenum = vid_priv->ysize - VID_TO_PIXEL(x_frac) - 1; + start = vid_priv->fb + linenum * vid_priv->line_length + y * pbytes; line = start; - for (col = 0; col < VIDEO_FONT_HEIGHT; col++) { - switch (vid_priv->bpix) { - case VIDEO_BPP8: - if (IS_ENABLED(CONFIG_VIDEO_BPP8)) { - uint8_t *dst = line; - - for (i = 0; i < VIDEO_FONT_HEIGHT; i++) { - *dst++ = (pfont[i] & mask) ? - vid_priv->colour_fg : - vid_priv->colour_bg; - } - break; - } - case VIDEO_BPP16: - if (IS_ENABLED(CONFIG_VIDEO_BPP16)) { - uint16_t *dst = line; - - for (i = 0; i < VIDEO_FONT_HEIGHT; i++) { - *dst++ = (pfont[i] & mask) ? - vid_priv->colour_fg : - vid_priv->colour_bg; - } - break; - } - case VIDEO_BPP32: - if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { - uint32_t *dst = line; - - for (i = 0; i < VIDEO_FONT_HEIGHT; i++) { - *dst++ = (pfont[i] & mask) ? - vid_priv->colour_fg : - vid_priv->colour_bg; - } - break; - } - default: - return -ENOSYS; - } - line -= vid_priv->line_length; - mask >>= 1; - } + + ret = fill_char_horizontally(pfont, &line, vid_priv, fontdata, NORMAL_DIRECTION); + if (ret) + return ret; /* Add a line to allow for the first pixels writen */ ret = vidconsole_sync_copy(dev, start + vid_priv->line_length, line); if (ret) return ret; - return VID_TO_POS(VIDEO_FONT_WIDTH); -} - - -static int console_probe_2(struct udevice *dev) -{ - struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); - struct udevice *vid_dev = dev->parent; - struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); - - vc_priv->x_charsize = VIDEO_FONT_WIDTH; - vc_priv->y_charsize = VIDEO_FONT_HEIGHT; - vc_priv->cols = vid_priv->xsize / VIDEO_FONT_WIDTH; - vc_priv->rows = vid_priv->ysize / VIDEO_FONT_HEIGHT; - - return 0; -} - -static int console_probe_1_3(struct udevice *dev) -{ - struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); - struct udevice *vid_dev = dev->parent; - struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); - - vc_priv->x_charsize = VIDEO_FONT_WIDTH; - vc_priv->y_charsize = VIDEO_FONT_HEIGHT; - vc_priv->cols = vid_priv->ysize / VIDEO_FONT_WIDTH; - vc_priv->rows = vid_priv->xsize / VIDEO_FONT_HEIGHT; - vc_priv->xsize_frac = VID_TO_POS(vid_priv->ysize); - - return 0; + return VID_TO_POS(fontdata->width); } struct vidconsole_ops console_ops_1 = { .putc_xy = console_putc_xy_1, .move_rows = console_move_rows_1, .set_row = console_set_row_1, + .get_font_size = console_simple_get_font_size, + .get_font = console_simple_get_font, + .select_font = console_simple_select_font, }; struct vidconsole_ops console_ops_2 = { .putc_xy = console_putc_xy_2, .move_rows = console_move_rows_2, .set_row = console_set_row_2, + .get_font_size = console_simple_get_font_size, + .get_font = console_simple_get_font, + .select_font = console_simple_select_font, }; struct vidconsole_ops console_ops_3 = { .putc_xy = console_putc_xy_3, .move_rows = console_move_rows_3, .set_row = console_set_row_3, + .get_font_size = console_simple_get_font_size, + .get_font = console_simple_get_font, + .select_font = console_simple_select_font, }; U_BOOT_DRIVER(vidconsole_1) = { .name = "vidconsole1", .id = UCLASS_VIDEO_CONSOLE, .ops = &console_ops_1, - .probe = console_probe_1_3, + .probe = console_probe, + .priv_auto = sizeof(struct console_simple_priv), }; U_BOOT_DRIVER(vidconsole_2) = { .name = "vidconsole2", .id = UCLASS_VIDEO_CONSOLE, .ops = &console_ops_2, - .probe = console_probe_2, + .probe = console_probe, + .priv_auto = sizeof(struct console_simple_priv), }; U_BOOT_DRIVER(vidconsole_3) = { .name = "vidconsole3", .id = UCLASS_VIDEO_CONSOLE, .ops = &console_ops_3, - .probe = console_probe_1_3, + .probe = console_probe, + .priv_auto = sizeof(struct console_simple_priv), }; diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index 9cac9a6de4..6b5390136a 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -724,7 +724,7 @@ static int truetype_select_font(struct udevice *dev, const char *name, return 0; } -const char *vidconsole_get_font_size(struct udevice *dev, uint *sizep) +const char *console_truetype_get_font_size(struct udevice *dev, uint *sizep) { struct console_tt_priv *priv = dev_get_priv(dev); struct console_tt_metrics *met = priv->cur_met; @@ -773,6 +773,7 @@ struct vidconsole_ops console_truetype_ops = { .backspace = console_truetype_backspace, .entry_start = console_truetype_entry_start, .get_font = console_truetype_get_font, + .get_font_size = console_truetype_get_font_size, .select_font = truetype_select_font, }; diff --git a/drivers/video/coreboot.c b/drivers/video/coreboot.c index d2d87c75c8..c586475e41 100644 --- a/drivers/video/coreboot.c +++ b/drivers/video/coreboot.c @@ -57,7 +57,7 @@ static int coreboot_video_probe(struct udevice *dev) goto err; } - ret = vesa_setup_video_priv(vesa, uc_priv, plat); + ret = vesa_setup_video_priv(vesa, vesa->phys_base_ptr, uc_priv, plat); if (ret) { ret = log_msg_ret("setup", ret); goto err; diff --git a/drivers/video/efi.c b/drivers/video/efi.c index b11e42c0eb..28ac15ff61 100644 --- a/drivers/video/efi.c +++ b/drivers/video/efi.c @@ -5,6 +5,8 @@ * EFI framebuffer driver based on GOP */ +#define LOG_CATEGORY LOGC_EFI + #include <common.h> #include <dm.h> #include <efi_api.h> @@ -50,7 +52,19 @@ static void efi_find_pixel_bits(u32 mask, u8 *pos, u8 *size) *size = len; } -static int get_mode_info(struct vesa_mode_info *vesa) +/** + * get_mode_info() - Ask EFI for the mode information + * + * Gets info from the graphics-output protocol + * + * @vesa: Place to put the mode information + * @fbp: Returns the address of the frame buffer + * @infop: Returns a pointer to the mode info + * Returns: 0 if OK, -ENOSYS if boot services are not available, -ENOTSUPP if + * the protocol is not supported by EFI + */ +static int get_mode_info(struct vesa_mode_info *vesa, u64 *fbp, + struct efi_gop_mode_info **infop) { efi_guid_t efi_gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; struct efi_boot_services *boot = efi_get_boot(); @@ -63,41 +77,70 @@ static int get_mode_info(struct vesa_mode_info *vesa) ret = boot->locate_protocol(&efi_gop_guid, NULL, (void **)&gop); if (ret) return log_msg_ret("prot", -ENOTSUPP); - mode = gop->mode; + log_debug("maxmode %u, mode %u, info %p, size %lx, fb %lx, fb_size %lx\n", + mode->max_mode, mode->mode, mode->info, mode->info_size, + (ulong)mode->fb_base, (ulong)mode->fb_size); + vesa->phys_base_ptr = mode->fb_base; + *fbp = mode->fb_base; vesa->x_resolution = mode->info->width; vesa->y_resolution = mode->info->height; + *infop = mode->info; return 0; } -static int save_vesa_mode(struct vesa_mode_info *vesa) +/** + * get_mode_from_entry() - Obtain fb info from the EFIET_GOP_MODE payload entry + * + * This gets the mode information provided by the stub to the payload and puts + * it into a vesa structure. It also returns the mode information. + * + * @vesa: Place to put the mode information + * @fbp: Returns the address of the frame buffer + * @infop: Returns a pointer to the mode info + * Returns: 0 if OK, -ve on error + */ +static int get_mode_from_entry(struct vesa_mode_info *vesa, u64 *fbp, + struct efi_gop_mode_info **infop) { - struct efi_entry_gopmode *mode; - const struct efi_framebuffer *fbinfo; + struct efi_gop_mode *mode; int size; int ret; - if (IS_ENABLED(CONFIG_EFI_APP)) { - ret = get_mode_info(vesa); - if (ret) { - printf("EFI graphics output protocol not found\n"); - return -ENXIO; - } - } else { - ret = efi_info_get(EFIET_GOP_MODE, (void **)&mode, &size); - if (ret == -ENOENT) { - printf("EFI graphics output protocol mode not found\n"); - return -ENXIO; - } - vesa->phys_base_ptr = mode->fb_base; - vesa->x_resolution = mode->info->width; - vesa->y_resolution = mode->info->height; + ret = efi_info_get(EFIET_GOP_MODE, (void **)&mode, &size); + if (ret) { + printf("EFI graphics output entry not found\n"); + return ret; } + vesa->phys_base_ptr = mode->fb_base; + *fbp = mode->fb_base; + vesa->x_resolution = mode->info->width; + vesa->y_resolution = mode->info->height; + *infop = mode->info; - if (mode->info->pixel_format < EFI_GOT_BITMASK) { - fbinfo = &efi_framebuffer_format_map[mode->info->pixel_format]; + return 0; +} + +static int save_vesa_mode(struct vesa_mode_info *vesa, u64 *fbp) +{ + const struct efi_framebuffer *fbinfo; + struct efi_gop_mode_info *info; + int ret; + + if (IS_ENABLED(CONFIG_EFI_APP)) + ret = get_mode_info(vesa, fbp, &info); + else + ret = get_mode_from_entry(vesa, fbp, &info); + if (ret) { + printf("EFI graphics output protocol not found (err=%dE)\n", + ret); + return ret; + } + + if (info->pixel_format < EFI_GOT_BITMASK) { + fbinfo = &efi_framebuffer_format_map[info->pixel_format]; vesa->red_mask_size = fbinfo->red.size; vesa->red_mask_pos = fbinfo->red.pos; vesa->green_mask_size = fbinfo->green.size; @@ -108,29 +151,28 @@ static int save_vesa_mode(struct vesa_mode_info *vesa) vesa->reserved_mask_pos = fbinfo->rsvd.pos; vesa->bits_per_pixel = 32; - vesa->bytes_per_scanline = mode->info->pixels_per_scanline * 4; - } else if (mode->info->pixel_format == EFI_GOT_BITMASK) { - efi_find_pixel_bits(mode->info->pixel_bitmask[0], + vesa->bytes_per_scanline = info->pixels_per_scanline * 4; + } else if (info->pixel_format == EFI_GOT_BITMASK) { + efi_find_pixel_bits(info->pixel_bitmask[0], &vesa->red_mask_pos, &vesa->red_mask_size); - efi_find_pixel_bits(mode->info->pixel_bitmask[1], + efi_find_pixel_bits(info->pixel_bitmask[1], &vesa->green_mask_pos, &vesa->green_mask_size); - efi_find_pixel_bits(mode->info->pixel_bitmask[2], + efi_find_pixel_bits(info->pixel_bitmask[2], &vesa->blue_mask_pos, &vesa->blue_mask_size); - efi_find_pixel_bits(mode->info->pixel_bitmask[3], + efi_find_pixel_bits(info->pixel_bitmask[3], &vesa->reserved_mask_pos, &vesa->reserved_mask_size); vesa->bits_per_pixel = vesa->red_mask_size + vesa->green_mask_size + vesa->blue_mask_size + vesa->reserved_mask_size; - vesa->bytes_per_scanline = (mode->info->pixels_per_scanline * + vesa->bytes_per_scanline = (info->pixels_per_scanline * vesa->bits_per_pixel) / 8; } else { - debug("efi set unknown framebuffer format: %d\n", - mode->info->pixel_format); + log_err("Unknown framebuffer format: %d\n", info->pixel_format); return -EINVAL; } @@ -142,19 +184,20 @@ static int efi_video_probe(struct udevice *dev) struct video_uc_plat *plat = dev_get_uclass_plat(dev); struct video_priv *uc_priv = dev_get_uclass_priv(dev); struct vesa_mode_info *vesa = &mode_info.vesa; + u64 fb; int ret; /* Initialize vesa_mode_info structure */ - ret = save_vesa_mode(vesa); + ret = save_vesa_mode(vesa, &fb); if (ret) goto err; - ret = vesa_setup_video_priv(vesa, uc_priv, plat); + ret = vesa_setup_video_priv(vesa, fb, uc_priv, plat); if (ret) goto err; - printf("Video: %dx%dx%d\n", uc_priv->xsize, uc_priv->ysize, - vesa->bits_per_pixel); + printf("Video: %dx%dx%d @ %lx\n", uc_priv->xsize, uc_priv->ysize, + vesa->bits_per_pixel, (ulong)fb); return 0; @@ -163,6 +206,30 @@ err: return ret; } +static int efi_video_bind(struct udevice *dev) +{ + if (IS_ENABLED(CONFIG_VIDEO_COPY)) { + struct video_uc_plat *plat = dev_get_uclass_plat(dev); + struct vesa_mode_info vesa; + int ret; + u64 fb; + + /* + * Initialise vesa_mode_info structure so we can figure out the + * required framebuffer size. If something goes wrong, just do + * without a copy framebuffer + */ + ret = save_vesa_mode(&vesa, &fb); + if (!ret) { + /* this is not reached if the EFI call failed */ + plat->copy_size = vesa.bytes_per_scanline * + vesa.y_resolution; + } + } + + return 0; +} + static const struct udevice_id efi_video_ids[] = { { .compatible = "efi-fb" }, { } @@ -172,5 +239,6 @@ U_BOOT_DRIVER(efi_video) = { .name = "efi_video", .id = UCLASS_VIDEO, .of_match = efi_video_ids, + .bind = efi_video_bind, .probe = efi_video_probe, }; diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 72a13d3052..1225de2333 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -575,6 +575,17 @@ int vidconsole_get_font(struct udevice *dev, int seq, return ops->get_font(dev, seq, info); } +int vidconsole_get_font_size(struct udevice *dev, const char **name, uint *sizep) +{ + struct vidconsole_ops *ops = vidconsole_get_ops(dev); + + if (!ops->get_font_size) + return -ENOSYS; + + *name = ops->get_font_size(dev, sizep); + return 0; +} + int vidconsole_select_font(struct udevice *dev, const char *name, uint size) { struct vidconsole_ops *ops = vidconsole_get_ops(dev); @@ -645,6 +656,18 @@ int vidconsole_memmove(struct udevice *dev, void *dst, const void *src, } #endif +int vidconsole_clear_and_reset(struct udevice *dev) +{ + int ret; + + ret = video_clear(dev_get_parent(dev)); + if (ret) + return ret; + vidconsole_position_cursor(dev, 0, 0); + + return 0; +} + void vidconsole_position_cursor(struct udevice *dev, unsigned col, unsigned row) { struct vidconsole_priv *priv = dev_get_uclass_priv(dev); diff --git a/drivers/video/vidconsole_internal.h b/drivers/video/vidconsole_internal.h new file mode 100644 index 0000000000..c41edd4524 --- /dev/null +++ b/drivers/video/vidconsole_internal.h @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2015 Google, Inc + * (C) Copyright 2015 + * Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com + * (C) Copyright 2023 Dzmitry Sankouski <dsankouski@gmail.com> + */ + +#define FLIPPED_DIRECTION 1 +#define NORMAL_DIRECTION 0 + +/** + * struct console_simple_priv - Private data for this driver + * + * @video_fontdata font graphical representation data + */ +struct console_simple_priv { + struct video_fontdata *fontdata; +}; + +/** + * Checks if bits per pixel supported. + * + * @param bpix framebuffer bits per pixel. + * + * @returns 0, if supported, or else -ENOSYS. + */ +int check_bpix_support(int bpix); + +/** + * Fill 1 pixel in framebuffer, and go to next one. + * + * @param dstp a pointer to pointer to framebuffer. + * @param value value to write to framebuffer. + * @param pbytes framebuffer bytes per pixel. + * @param step framebuffer pointer increment. Usually is equal to pbytes, + * and may be negative to control filling direction. + */ +void fill_pixel_and_goto_next(void **dstp, u32 value, int pbytes, int step); + +/** + * Fills 1 character in framebuffer vertically. Vertically means we're filling char font data rows + * across the lines. + * + * @param pfont a pointer to character font data. + * @param line a pointer to pointer to framebuffer. It's a point for upper left char corner + * @param vid_priv driver private data. + * @fontdata font graphical representation data + * @param direction controls character orientation. Can be normal or flipped. + * When normal: When flipped: + *|-----------------------------------------------| + *| line stepping | | + *| | | stepping -> | + *| * | | * * * | + *| * * v | * | + *| * | * | + *| * | * * ^ | + *| * * * | * | | + *| | | | + *| stepping -> | line stepping | + *|---!!we're starting from upper left char corner| + *|-----------------------------------------------| + * + * @returns 0, if success, or else error code. + */ +int fill_char_vertically(uchar *pfont, void **line, struct video_priv *vid_priv, + struct video_fontdata *fontdata, bool direction); + +/** + * Fills 1 character in framebuffer horizontally. + * Horizontally means we're filling char font data columns across the lines. + * + * @param pfont a pointer to character font data. + * @param line a pointer to pointer to framebuffer. It's a point for upper left char corner + * @param vid_priv driver private data. + * @fontdata font graphical representation data + * @param direction controls character orientation. Can be normal or flipped. + * When normal: When flipped: + *|-----------------------------------------------| + *| * | line stepping | + *| ^ * * * * * | | | + *| | * * | v * * | + *| | | * * * * * | + *| line stepping | * | + *| | | + *| stepping -> | <- stepping | + *|---!!we're starting from upper left char corner| + *|-----------------------------------------------| + * + * @returns 0, if success, or else error code. + */ +int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_priv, + struct video_fontdata *fontdata, bool direction); + +/** + * console probe function. + * + * @param dev a pointer to device. + * + * @returns 0, if success, or else error code. + */ +int console_probe(struct udevice *dev); + +/** + * Internal function to be used in as ops. + * See details in video_console.h get_font_size function + **/ +const char *console_simple_get_font_size(struct udevice *dev, uint *sizep); + +/** + * Internal function to be used in as ops. + * See details in video_console.h get_font function + **/ +int console_simple_get_font(struct udevice *dev, int seq, struct vidfont_info *info); + +/** + * Internal function to be used in as ops. + * See details in video_console.h select_font function + **/ +int console_simple_select_font(struct udevice *dev, const char *name, uint size); diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index 6aaacff10d..da89f43144 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -78,24 +78,40 @@ void video_set_flush_dcache(struct udevice *dev, bool flush) priv->flush_dcache = flush; } +static ulong alloc_fb_(ulong align, ulong size, ulong *addrp) +{ + ulong base; + + align = align ? align : 1 << 20; + base = *addrp - size; + base &= ~(align - 1); + size = *addrp - base; + *addrp = base; + + return size; +} + static ulong alloc_fb(struct udevice *dev, ulong *addrp) { struct video_uc_plat *plat = dev_get_uclass_plat(dev); - ulong base, align, size; + ulong size; + + if (!plat->size) { + if (IS_ENABLED(CONFIG_VIDEO_COPY) && plat->copy_size) { + size = alloc_fb_(plat->align, plat->copy_size, addrp); + plat->copy_base = *addrp; + return size; + } - if (!plat->size) return 0; + } /* Allow drivers to allocate the frame buffer themselves */ if (plat->base) return 0; - align = plat->align ? plat->align : 1 << 20; - base = *addrp - plat->size; - base &= ~(align - 1); - plat->base = base; - size = *addrp - base; - *addrp = base; + size = alloc_fb_(plat->align, plat->size, addrp); + plat->base = *addrp; return size; } @@ -529,8 +545,8 @@ static int video_post_bind(struct udevice *dev) addr = uc_priv->video_ptr; size = alloc_fb(dev, &addr); if (addr < gd->video_bottom) { - /* Device tree node may need the 'u-boot,dm-pre-reloc' or - * 'u-boot,dm-pre-proper' tag + /* Device tree node may need the 'bootph-all' or + * 'bootph-some-ram' tag */ printf("Video device '%s' cannot allocate frame buffer memory -ensure the device is set up before relocation\n", dev->name); |