diff options
Diffstat (limited to 'drivers')
30 files changed, 2185 insertions, 73 deletions
diff --git a/drivers/ata/ahci-pci.c b/drivers/ata/ahci-pci.c index 11ec98b56f9..b1d231e0f9e 100644 --- a/drivers/ata/ahci-pci.c +++ b/drivers/ata/ahci-pci.c @@ -5,6 +5,7 @@ #include <common.h> #include <ahci.h> +#include <scsi.h> #include <dm.h> #include <pci.h> @@ -28,6 +29,7 @@ static const struct udevice_id ahci_pci_ids[] = { U_BOOT_DRIVER(ahci_pci) = { .name = "ahci_pci", .id = UCLASS_AHCI, + .ops = &scsi_ops, .of_match = ahci_pci_ids, .bind = ahci_pci_bind, .probe = ahci_pci_probe, diff --git a/drivers/clk/sifive/fu740-prci.c b/drivers/clk/sifive/fu740-prci.c index 9a642c1c99c..b025050e224 100644 --- a/drivers/clk/sifive/fu740-prci.c +++ b/drivers/clk/sifive/fu740-prci.c @@ -20,7 +20,7 @@ #include "sifive-prci.h" #include <asm/io.h> -int sifive_prci_fu740_pciauxclk_enable(struct __prci_clock *pc, bool enable) +int sifive_prci_fu740_pcieauxclk_enable(struct __prci_clock *pc, bool enable) { struct __prci_wrpll_data *pwd = pc->pwd; struct __prci_data *pd = pc->pd; @@ -98,7 +98,7 @@ static const struct __prci_clock_ops sifive_fu740_prci_hfpclkplldiv_clk_ops = { }; static const struct __prci_clock_ops sifive_fu740_prci_pcieaux_clk_ops = { - .enable_clk = sifive_prci_fu740_pciauxclk_enable, + .enable_clk = sifive_prci_fu740_pcieauxclk_enable, }; /* List of clock controls provided by the PRCI */ @@ -150,7 +150,7 @@ struct __prci_clock __prci_init_clocks_fu740[] = { .ops = &sifive_fu740_prci_hfpclkplldiv_clk_ops, }, [PRCI_CLK_PCIEAUX] { - .name = "pciaux", + .name = "pcieaux", .parent_name = "", .ops = &sifive_fu740_prci_pcieaux_clk_ops, .pwd = &__prci_pcieaux_data, diff --git a/drivers/ddr/marvell/a38x/ddr3_training_ip_flow.h b/drivers/ddr/marvell/a38x/ddr3_training_ip_flow.h index ab152cb455e..55832a55405 100644 --- a/drivers/ddr/marvell/a38x/ddr3_training_ip_flow.h +++ b/drivers/ddr/marvell/a38x/ddr3_training_ip_flow.h @@ -8,6 +8,7 @@ #include "ddr3_training_ip.h" #include "ddr3_training_ip_db.h" +#include "mv_ddr_plat.h" #define KILLER_PATTERN_LENGTH 32 #define EXT_ACCESS_BURST_LENGTH 8 @@ -112,9 +113,12 @@ int ddr3_tip_configure_odpg(u32 dev_num, enum hws_access_type access_type, int ddr3_tip_write_mrs_cmd(u32 dev_num, u32 *cs_mask_arr, enum mr_number mr_num, u32 data, u32 mask); int ddr3_tip_write_cs_result(u32 dev_num, u32 offset); int ddr3_tip_reset_fifo_ptr(u32 dev_num); -int ddr3_tip_read_pup_value(u32 dev_num, u32 pup_values[], int reg_addr, u32 mask); -int ddr3_tip_read_adll_value(u32 dev_num, u32 pup_values[], u32 reg_addr, u32 mask); -int ddr3_tip_write_adll_value(u32 dev_num, u32 pup_values[], u32 reg_addr); +int ddr3_tip_read_adll_value(u32 dev_num, + u32 pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM], + u32 reg_addr, u32 mask); +int ddr3_tip_write_adll_value(u32 dev_num, + u32 pup_values[MAX_INTERFACE_NUM * MAX_BUS_NUM], + u32 reg_addr); int ddr3_tip_tune_training_params(u32 dev_num, struct tune_train_params *params); #endif /* _DDR3_TRAINING_IP_FLOW_H_ */ diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 57a4efb88ed..41065dd5026 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -169,6 +169,12 @@ config SYS_I2C_IMX_LPI2C help Add support for the NXP i.MX LPI2C driver. +config SYS_I2C_LPC32XX + bool "LPC32XX I2C driver" + depends on ARCH_LPC32XX + help + Enable support for the LPC32xx I2C driver. + config SYS_I2C_MESON bool "Amlogic Meson I2C driver" depends on DM_I2C && ARCH_MESON @@ -455,6 +461,13 @@ config SYS_I2C_STM32F7 _ Optional clock stretching _ Software reset +config SYS_I2C_SYNQUACER + bool "Socionext SynQuacer I2C controller" + depends on ARCH_SYNQUACER && DM_I2C + help + Support for Socionext Synquacer I2C controller. This I2C controller + will be used for RTC and LS-connector on DeveloperBox. + config SYS_I2C_TEGRA bool "NVIDIA Tegra internal I2C controller" depends on ARCH_TEGRA diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 8c9f1fcd8b9..06a1150f03d 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o obj-$(CONFIG_SYS_I2C_STM32F7) += stm32f7_i2c.o +obj-$(CONFIG_SYS_I2C_SYNQUACER) += synquacer_i2c.o obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o obj-$(CONFIG_SYS_I2C_UNIPHIER) += i2c-uniphier.o obj-$(CONFIG_SYS_I2C_UNIPHIER_F) += i2c-uniphier-f.o diff --git a/drivers/i2c/lpc32xx_i2c.c b/drivers/i2c/lpc32xx_i2c.c index f89f7955e4c..774129ad8ea 100644 --- a/drivers/i2c/lpc32xx_i2c.c +++ b/drivers/i2c/lpc32xx_i2c.c @@ -38,7 +38,6 @@ /* Status register values */ #define LPC32XX_I2C_STAT_TFF 0x00000400 #define LPC32XX_I2C_STAT_RFE 0x00000200 -#define LPC32XX_I2C_STAT_DRMI 0x00000008 #define LPC32XX_I2C_STAT_NAI 0x00000004 #define LPC32XX_I2C_STAT_TDI 0x00000001 @@ -283,11 +282,7 @@ static int lpc32xx_i2c_probe(struct udevice *bus) { struct lpc32xx_i2c_dev *dev = dev_get_plat(bus); - /* - * FIXME: This is not permitted - * dev_seq(bus) = dev->index; - */ - + dev->base = dev_read_addr_ptr(bus); __i2c_init(dev->base, dev->speed, 0, dev->index); return 0; } @@ -353,9 +348,15 @@ static const struct dm_i2c_ops lpc32xx_i2c_ops = { .set_bus_speed = lpc32xx_i2c_set_bus_speed, }; +static const struct udevice_id lpc32xx_i2c_ids[] = { + { .compatible = "nxp,pnx-i2c" }, + { } +}; + U_BOOT_DRIVER(i2c_lpc32xx) = { - .id = UCLASS_I2C, .name = "i2c_lpc32xx", + .id = UCLASS_I2C, + .of_match = lpc32xx_i2c_ids, .probe = lpc32xx_i2c_probe, .ops = &lpc32xx_i2c_ops, }; diff --git a/drivers/i2c/synquacer_i2c.c b/drivers/i2c/synquacer_i2c.c new file mode 100644 index 00000000000..6672d9435e3 --- /dev/null +++ b/drivers/i2c/synquacer_i2c.c @@ -0,0 +1,338 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + */ + +#include <dm/device_compat.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <linux/sizes.h> +#include <linux/types.h> +#include <dm.h> +#include <fdtdec.h> +#include <i2c.h> +#include <clk.h> + +#define REG_BSR 0x0 +#define REG_BCR 0x4 +#define REG_CCR 0x8 +#define REG_ADR 0xc +#define REG_DAR 0x10 +#define REG_CSR 0x14 +#define REG_FSR 0x18 +#define REG_BC2R 0x1c + +/* I2C register bit definitions */ +#define BSR_FBT BIT(0) // First Byte Transfer +#define BSR_GCA BIT(1) // General Call Address +#define BSR_AAS BIT(2) // Address as Slave +#define BSR_TRX BIT(3) // Transfer/Receive +#define BSR_LRB BIT(4) // Last Received Bit +#define BSR_AL BIT(5) // Arbitration Lost +#define BSR_RSC BIT(6) // Repeated Start Cond. +#define BSR_BB BIT(7) // Bus Busy + +#define BCR_INT BIT(0) // Interrupt +#define BCR_INTE BIT(1) // Interrupt Enable +#define BCR_GCAA BIT(2) // Gen. Call Access Ack. +#define BCR_ACK BIT(3) // Acknowledge +#define BCR_MSS BIT(4) // Master Slave Select +#define BCR_SCC BIT(5) // Start Condition Cont. +#define BCR_BEIE BIT(6) // Bus Error Int Enable +#define BCR_BER BIT(7) // Bus Error + +#define CCR_CS_MASK (0x1f) // CCR Clock Period Sel. +#define CCR_EN BIT(5) // Enable +#define CCR_FM BIT(6) // Speed Mode Select + +#define CSR_CS_MASK (0x3f) // CSR Clock Period Sel. + +#define BC2R_SCLL BIT(0) // SCL Low Drive +#define BC2R_SDAL BIT(1) // SDA Low Drive +#define BC2R_SCLS BIT(4) // SCL Status +#define BC2R_SDAS BIT(5) // SDA Status + +/* PCLK frequency */ +#define BUS_CLK_FR(rate) (((rate) / 20000000) + 1) + +#define I2C_CLK_DEF 62500000 + +/* STANDARD MODE frequency */ +#define CLK_MASTER_STD(rate) \ + DIV_ROUND_UP(DIV_ROUND_UP((rate), I2C_SPEED_STANDARD_RATE) - 2, 2) +/* FAST MODE frequency */ +#define CLK_MASTER_FAST(rate) \ + DIV_ROUND_UP((DIV_ROUND_UP((rate), I2C_SPEED_FAST_RATE) - 2) * 2, 3) + +/* (clkrate <= 18000000) */ +/* calculate the value of CS bits in CCR register on standard mode */ +#define CCR_CS_STD_MAX_18M(rate) \ + ((CLK_MASTER_STD(rate) - 65) \ + & CCR_CS_MASK) + +/* calculate the value of CS bits in CSR register on standard mode */ +#define CSR_CS_STD_MAX_18M(rate) 0x00 + +/* calculate the value of CS bits in CCR register on fast mode */ +#define CCR_CS_FAST_MAX_18M(rate) \ + ((CLK_MASTER_FAST(rate) - 1) \ + & CCR_CS_MASK) + +/* calculate the value of CS bits in CSR register on fast mode */ +#define CSR_CS_FAST_MAX_18M(rate) 0x00 + +/* (clkrate > 18000000) */ +/* calculate the value of CS bits in CCR register on standard mode */ +#define CCR_CS_STD_MIN_18M(rate) \ + ((CLK_MASTER_STD(rate) - 1) \ + & CCR_CS_MASK) + +/* calculate the value of CS bits in CSR register on standard mode */ +#define CSR_CS_STD_MIN_18M(rate) \ + (((CLK_MASTER_STD(rate) - 1) >> 5) \ + & CSR_CS_MASK) + +/* calculate the value of CS bits in CCR register on fast mode */ +#define CCR_CS_FAST_MIN_18M(rate) \ + ((CLK_MASTER_FAST(rate) - 1) \ + & CCR_CS_MASK) + +/* calculate the value of CS bits in CSR register on fast mode */ +#define CSR_CS_FAST_MIN_18M(rate) \ + (((CLK_MASTER_FAST(rate) - 1) >> 5) \ + & CSR_CS_MASK) + +/* min I2C clock frequency 14M */ +#define MIN_CLK_RATE (14 * 1000000) +/* max I2C clock frequency 200M */ +#define MAX_CLK_RATE (200 * 1000000) +/* I2C clock frequency 18M */ +#define CLK_RATE_18M (18 * 1000000) + +#define SPEED_FM 400 // Fast Mode +#define SPEED_SM 100 // Standard Mode + +DECLARE_GLOBAL_DATA_PTR; + +struct synquacer_i2c { + void __iomem *base; + unsigned long pclkrate; + unsigned long speed_khz; +}; + +static int wait_irq(struct udevice *dev) +{ + struct synquacer_i2c *i2c = dev_get_priv(dev); + int timeout = 500000; + + do { + if (readb(i2c->base + REG_BCR) & BCR_INT) + return 0; + } while (timeout--); + + pr_err("%s: timeout\n", __func__); + return -1; +} + +static int synquacer_i2c_xfer_start(struct synquacer_i2c *i2c, + int addr, int read) +{ + u8 bsr, bcr; + + writeb((addr << 1) | (read ? 1 : 0), i2c->base + REG_DAR); + + bsr = readb(i2c->base + REG_BSR); + bcr = readb(i2c->base + REG_BCR); + + if ((bsr & BSR_BB) && !(bcr & BCR_MSS)) + return -EBUSY; + + if (bsr & BSR_BB) { + writeb(bcr | BCR_SCC, i2c->base + REG_BCR); + } else { + if (bcr & BCR_MSS) + return -EAGAIN; + /* Start Condition + Enable Interrupts */ + writeb(bcr | BCR_MSS | BCR_INTE | BCR_BEIE, i2c->base + REG_BCR); + } + + udelay(100); + return 0; +} + +static int synquacer_i2c_xfer(struct udevice *bus, + struct i2c_msg *msg, int nmsgs) +{ + struct synquacer_i2c *i2c = dev_get_priv(bus); + u8 bsr, bcr; + int idx; + + for (; nmsgs > 0; nmsgs--, msg++) { + synquacer_i2c_xfer_start(i2c, msg->addr, msg->flags & I2C_M_RD); + if (wait_irq(bus)) + return -EREMOTEIO; + + bsr = readb(i2c->base + REG_BSR); + if (bsr & BSR_LRB) { + debug("%s: No ack received\n", __func__); + return -EREMOTEIO; + } + + idx = 0; + do { + bsr = readb(i2c->base + REG_BSR); + bcr = readb(i2c->base + REG_BCR); + if (bcr & BCR_BER) { + debug("%s: Bus error detected\n", __func__); + return -EREMOTEIO; + } + if ((bsr & BSR_AL) || !(bcr & BCR_MSS)) { + debug("%s: Arbitration lost\n", __func__); + return -EREMOTEIO; + } + + if (msg->flags & I2C_M_RD) { + bcr = BCR_MSS | BCR_INTE | BCR_BEIE; + if (idx < msg->len - 1) + bcr |= BCR_ACK; + writeb(bcr, i2c->base + REG_BCR); + if (wait_irq(bus)) + return -EREMOTEIO; + bsr = readb(i2c->base + REG_BSR); + if (!(bsr & BSR_FBT)) + msg->buf[idx++] = readb(i2c->base + REG_DAR); + } else { + writeb(msg->buf[idx++], i2c->base + REG_DAR); + bcr = BCR_MSS | BCR_INTE | BCR_BEIE; + writeb(bcr, i2c->base + REG_BCR); + if (wait_irq(bus)) + return -EREMOTEIO; + bsr = readb(i2c->base + REG_BSR); + if (bsr & BSR_LRB) { + debug("%s: no ack\n", __func__); + return -EREMOTEIO; + } + } + } while (idx < msg->len); + } + + /* Force bus state to idle, terminating any ongoing transfer */ + writeb(0, i2c->base + REG_BCR); + udelay(100); + + return 0; +} + +static void synquacer_i2c_hw_reset(struct synquacer_i2c *i2c) +{ + /* Disable clock */ + writeb(0, i2c->base + REG_CCR); + writeb(0, i2c->base + REG_CSR); + + /* Set own Address */ + writeb(0, i2c->base + REG_ADR); + + /* Set PCLK frequency */ + writeb(BUS_CLK_FR(i2c->pclkrate), i2c->base + REG_FSR); + + /* clear IRQ (INT=0, BER=0), Interrupt Disable */ + writeb(0, i2c->base + REG_BCR); + writeb(0, i2c->base + REG_BC2R); +} + +static int synquacer_i2c_get_bus_speed(struct udevice *bus) +{ + struct synquacer_i2c *i2c = dev_get_priv(bus); + + return i2c->speed_khz * 1000; +} + +static int synquacer_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) +{ + struct synquacer_i2c *i2c = dev_get_priv(bus); + u32 rt = i2c->pclkrate; + u8 ccr_cs, csr_cs; + + /* Set PCLK frequency */ + writeb(BUS_CLK_FR(i2c->pclkrate), i2c->base + REG_FSR); + + if (speed >= SPEED_FM * 1000) { + i2c->speed_khz = SPEED_FM; + if (i2c->pclkrate <= CLK_RATE_18M) { + ccr_cs = CCR_CS_FAST_MAX_18M(rt); + csr_cs = CSR_CS_FAST_MAX_18M(rt); + } else { + ccr_cs = CCR_CS_FAST_MIN_18M(rt); + csr_cs = CSR_CS_FAST_MIN_18M(rt); + } + + /* Set Clock and enable, Set fast mode */ + writeb(ccr_cs | CCR_FM | CCR_EN, i2c->base + REG_CCR); + writeb(csr_cs, i2c->base + REG_CSR); + } else { + i2c->speed_khz = SPEED_SM; + if (i2c->pclkrate <= CLK_RATE_18M) { + ccr_cs = CCR_CS_STD_MAX_18M(rt); + csr_cs = CSR_CS_STD_MAX_18M(rt); + } else { + ccr_cs = CCR_CS_STD_MIN_18M(rt); + csr_cs = CSR_CS_STD_MIN_18M(rt); + } + + /* Set Clock and enable, Set standard mode */ + writeb(ccr_cs | CCR_EN, i2c->base + REG_CCR); + writeb(csr_cs, i2c->base + REG_CSR); + } + + return 0; +} + +static int synquacer_i2c_of_to_plat(struct udevice *bus) +{ + struct synquacer_i2c *priv = dev_get_priv(bus); + struct clk ck; + int ret; + + ret = clk_get_by_index(bus, 0, &ck); + if (ret < 0) { + priv->pclkrate = I2C_CLK_DEF; + } else { + clk_enable(&ck); + priv->pclkrate = clk_get_rate(&ck); + } + + return 0; +} + +static int synquacer_i2c_probe(struct udevice *bus) +{ + struct synquacer_i2c *i2c = dev_get_priv(bus); + + i2c->base = dev_read_addr_ptr(bus); + synquacer_i2c_hw_reset(i2c); + synquacer_i2c_set_bus_speed(bus, 400000); /* set default speed */ + return 0; +} + +static const struct dm_i2c_ops synquacer_i2c_ops = { + .xfer = synquacer_i2c_xfer, + .set_bus_speed = synquacer_i2c_set_bus_speed, + .get_bus_speed = synquacer_i2c_get_bus_speed, +}; + +static const struct udevice_id synquacer_i2c_ids[] = { + { + .compatible = "socionext,synquacer-i2c", + }, + { } +}; + +U_BOOT_DRIVER(sni_synquacer_i2c) = { + .name = "sni_synquacer_i2c", + .id = UCLASS_I2C, + .of_match = synquacer_i2c_ids, + .of_to_plat = synquacer_i2c_of_to_plat, + .probe = synquacer_i2c_probe, + .priv_auto = sizeof(struct synquacer_i2c), + .ops = &synquacer_i2c_ops, +}; diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 0909f502a16..717ce5a62f4 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -561,6 +561,16 @@ config MMC_SDHCI_IPROC If unsure, say N. +config MMC_SDHCI_F_SDH30 + bool "SDHCI support for Fujitsu Semiconductor F_SDH30" + depends on BLK && DM_MMC + depends on MMC_SDHCI + help + This selects the Secure Digital Host Controller Interface (SDHCI) + Needed by some Fujitsu SoC for MMC / SD / SDIO support. + If you have a controller with this interface, say Y or M here. + If unsure, say N. + config MMC_SDHCI_KONA bool "SDHCI support on Broadcom KONA platform" depends on MMC_SDHCI @@ -727,6 +737,15 @@ config MMC_SUNXI_HAS_MODE_SWITCH bool depends on MMC_SUNXI +config MMC_PITON + bool "MMC support for OpenPiton SoC" + depends on DM_MMC && BLK + help + This selects support for the SD host controller on OpenPiton SoC. + Note that this SD controller directly exposes the contents of the + SD card as memory mapped, so there is no manual configuration + required + config GENERIC_ATMEL_MCI bool "Atmel Multimedia Card Interface support" depends on DM_MMC && BLK && ARCH_AT91 diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 89d6af3db30..dde6cd563ff 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -72,7 +72,9 @@ obj-$(CONFIG_MMC_SDHCI_XENON) += xenon_sdhci.o obj-$(CONFIG_MMC_SDHCI_ZYNQ) += zynq_sdhci.o obj-$(CONFIG_MMC_SUNXI) += sunxi_mmc.o +obj-$(CONFIG_MMC_PITON) += piton_mmc.o obj-$(CONFIG_MMC_UNIPHIER) += tmio-common.o uniphier-sd.o obj-$(CONFIG_RENESAS_SDHI) += tmio-common.o renesas-sdhi.o obj-$(CONFIG_MMC_BCM2835) += bcm2835_sdhost.o obj-$(CONFIG_MMC_MTK) += mtk-sd.o +obj-$(CONFIG_MMC_SDHCI_F_SDH30) += f_sdh30.o diff --git a/drivers/mmc/f_sdh30.c b/drivers/mmc/f_sdh30.c new file mode 100644 index 00000000000..3a85d9e348a --- /dev/null +++ b/drivers/mmc/f_sdh30.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Socionext F_SDH30 eMMC driver + * Copyright 2021 Linaro Ltd. + * Copyright 2021 Socionext, Inc. + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <malloc.h> +#include <sdhci.h> + +struct f_sdh30_plat { + struct mmc_config cfg; + struct mmc mmc; +}; + +DECLARE_GLOBAL_DATA_PTR; + +static int f_sdh30_sdhci_probe(struct udevice *dev) +{ + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct f_sdh30_plat *plat = dev_get_plat(dev); + struct sdhci_host *host = dev_get_priv(dev); + int ret; + + ret = mmc_of_parse(dev, &plat->cfg); + if (ret) + return ret; + + host->mmc = &plat->mmc; + host->mmc->dev = dev; + host->mmc->priv = host; + + ret = sdhci_setup_cfg(&plat->cfg, host, 200000000, 400000); + if (ret) + return ret; + + upriv->mmc = host->mmc; + + mmc_set_clock(host->mmc, host->mmc->cfg->f_min, MMC_CLK_ENABLE); + + return sdhci_probe(dev); +} + +static int f_sdh30_of_to_plat(struct udevice *dev) +{ + struct sdhci_host *host = dev_get_priv(dev); + + host->name = strdup(dev->name); + host->ioaddr = dev_read_addr_ptr(dev); + host->bus_width = dev_read_u32_default(dev, "bus-width", 4); + host->index = dev_read_u32_default(dev, "index", 0); + + return 0; +} + +static int f_sdh30_bind(struct udevice *dev) +{ + struct f_sdh30_plat *plat = dev_get_plat(dev); + + return sdhci_bind(dev, &plat->mmc, &plat->cfg); +} + +static const struct udevice_id f_sdh30_mmc_ids[] = { + { .compatible = "fujitsu,mb86s70-sdhci-3.0" }, + { } +}; + +U_BOOT_DRIVER(f_sdh30_drv) = { + .name = "f_sdh30_sdhci", + .id = UCLASS_MMC, + .of_match = f_sdh30_mmc_ids, + .of_to_plat = f_sdh30_of_to_plat, + .ops = &sdhci_ops, + .bind = f_sdh30_bind, + .probe = f_sdh30_sdhci_probe, + .priv_auto = sizeof(struct sdhci_host), + .plat_auto = sizeof(struct f_sdh30_plat), +}; diff --git a/drivers/mmc/piton_mmc.c b/drivers/mmc/piton_mmc.c new file mode 100644 index 00000000000..9f5da6d6339 --- /dev/null +++ b/drivers/mmc/piton_mmc.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2009 SAMSUNG Electronics + * Minkyu Kang <mk7.kang@samsung.com> + * Jaehoon Chung <jh80.chung@samsung.com> + * Portions Copyright 2011-2019 NVIDIA Corporation + * Portions Copyright 2021 Tianrui Wei + * This file is adapted from tegra_mmc.c + * Tianrui Wei <tianrui-wei@outlook.com> + */ + +#include <asm/gpio.h> +#include <asm/io.h> +#include <common.h> +#include <div64.h> +#include <dm.h> +#include <errno.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/types.h> +#include <linux/sizes.h> +#include <log.h> +#include <mmc.h> + + +#define PITON_MMC_DUMMY_F_MAX 20000000 +#define PITON_MMC_DUMMY_F_MIN 10000000 +#define PITON_MMC_DUMMY_CAPACITY SZ_4G << 3 +#define PITON_MMC_DUMMY_B_MAX SZ_4G + +struct piton_mmc_plat { + struct mmc_config cfg; + struct mmc mmc; +}; + +struct piton_mmc_priv { + void __iomem *base_addr; +}; + +static int piton_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + if (!data) + return 0; + + struct piton_mmc_priv *priv = dev_get_priv(dev); + u32 *buff, *start_addr, *write_src; + size_t byte_cnt, start_block; + + buff = (u32 *)data->dest; + write_src = (u32 *)data->src; + start_block = cmd->cmdarg; + start_addr = priv->base_addr + start_block; + + /* if there is a read */ + for (byte_cnt = data->blocks * data->blocksize; byte_cnt; + byte_cnt -= sizeof(u32)) { + if (data->flags & MMC_DATA_READ) { + *buff++ = readl(start_addr++); + } + else if (data->flags & MMC_DATA_WRITE) { + writel(*write_src++,start_addr++); + } + } + return 0; +} + +static int piton_mmc_ofdata_to_platdata(struct udevice *dev) +{ + struct piton_mmc_priv *priv = dev_get_priv(dev); + struct piton_mmc_plat *plat = dev_get_plat(dev); + struct mmc_config *cfg; + struct mmc *mmc; + struct blk_desc *bdesc; + + priv->base_addr = (void *)dev_read_addr(dev); + cfg = &plat->cfg; + cfg->name = "PITON MMC"; + cfg->host_caps = MMC_MODE_8BIT; + cfg->f_max = PITON_MMC_DUMMY_F_MAX; + cfg->f_min = PITON_MMC_DUMMY_F_MIN; + cfg->voltages = MMC_VDD_21_22; + + mmc = &plat->mmc; + mmc->read_bl_len = MMC_MAX_BLOCK_LEN; + mmc->capacity_user = PITON_MMC_DUMMY_CAPACITY; + mmc->capacity_user *= mmc->read_bl_len; + mmc->capacity_boot = 0; + mmc->capacity_rpmb = 0; + for (int i = 0; i < 4; i++) + mmc->capacity_gp[i] = 0; + mmc->capacity = PITON_MMC_DUMMY_CAPACITY; + mmc->has_init = 1; + + bdesc = mmc_get_blk_desc(mmc); + bdesc->lun = 0; + bdesc->hwpart = 0; + bdesc->type = 0; + bdesc->blksz = mmc->read_bl_len; + bdesc->log2blksz = LOG2(bdesc->blksz); + bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); + + return 0; +} + +static int piton_mmc_getcd(struct udevice *dev) +{ + return 1; +} + +static const struct dm_mmc_ops piton_mmc_ops = { + .send_cmd = piton_mmc_send_cmd, + .get_cd = piton_mmc_getcd, +}; + +static int piton_mmc_probe(struct udevice *dev) +{ + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct piton_mmc_plat *plat = dev_get_plat(dev); + struct mmc_config *cfg = &plat->cfg; + + cfg->name = dev->name; + upriv->mmc = &plat->mmc; + upriv->mmc->has_init = 1; + upriv->mmc->capacity = PITON_MMC_DUMMY_CAPACITY; + upriv->mmc->read_bl_len = MMC_MAX_BLOCK_LEN; + return 0; +} + +static int piton_mmc_bind(struct udevice *dev) +{ + struct piton_mmc_plat *plat = dev_get_plat(dev); + struct mmc_config *cfg = &plat->cfg; + + cfg->name = dev->name; + cfg->host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS | MMC_MODE_8BIT; + cfg->voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34; + cfg->f_min = PITON_MMC_DUMMY_F_MIN; + cfg->f_max = PITON_MMC_DUMMY_F_MAX; + cfg->b_max = MMC_MAX_BLOCK_LEN; + + return mmc_bind(dev, &plat->mmc, cfg); +} + +static const struct udevice_id piton_mmc_ids[] = { + {.compatible = "openpiton,piton-mmc"}, + {/* sentinel */} +}; + +U_BOOT_DRIVER(piton_mmc_drv) = { + .name = "piton_mmc", + .id = UCLASS_MMC, + .of_match = piton_mmc_ids, + .of_to_plat = piton_mmc_ofdata_to_platdata, + .bind = piton_mmc_bind, + .probe = piton_mmc_probe, + .ops = &piton_mmc_ops, + .plat_auto = sizeof(struct piton_mmc_plat), + .priv_auto = sizeof(struct piton_mmc_priv), +}; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 9fc28b149d0..2a7c8f9a7ff 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -548,21 +548,14 @@ config SMC911X_BASE of the device (I/O space) endif #DM_ETH -choice - prompt "SMC911X bus width" - default SMC911X_16_BIT - config SMC911X_32_BIT - bool "Enable 32-bit interface" - -config SMC911X_16_BIT - bool "Enable 16-bit interface" + bool "Enable SMC911X 32-bit interface" + default n help - Define this if data bus is 16 bits. If your processor - automatically converts one 32 bit word to two 16 bit - words you may also try CONFIG_SMC911X_32_BIT. + Define this if data bus is 32 bits. If your processor use a + narrower 16 bit bus or cannot convert one 32 bit word to two 16 bit + words, leave this to "n". -endchoice endif #SMC911X config SUN7I_GMAC diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index b012bed517d..f048e9d5851 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -238,8 +238,6 @@ struct eqos_tegra186_regs { #define EQOS_AUTO_CAL_STATUS_ACTIVE BIT(31) /* Descriptors */ -/* We assume ARCH_DMA_MINALIGN >= 16; 16 is the EQOS HW minimum */ -#define EQOS_DESCRIPTOR_ALIGN ARCH_DMA_MINALIGN #define EQOS_DESCRIPTORS_TX 4 #define EQOS_DESCRIPTORS_RX 4 #define EQOS_DESCRIPTORS_NUM (EQOS_DESCRIPTORS_TX + EQOS_DESCRIPTORS_RX) diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c index f6fc7801b95..566cdc7e546 100644 --- a/drivers/net/fsl_enetc.c +++ b/drivers/net/fsl_enetc.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * ENETC ethernet controller driver - * Copyright 2017-2019 NXP + * Copyright 2017-2021 NXP */ #include <common.h> @@ -178,21 +178,43 @@ static int enetc_init_sgmii(struct udevice *dev) } /* set up MAC for RGMII */ -static int enetc_init_rgmii(struct udevice *dev) +static void enetc_init_rgmii(struct udevice *dev, struct phy_device *phydev) { struct enetc_priv *priv = dev_get_priv(dev); - u32 if_mode; + u32 old_val, val; - /* enable RGMII AN */ - if_mode = enetc_read_port(priv, ENETC_PM_IF_MODE); - if_mode |= ENETC_PM_IF_MODE_AN_ENA; - enetc_write_port(priv, ENETC_PM_IF_MODE, if_mode); + old_val = val = enetc_read_port(priv, ENETC_PM_IF_MODE); - return 0; + /* disable unreliable RGMII in-band signaling and force the MAC into + * the speed negotiated by the PHY. + */ + val &= ~ENETC_PM_IF_MODE_AN_ENA; + + if (phydev->speed == SPEED_1000) { + val &= ~ENETC_PM_IFM_SSP_MASK; + val |= ENETC_PM_IFM_SSP_1000; + } else if (phydev->speed == SPEED_100) { + val &= ~ENETC_PM_IFM_SSP_MASK; + val |= ENETC_PM_IFM_SSP_100; + } else if (phydev->speed == SPEED_10) { + val &= ~ENETC_PM_IFM_SSP_MASK; + val |= ENETC_PM_IFM_SSP_10; + } + + if (phydev->duplex == DUPLEX_FULL) + val |= ENETC_PM_IFM_FULL_DPX; + else + val &= ~ENETC_PM_IFM_FULL_DPX; + + if (val == old_val) + return; + + enetc_write_port(priv, ENETC_PM_IF_MODE, val); } /* set up MAC configuration for the given interface type */ -static void enetc_setup_mac_iface(struct udevice *dev) +static void enetc_setup_mac_iface(struct udevice *dev, + struct phy_device *phydev) { struct enetc_priv *priv = dev_get_priv(dev); u32 if_mode; @@ -202,7 +224,7 @@ static void enetc_setup_mac_iface(struct udevice *dev) case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_TXID: - enetc_init_rgmii(dev); + enetc_init_rgmii(dev, phydev); break; case PHY_INTERFACE_MODE_XGMII: case PHY_INTERFACE_MODE_USXGMII: @@ -281,21 +303,20 @@ static void enetc_start_pcs(struct udevice *dev) } /* Configure the actual/external ethernet PHY, if one is found */ -static void enetc_config_phy(struct udevice *dev) +static int enetc_config_phy(struct udevice *dev) { struct enetc_priv *priv = dev_get_priv(dev); int supported; priv->phy = dm_eth_phy_connect(dev); - if (!priv->phy) - return; + return -ENODEV; supported = PHY_GBIT_FEATURES | SUPPORTED_2500baseX_Full; priv->phy->supported &= supported; priv->phy->advertising &= supported; - phy_config(priv->phy); + return phy_config(priv->phy); } /* @@ -335,9 +356,8 @@ static int enetc_probe(struct udevice *dev) dm_pci_clrset_config16(dev, PCI_COMMAND, 0, PCI_COMMAND_MEMORY); enetc_start_pcs(dev); - enetc_config_phy(dev); - return 0; + return enetc_config_phy(dev); } /* @@ -548,12 +568,9 @@ static int enetc_start(struct udevice *dev) enetc_setup_tx_bdr(dev); enetc_setup_rx_bdr(dev); - enetc_setup_mac_iface(dev); - - if (priv->phy) - phy_startup(priv->phy); + enetc_setup_mac_iface(dev, priv->phy); - return 0; + return phy_startup(priv->phy); } /* diff --git a/drivers/net/fsl_enetc.h b/drivers/net/fsl_enetc.h index 110c1d78fbc..69f2f4aaff1 100644 --- a/drivers/net/fsl_enetc.h +++ b/drivers/net/fsl_enetc.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* * ENETC ethernet controller driver - * Copyright 2017-2019 NXP + * Copyright 2017-2021 NXP */ #ifndef _ENETC_H @@ -77,6 +77,11 @@ enum enetc_bdr_type {TX, RX}; #define ENETC_PM_IF_MODE 0x8300 #define ENETC_PM_IF_MODE_RG BIT(2) #define ENETC_PM_IF_MODE_AN_ENA BIT(15) +#define ENETC_PM_IFM_SSP_MASK GENMASK(14, 13) +#define ENETC_PM_IFM_SSP_1000 (2 << 13) +#define ENETC_PM_IFM_SSP_100 (0 << 13) +#define ENETC_PM_IFM_SSP_10 (1 << 13) +#define ENETC_PM_IFM_FULL_DPX BIT(12) #define ENETC_PM_IF_IFMODE_MASK GENMASK(1, 0) /* buffer descriptors count must be multiple of 8 and aligned to 128 bytes */ diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 070ffa82cb9..405bf767530 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -197,6 +197,12 @@ config PHY_MSCC config PHY_NATSEMI bool "National Semiconductor Ethernet PHYs support" +config PHY_NXP_C45_TJA11XX + tristate "NXP C45 TJA11XX PHYs" + help + Enable support for NXP C45 TJA11XX PHYs. + Currently supports only the TJA1103 PHY. + config PHY_REALTEK bool "Realtek Ethernet PHYs support" diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index e967f822016..218b8c7669b 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_PHY_MICREL_KSZ8XXX) += micrel_ksz8xxx.o obj-$(CONFIG_PHY_MICREL_KSZ90X1) += micrel_ksz90x1.o obj-$(CONFIG_PHY_MESON_GXL) += meson-gxl.o obj-$(CONFIG_PHY_NATSEMI) += natsemi.o +obj-$(CONFIG_PHY_NXP_C45_TJA11XX) += nxp-c45-tja11xx.o obj-$(CONFIG_PHY_REALTEK) += realtek.o obj-$(CONFIG_PHY_SMSC) += smsc.o obj-$(CONFIG_PHY_TERANETICS) += teranetics.o diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c new file mode 100644 index 00000000000..f86e31f0d9e --- /dev/null +++ b/drivers/net/phy/nxp-c45-tja11xx.c @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NXP C45 PHY driver + * + * Copyright 2021 NXP + * Author: Radu Pirea <radu-nicolae.pirea@oss.nxp.com> + */ +#include <common.h> +#include <dm.h> +#include <dm/devres.h> +#include <linux/delay.h> +#include <linux/math64.h> +#include <linux/mdio.h> +#include <phy.h> + +#define PHY_ID_TJA_1103 0x001BB010 + +#define VEND1_DEVICE_CONTROL 0x0040 +#define DEVICE_CONTROL_RESET BIT(15) +#define DEVICE_CONTROL_CONFIG_GLOBAL_EN BIT(14) +#define DEVICE_CONTROL_CONFIG_ALL_EN BIT(13) + +#define VEND1_PORT_CONTROL 0x8040 +#define PORT_CONTROL_EN BIT(14) + +#define VEND1_PHY_CONTROL 0x8100 +#define PHY_CONFIG_EN BIT(14) +#define PHY_START_OP BIT(0) + +#define VEND1_PHY_CONFIG 0x8108 +#define PHY_CONFIG_AUTO BIT(0) + +#define VEND1_PORT_INFRA_CONTROL 0xAC00 +#define PORT_INFRA_CONTROL_EN BIT(14) + +#define VEND1_RXID 0xAFCC +#define VEND1_TXID 0xAFCD +#define ID_ENABLE BIT(15) + +#define VEND1_ABILITIES 0xAFC4 +#define RGMII_ID_ABILITY BIT(15) +#define RGMII_ABILITY BIT(14) +#define RMII_ABILITY BIT(10) +#define REVMII_ABILITY BIT(9) +#define MII_ABILITY BIT(8) +#define SGMII_ABILITY BIT(0) + +#define VEND1_MII_BASIC_CONFIG 0xAFC6 +#define MII_BASIC_CONFIG_REV BIT(8) +#define MII_BASIC_CONFIG_SGMII 0x9 +#define MII_BASIC_CONFIG_RGMII 0x7 +#define MII_BASIC_CONFIG_RMII 0x5 +#define MII_BASIC_CONFIG_MII 0x4 + +#define RGMII_PERIOD_PS 8000U +#define PS_PER_DEGREE div_u64(RGMII_PERIOD_PS, 360) +#define MIN_ID_PS 1644U +#define MAX_ID_PS 2260U +#define DEFAULT_ID_PS 2000U + +#define RESET_DELAY_MS 25 +#define CONF_EN_DELAY_US 450 + +struct nxp_c45_phy { + u32 tx_delay; + u32 rx_delay; +}; + +static int nxp_c45_soft_reset(struct phy_device *phydev) +{ + int tries = 10, ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_DEVICE_CONTROL, + DEVICE_CONTROL_RESET); + if (ret) + return ret; + + do { + ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, + VEND1_DEVICE_CONTROL); + if (!(ret & DEVICE_CONTROL_RESET)) + return 0; + mdelay(RESET_DELAY_MS); + } while (tries--); + + return -EIO; +} + +static int nxp_c45_start_op(struct phy_device *phydev) +{ + return phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_CONTROL, + PHY_START_OP); +} + +static int nxp_c45_config_enable(struct phy_device *phydev) +{ + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_DEVICE_CONTROL, + DEVICE_CONTROL_CONFIG_GLOBAL_EN | + DEVICE_CONTROL_CONFIG_ALL_EN); + udelay(CONF_EN_DELAY_US); + + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_CONTROL, + PORT_CONTROL_EN); + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_CONTROL, + PHY_CONFIG_EN); + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_INFRA_CONTROL, + PORT_INFRA_CONTROL_EN); + + return 0; +} + +static u64 nxp_c45_get_phase_shift(u64 phase_offset_raw) +{ + /* The delay in degree phase is 73.8 + phase_offset_raw * 0.9. + * To avoid floating point operations we'll multiply by 10 + * and get 1 decimal point precision. + */ + phase_offset_raw *= 10; + phase_offset_raw -= 738; + return div_u64(phase_offset_raw, 9); +} + +static void nxp_c45_disable_delays(struct phy_device *phydev) +{ + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_TXID, 0); + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_RXID, 0); +} + +static int nxp_c45_check_delay(struct phy_device *phydev, u32 delay) +{ + if (delay < MIN_ID_PS) { + pr_err("%s: delay value smaller than %u\n", + phydev->drv->name, MIN_ID_PS); + return -EINVAL; + } + + if (delay > MAX_ID_PS) { + pr_err("%s: delay value higher than %u\n", + phydev->drv->name, MAX_ID_PS); + return -EINVAL; + } + + return 0; +} + +static int nxp_c45_get_delays(struct phy_device *phydev) +{ + struct nxp_c45_phy *priv = phydev->priv; + int ret; + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { + ret = dev_read_u32(phydev->dev, "tx-internal-delay-ps", + &priv->tx_delay); + if (ret) + priv->tx_delay = DEFAULT_ID_PS; + + ret = nxp_c45_check_delay(phydev, priv->tx_delay); + if (ret) { + pr_err("%s: tx-internal-delay-ps invalid value\n", + phydev->drv->name); + return ret; + } + } + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { + ret = dev_read_u32(phydev->dev, "rx-internal-delay-ps", + &priv->rx_delay); + if (ret) + priv->rx_delay = DEFAULT_ID_PS; + + ret = nxp_c45_check_delay(phydev, priv->rx_delay); + if (ret) { + pr_err("%s: rx-internal-delay-ps invalid value\n", + phydev->drv->name); + return ret; + } + } + + return 0; +} + +static void nxp_c45_set_delays(struct phy_device *phydev) +{ + struct nxp_c45_phy *priv = phydev->priv; + u64 tx_delay = priv->tx_delay; + u64 rx_delay = priv->rx_delay; + u64 degree; + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { + degree = div_u64(tx_delay, PS_PER_DEGREE); + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_TXID, + ID_ENABLE | nxp_c45_get_phase_shift(degree)); + } else { + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_TXID, 0); + } + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { + degree = div_u64(rx_delay, PS_PER_DEGREE); + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_RXID, + ID_ENABLE | nxp_c45_get_phase_shift(degree)); + } else { + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_RXID, 0); + } +} + +static int nxp_c45_set_phy_mode(struct phy_device *phydev) +{ + int ret; + + ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_ABILITIES); + pr_debug("%s: Clause 45 managed PHY abilities 0x%x\n", + phydev->drv->name, ret); + + switch (phydev->interface) { + case PHY_INTERFACE_MODE_RGMII: + if (!(ret & RGMII_ABILITY)) { + pr_err("%s: rgmii mode not supported\n", + phydev->drv->name); + return -EINVAL; + } + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG, + MII_BASIC_CONFIG_RGMII); + nxp_c45_disable_delays(phydev); + break; + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + if (!(ret & RGMII_ID_ABILITY)) { + pr_err("%s: rgmii-id, rgmii-txid, rgmii-rxid modes are not supported\n", + phydev->drv->name); + return -EINVAL; + } + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG, + MII_BASIC_CONFIG_RGMII); + ret = nxp_c45_get_delays(phydev); + if (ret) + return ret; + + nxp_c45_set_delays(phydev); + break; + case PHY_INTERFACE_MODE_MII: + if (!(ret & MII_ABILITY)) { + pr_err("%s: mii mode not supported\n", + phydev->drv->name); + return -EINVAL; + } + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG, + MII_BASIC_CONFIG_MII); + break; + case PHY_INTERFACE_MODE_RMII: + if (!(ret & RMII_ABILITY)) { + pr_err("%s: rmii mode not supported\n", + phydev->drv->name); + return -EINVAL; + } + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG, + MII_BASIC_CONFIG_RMII); + break; + case PHY_INTERFACE_MODE_SGMII: + if (!(ret & SGMII_ABILITY)) { + pr_err("%s: sgmii mode not supported\n", + phydev->drv->name); + return -EINVAL; + } + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_MII_BASIC_CONFIG, + MII_BASIC_CONFIG_SGMII); + break; + case PHY_INTERFACE_MODE_INTERNAL: + break; + default: + return -EINVAL; + } + + return 0; +} + +static int nxp_c45_config(struct phy_device *phydev) +{ + int ret; + + ret = nxp_c45_soft_reset(phydev); + if (ret) + return ret; + + ret = nxp_c45_config_enable(phydev); + if (ret) { + pr_err("%s: Failed to enable config\n", phydev->drv->name); + return ret; + } + + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_CONFIG, + PHY_CONFIG_AUTO); + + ret = nxp_c45_set_phy_mode(phydev); + if (ret) { + pr_err("%s: Failed to set phy mode\n", phydev->drv->name); + return ret; + } + + phydev->autoneg = AUTONEG_DISABLE; + + return nxp_c45_start_op(phydev); +} + +static int nxp_c45_startup(struct phy_device *phydev) +{ + u32 reg; + + reg = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_STAT1); + phydev->link = !!(reg & MDIO_STAT1_LSTATUS); + phydev->speed = SPEED_100; + phydev->duplex = DUPLEX_FULL; + return 0; +} + +static int nxp_c45_probe(struct phy_device *phydev) +{ + struct nxp_c45_phy *priv; + + priv = devm_kzalloc(phydev->priv, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + phydev->priv = priv; + + return 0; +} + +static struct phy_driver nxp_tja11xx = { + .name = "NXP C45 TJA1103", + .uid = PHY_ID_TJA_1103, + .mask = 0xfffff0, + .features = PHY_100BT1_FEATURES, + .probe = &nxp_c45_probe, + .config = &nxp_c45_config, + .startup = &nxp_c45_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_nxp_tja11xx_init(void) +{ + phy_register(&nxp_tja11xx); + return 0; +} diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index ed197fa46d7..69acb694606 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -529,6 +529,9 @@ int phy_init(void) #ifdef CONFIG_PHY_NATSEMI phy_natsemi_init(); #endif +#ifdef CONFIG_NXP_C45_TJA11XX_PHY + phy_nxp_tja11xx_init(); +#endif #ifdef CONFIG_PHY_REALTEK phy_realtek_init(); #endif diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 7b79831c281..3afebee4402 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -28,6 +28,7 @@ struct smc911x_priv { phys_addr_t iobase; const struct chip_id *chipid; unsigned char enetaddr[6]; + bool use_32_bit_io; }; static const struct chip_id chip_ids[] = { @@ -48,36 +49,24 @@ static const struct chip_id chip_ids[] = { #define DRIVERNAME "smc911x" -#if defined (CONFIG_SMC911X_32_BIT) && \ - defined (CONFIG_SMC911X_16_BIT) -#error "SMC911X: Only one of CONFIG_SMC911X_32_BIT and \ - CONFIG_SMC911X_16_BIT shall be set" -#endif - -#if defined (CONFIG_SMC911X_32_BIT) static u32 smc911x_reg_read(struct smc911x_priv *priv, u32 offset) { - return readl(priv->iobase + offset); -} + if (priv->use_32_bit_io) + return readl(priv->iobase + offset); -static void smc911x_reg_write(struct smc911x_priv *priv, u32 offset, u32 val) -{ - writel(val, priv->iobase + offset); -} -#elif defined (CONFIG_SMC911X_16_BIT) -static u32 smc911x_reg_read(struct smc911x_priv *priv, u32 offset) -{ return (readw(priv->iobase + offset) & 0xffff) | (readw(priv->iobase + offset + 2) << 16); } + static void smc911x_reg_write(struct smc911x_priv *priv, u32 offset, u32 val) { - writew(val & 0xffff, priv->iobase + offset); - writew(val >> 16, priv->iobase + offset + 2); + if (priv->use_32_bit_io) { + writel(val, priv->iobase + offset); + } else { + writew(val & 0xffff, priv->iobase + offset); + writew(val >> 16, priv->iobase + offset + 2); + } } -#else -#error "SMC911X: undefined bus width" -#endif /* CONFIG_SMC911X_16_BIT */ static u32 smc911x_get_mac_csr(struct smc911x_priv *priv, u8 reg) { @@ -501,6 +490,8 @@ int smc911x_initialize(u8 dev_num, int base_addr) priv->iobase = base_addr; priv->dev.iobase = base_addr; + priv->use_32_bit_io = CONFIG_IS_ENABLED(SMC911X_32_BIT); + /* Try to detect chip. Will fail if not present. */ ret = smc911x_detect_chip(priv); if (ret) { @@ -611,10 +602,18 @@ static int smc911x_of_to_plat(struct udevice *dev) { struct smc911x_priv *priv = dev_get_priv(dev); struct eth_pdata *pdata = dev_get_plat(dev); + u32 io_width; + int ret; pdata->iobase = dev_read_addr(dev); priv->iobase = pdata->iobase; + ret = dev_read_u32(dev, "reg-io-width", &io_width); + if (!ret) + priv->use_32_bit_io = (io_width == 4); + else + priv->use_32_bit_io = CONFIG_IS_ENABLED(SMC911X_32_BIT); + return 0; } diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index b2b7b253f84..782179eb0f6 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -81,6 +81,18 @@ config PCIE_ECAM_GENERIC Say Y here if you want to enable support for generic ECAM-based PCIe host controllers, such as the one emulated by QEMU. +config PCIE_ECAM_SYNQUACER + bool "SynQuacer ECAM-based PCI host controller support" + default n + depends on DM_PCI + select PCI_INIT_R + select PCI_REGION_MULTI_ENTRY + help + Say Y here if you want to enable support for Socionext + SynQuacer SoC's ECAM-based PCIe host controllers. + Note that this must be configured when boot because Linux driver + expects the PCIe RC has been configured in the bootloader. + config PCI_PHYTIUM bool "Phytium PCIe support" depends on DM_PCI diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index c742bb2c94d..6568dc9a088 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -16,6 +16,7 @@ endif obj-$(CONFIG_PCI) += pci_auto_common.o pci_common.o obj-$(CONFIG_PCIE_ECAM_GENERIC) += pcie_ecam_generic.o +obj-$(CONFIG_PCIE_ECAM_SYNQUACER) += pcie_ecam_synquacer.o obj-$(CONFIG_FSL_PCI_INIT) += fsl_pci_init.o obj-$(CONFIG_PCI_INDIRECT_BRIDGE) += pci_indirect.o obj-$(CONFIG_PCI_GT64120) += pci_gt64120.o diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 0bd604d061d..cb9aa818359 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -552,6 +552,9 @@ int pci_auto_config_devices(struct udevice *bus) max_bus = ret; sub_bus = max(sub_bus, max_bus); + if (dev_get_parent(dev) == bus) + continue; + pplat = dev_get_parent_plat(dev); if (pplat->class == (PCI_CLASS_DISPLAY_VGA << 8)) set_vga_bridge_bits(dev); diff --git a/drivers/pci/pcie_ecam_synquacer.c b/drivers/pci/pcie_ecam_synquacer.c new file mode 100644 index 00000000000..c6e7c59f8a6 --- /dev/null +++ b/drivers/pci/pcie_ecam_synquacer.c @@ -0,0 +1,600 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * SynQuacer PCIE host driver + * + * Based on drivers/pci/pcie_ecam_generic.c + * + * Copyright (C) 2016 Imagination Technologies + * Copyright (C) 2021 Linaro Ltd. + */ + +#include <common.h> +#include <dm.h> +#include <pci.h> +#include <log.h> + +#include <asm/io.h> +#include <linux/bitops.h> +#include <linux/delay.h> + +/* iATU registers */ +#define IATU_VIEWPORT_OFF 0x900 +#define IATU_VIEWPORT_INBOUND BIT(31) +#define IATU_VIEWPORT_OUTBOUND 0 +#define IATU_VIEWPORT_REGION_INDEX(idx) ((idx) & 7) + +#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0 0x904 +#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_MEM 0x0 +#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_IO 0x2 +#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_CFG0 0x4 +#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_CFG1 0x5 +#define IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TH BIT(12) + +#define IATU_REGION_CTRL_2_OFF_OUTBOUND_0 0x908 +#define IATU_REGION_CTRL_2_OFF_OUTBOUND_0_REGION_EN BIT(31) +#define IATU_REGION_CTRL_2_OFF_OUTBOUND_0_CFG_SHIFT_MODE BIT(28) +#define IATU_REGION_CTRL_2_OFF_OUTBOUND_0_MSG_CODE_32BIT 0xF +#define IATU_REGION_CTRL_2_OFF_OUTBOUND_0_MSG_CODE_64BIT 0xFF + +#define IATU_LWR_BASE_ADDR_OFF_OUTBOUND_0 0x90C +#define IATU_UPPER_BASE_ADDR_OFF_OUTBOUND_0 0x910 +#define IATU_LIMIT_ADDR_OFF_OUTBOUND_0 0x914 +#define IATU_LWR_TARGET_ADDR_OFF_OUTBOUND_0 0x918 +#define IATU_UPPER_TARGET_ADDR_OFF_OUTBOUND_0 0x91C + +/* Clock and resets */ +#define CORE_CONTROL 0x000 +#define APP_LTSSM_ENABLE BIT(4) +#define DEVICE_TYPE (BIT(3) | BIT(2) | BIT(1) | BIT(0)) + +#define AXI_CLK_STOP 0x004 +#define DBI_ACLK_STOP BIT(8) +#define SLV_ACLK_STOP BIT(4) +#define MSTR_ACLK_STOP BIT(0) +#define DBI_CSYSREQ_REG BIT(9) +#define SLV_CSYSREQ_REG BIT(5) +#define MSTR_CSYSREQ_REG BIT(1) + +#define RESET_CONTROL_1 0x00C +#define PERST_N_O_REG BIT(5) +#define PERST_N_I_REG BIT(4) +#define BUTTON_RST_N_REG BIT(1) +#define PWUP_RST_N_REG BIT(0) + +#define RESET_CONTROL_2 0x010 + +#define RESET_SELECT_1 0x014 +#define SQU_RST_SEL BIT(29) +#define PHY_RST_SEL BIT(28) +#define PWR_RST_SEL BIT(24) +#define STI_RST_SEL BIT(20) +#define N_STI_RST_SEL BIT(16) +#define CORE_RST_SEL BIT(12) +#define PERST_SEL BIT(4) +#define BUTTON_RST_SEL BIT(1) +#define PWUP_RST_SEL BIT(0) + +#define RESET_SELECT_2 0x018 +#define DBI_ARST_SEL BIT(8) +#define SLV_ARST_SEL BIT(4) +#define MSTR_ARST_SEL BIT(0) + +#define EM_CONTROL 0x030 +#define PRE_DET_STT_REG BIT(4) + +#define EM_SELECT 0x034 +#define PRE_DET_STT_SEL BIT(4) + +#define PM_CONTROL_2 0x050 +#define SYS_AUX_PWR_DET BIT(8) + +#define PHY_CONFIG_COM_6 0x114 +#define PIPE_PORT_SEL GENMASK(1, 0) + +#define LINK_MONITOR 0x210 +#define SMLH_LINK_UP BIT(0) + +#define LINK_CAPABILITIES_REG 0x07C +#define PCIE_CAP_MAX_LINK_WIDTH GENMASK(7, 4) +#define PCIE_CAP_MAX_LINK_SPEED GENMASK(3, 0) + +#define LINK_CONTROL_LINK_STATUS_REG 0x080 +#define PCIE_CAP_NEGO_LINK_WIDTH GENMASK(23, 20) +#define PCIE_CAP_LINK_SPEED GENMASK(19, 16) + +#define TYPE1_CLASS_CODE_REV_ID_REG 0x008 +#define BASE_CLASS_CODE 0xFF000000 +#define BASE_CLASS_CODE_VALUE 0x06 +#define SUBCLASS_CODE 0x00FF0000 +#define SUBCLASS_CODE_VALUE 0x04 +#define PROGRAM_INTERFACE 0x0000FF00 +#define PROGRAM_INTERFACE_VALUE 0x00 + +#define GEN2_CONTROL_OFF 0x80c +#define DIRECT_SPEED_CHANGE BIT(17) + +#define MISC_CONTROL_1_OFF 0x8BC +#define DBI_RO_WR_EN BIT(0) + +static void or_writel(void *base, u32 offs, u32 val) +{ + writel(readl(base + offs) | val, base + offs); +} + +static void masked_writel(void *base, u32 offs, u32 mask, u32 val) +{ + u32 data; + int shift = ffs(mask); /* Note that ffs() returns 1 for 0x1 */ + + if (val && shift > 1) + val <<= shift - 1; + + if (mask != ~0) + data = (readl(base + offs) & ~mask) | val; + else + data = val; + + writel(data, base + offs); +} + +static u32 masked_readl(void *base, u32 offs, u32 mask) +{ + u32 data; + int shift = ffs(mask); /* Note that ffs() returns 1 for 0x1 */ + + data = readl(base + offs); + + if (mask != ~0) + data &= mask; + if (shift > 1) + data >>= shift - 1; + + return data; +} + +/* + * Since SynQuacer's PCIe RC is expected to be initialized in the + * firmware (including U-Boot), devicetree doesn't have control + * blocks. + * + * Thus, this will initialize the PCIe RC with fixed addresses. + */ + +#define SYNQUACER_PCI_SEG0_CONFIG_BASE 0x60000000 +#define SYNQUACER_PCI_SEG0_CONFIG_SIZE 0x07f00000 +#define SYNQUACER_PCI_SEG0_DBI_BASE 0x583d0000 +#define SYNQUACER_PCI_SEG0_EXS_BASE 0x58390000 + +#define SYNQUACER_PCI_SEG1_CONFIG_BASE 0x70000000 +#define SYNQUACER_PCI_SEG1_CONFIG_SIZE 0x07f00000 +#define SYNQUACER_PCI_SEG1_DBI_BASE 0x583c0000 +#define SYNQUACER_PCI_SEG1_EXS_BASE 0x58380000 + +#define SIZE_16KB 0x00004000 +#define SIZE_64KB 0x00010000 +#define SIZE_1MB 0x00100000 + +#define SYNQUACER_PCI_DBI_SIZE SIZE_16KB +#define SYNQUACER_PCI_EXS_SIZE SIZE_64KB + +#define NUM_SQ_PCI_RC 2 + +static const struct synquacer_pcie_base { + phys_addr_t cfg_base; + phys_addr_t dbi_base; + phys_addr_t exs_base; +} synquacer_pci_bases[NUM_SQ_PCI_RC] = { + { + .cfg_base = SYNQUACER_PCI_SEG0_CONFIG_BASE, + .dbi_base = SYNQUACER_PCI_SEG0_DBI_BASE, + .exs_base = SYNQUACER_PCI_SEG0_EXS_BASE, + }, { + .cfg_base = SYNQUACER_PCI_SEG1_CONFIG_BASE, + .dbi_base = SYNQUACER_PCI_SEG1_DBI_BASE, + .exs_base = SYNQUACER_PCI_SEG1_EXS_BASE, + }, +}; + +/** + * struct synquacer_ecam_pcie - synquacer_ecam PCIe controller state + * @cfg_base: The base address of memory mapped configuration space + */ +struct synquacer_ecam_pcie { + void *cfg_base; + pci_size_t size; + void *dbi_base; + void *exs_base; + int first_busno; + + struct pci_region mem; + struct pci_region io; + struct pci_region mem64; +}; + +DECLARE_GLOBAL_DATA_PTR; + +/** + * pci_synquacer_ecam_conf_address() - Calculate the address of a config access + * @bus: Pointer to the PCI bus + * @bdf: Identifies the PCIe device to access + * @offset: The offset into the device's configuration space + * @paddress: Pointer to the pointer to write the calculates address to + * + * Calculates the address that should be accessed to perform a PCIe + * configuration space access for a given device identified by the PCIe + * controller device @pcie and the bus, device & function numbers in @bdf. If + * access to the device is not valid then the function will return an error + * code. Otherwise the address to access will be written to the pointer pointed + * to by @paddress. + */ +static int pci_synquacer_ecam_conf_address(const struct udevice *bus, + pci_dev_t bdf, uint offset, + void **paddress) +{ + struct synquacer_ecam_pcie *pcie = dev_get_priv(bus); + void *addr; + + addr = pcie->cfg_base; + addr += (PCI_BUS(bdf) - pcie->first_busno) << 20; + addr += PCI_DEV(bdf) << 15; + addr += PCI_FUNC(bdf) << 12; + addr += offset; + *paddress = addr; + + return 0; +} + +static bool pci_synquacer_ecam_addr_valid(const struct udevice *bus, + pci_dev_t bdf) +{ + struct synquacer_ecam_pcie *pcie = dev_get_priv(bus); + int num_buses = DIV_ROUND_UP(pcie->size, 1 << 16); + + /* + * The Synopsys DesignWare PCIe controller in ECAM mode will not filter + * type 0 config TLPs sent to devices 1 and up on its downstream port, + * resulting in devices appearing multiple times on bus 0 unless we + * filter out those accesses here. + */ + if (PCI_BUS(bdf) == pcie->first_busno && PCI_DEV(bdf) > 0) + return false; + + return (PCI_BUS(bdf) >= pcie->first_busno && + PCI_BUS(bdf) < pcie->first_busno + num_buses); +} + +/** + * pci_synquacer_ecam_read_config() - Read from configuration space + * @bus: Pointer to the PCI bus + * @bdf: Identifies the PCIe device to access + * @offset: The offset into the device's configuration space + * @valuep: A pointer at which to store the read value + * @size: Indicates the size of access to perform + * + * Read a value of size @size from offset @offset within the configuration + * space of the device identified by the bus, device & function numbers in @bdf + * on the PCI bus @bus. + */ +static int pci_synquacer_ecam_read_config(const struct udevice *bus, + pci_dev_t bdf, uint offset, + ulong *valuep, enum pci_size_t size) +{ + if (!pci_synquacer_ecam_addr_valid(bus, bdf)) { + *valuep = pci_get_ff(size); + return 0; + } + + return pci_generic_mmap_read_config(bus, pci_synquacer_ecam_conf_address, + bdf, offset, valuep, size); +} + +/** + * pci_synquacer_ecam_write_config() - Write to configuration space + * @bus: Pointer to the PCI bus + * @bdf: Identifies the PCIe device to access + * @offset: The offset into the device's configuration space + * @value: The value to write + * @size: Indicates the size of access to perform + * + * Write the value @value of size @size from offset @offset within the + * configuration space of the device identified by the bus, device & function + * numbers in @bdf on the PCI bus @bus. + */ +static int pci_synquacer_ecam_write_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong value, + enum pci_size_t size) +{ + if (!pci_synquacer_ecam_addr_valid(bus, bdf)) + return 0; + + return pci_generic_mmap_write_config(bus, pci_synquacer_ecam_conf_address, + bdf, offset, value, size); +} + +/** + * pci_synquacer_ecam_of_to_plat() - Translate from DT to device state + * @dev: A pointer to the device being operated on + * + * Translate relevant data from the device tree pertaining to device @dev into + * state that the driver will later make use of. This state is stored in the + * device's private data structure. + * + * Return: 0 on success, else -EINVAL + */ +static int pci_synquacer_ecam_of_to_plat(struct udevice *dev) +{ + struct synquacer_ecam_pcie *pcie = dev_get_priv(dev); + struct fdt_resource reg_res; + int i, err; + + debug("%s: called for %s\n", __func__, dev->name); + + err = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), "reg", + 0, ®_res); + if (err < 0) { + pr_err("\"reg\" resource not found\n"); + return err; + } + + /* Find the correct pair of the DBI/EXS base address */ + for (i = 0; i < NUM_SQ_PCI_RC; i++) { + if (synquacer_pci_bases[i].cfg_base == reg_res.start) + break; + } + if (i == NUM_SQ_PCI_RC) { + pr_err("Unknown ECAM base address %lx.\n", + (unsigned long)reg_res.start); + return -ENOENT; + } + pcie->dbi_base = map_physmem(synquacer_pci_bases[i].dbi_base, + SYNQUACER_PCI_DBI_SIZE, MAP_NOCACHE); + if (!pcie->dbi_base) { + pr_err("Failed to map DBI for %s\n", dev->name); + return -ENOMEM; + } + + pcie->exs_base = map_physmem(synquacer_pci_bases[i].exs_base, + SYNQUACER_PCI_EXS_SIZE, MAP_NOCACHE); + if (!pcie->exs_base) { + pr_err("Failed to map EXS for %s\n", dev->name); + return -ENOMEM; + } + + pcie->size = fdt_resource_size(®_res); + pcie->cfg_base = map_physmem(reg_res.start, pcie->size, MAP_NOCACHE); + if (!pcie->cfg_base) { + pr_err("Failed to map config space for %s\n", dev->name); + return -ENOMEM; + } + debug("mappings DBI: %p EXS: %p CFG: %p\n", pcie->dbi_base, pcie->exs_base, pcie->cfg_base); + + return 0; +} + +static void pci_synquacer_pre_init(struct synquacer_ecam_pcie *pcie) +{ + void *base = pcie->exs_base; + + masked_writel(base, EM_SELECT, PRE_DET_STT_SEL, 0); + masked_writel(base, EM_CONTROL, PRE_DET_STT_REG, 0); + masked_writel(base, EM_CONTROL, PRE_DET_STT_REG, 1); + + /* 1: Assert all PHY / LINK resets */ + masked_writel(base, RESET_SELECT_1, PERST_SEL, 0); + masked_writel(base, RESET_CONTROL_1, PERST_N_I_REG, 0); + masked_writel(base, RESET_CONTROL_1, PERST_N_O_REG, 0); + + /* Device Reset(PERST#) is effective afrer Set device_type (RC) */ + masked_writel(base, RESET_SELECT_1, PWUP_RST_SEL, 0); + masked_writel(base, RESET_CONTROL_1, PWUP_RST_N_REG, 0); + masked_writel(base, RESET_SELECT_1, BUTTON_RST_SEL, 0); + masked_writel(base, RESET_CONTROL_1, BUTTON_RST_N_REG, 0); + masked_writel(base, RESET_SELECT_1, PWR_RST_SEL, 1); + masked_writel(base, RESET_SELECT_2, MSTR_ARST_SEL, 1); + masked_writel(base, RESET_SELECT_2, SLV_ARST_SEL, 1); + masked_writel(base, RESET_SELECT_2, DBI_ARST_SEL, 1); + masked_writel(base, RESET_SELECT_1, CORE_RST_SEL, 1); + masked_writel(base, RESET_SELECT_1, STI_RST_SEL, 1); + masked_writel(base, RESET_SELECT_1, N_STI_RST_SEL, 1); + masked_writel(base, RESET_SELECT_1, SQU_RST_SEL, 1); + masked_writel(base, RESET_SELECT_1, PHY_RST_SEL, 1); + + /* 2: Set P<n>_app_ltssm_enable='0' for reprogramming before linkup. */ + masked_writel(base, CORE_CONTROL, APP_LTSSM_ENABLE, 0); + + /* 3: Set device_type (RC) */ + masked_writel(base, CORE_CONTROL, DEVICE_TYPE, 4); +} + +static void pci_synquacer_dbi_init(void *dbi_base) +{ + masked_writel(dbi_base, MISC_CONTROL_1_OFF, DBI_RO_WR_EN, 1); + /* 4 Lanes */ + masked_writel(dbi_base, LINK_CAPABILITIES_REG, + PCIE_CAP_MAX_LINK_WIDTH, 4); + /* Gen 2 */ + masked_writel(dbi_base, LINK_CAPABILITIES_REG, + PCIE_CAP_MAX_LINK_SPEED, 2); + + masked_writel(dbi_base, TYPE1_CLASS_CODE_REV_ID_REG, + BASE_CLASS_CODE, BASE_CLASS_CODE_VALUE); + masked_writel(dbi_base, TYPE1_CLASS_CODE_REV_ID_REG, + SUBCLASS_CODE, SUBCLASS_CODE_VALUE); + masked_writel(dbi_base, TYPE1_CLASS_CODE_REV_ID_REG, + PROGRAM_INTERFACE, PROGRAM_INTERFACE_VALUE); + + masked_writel(dbi_base, MISC_CONTROL_1_OFF, DBI_RO_WR_EN, 0); +} + +static void pcie_sq_prog_outbound_atu(void *dbi_base, int index, + u64 cpu_base, u64 pci_base, u64 size, + u32 type, u32 flags) +{ + debug("%s: %p, %d, %llx, %llx, %llx, %x, %x\n", __func__, + dbi_base, index, cpu_base, pci_base, size, type, flags); + + writel(IATU_VIEWPORT_OUTBOUND | IATU_VIEWPORT_REGION_INDEX(index), + dbi_base + IATU_VIEWPORT_OFF); + + writel((u32)(cpu_base & 0xffffffff), + dbi_base + IATU_LWR_BASE_ADDR_OFF_OUTBOUND_0); + writel((u32)(cpu_base >> 32), + dbi_base + IATU_UPPER_BASE_ADDR_OFF_OUTBOUND_0); + writel((u32)(cpu_base + size - 1), + dbi_base + IATU_LIMIT_ADDR_OFF_OUTBOUND_0); + + writel((u32)(pci_base & 0xffffffff), + dbi_base + IATU_LWR_TARGET_ADDR_OFF_OUTBOUND_0); + writel((u32)(pci_base >> 32), + dbi_base + IATU_UPPER_TARGET_ADDR_OFF_OUTBOUND_0); + + writel(type, dbi_base + IATU_REGION_CTRL_1_OFF_OUTBOUND_0); + writel(IATU_REGION_CTRL_2_OFF_OUTBOUND_0_REGION_EN | flags, + dbi_base + IATU_REGION_CTRL_2_OFF_OUTBOUND_0); +} + +static void pci_synquacer_post_init(struct synquacer_ecam_pcie *pcie) +{ + void *base = pcie->exs_base; + + /* + * 4: Set Bifurcation 1=disable 4=able + * 5: Supply Reference (It has executed) + * 6: Wait for 10usec (Reference Clocks is stable) + * 7: De assert PERST# + */ + masked_writel(base, RESET_CONTROL_1, PERST_N_I_REG, 1); + masked_writel(base, RESET_CONTROL_1, PERST_N_O_REG, 1); + + /* 8: Assert SYS_AUX_PWR_DET */ + masked_writel(base, PM_CONTROL_2, SYS_AUX_PWR_DET, 1); + + /* 9: Supply following clocks */ + masked_writel(base, AXI_CLK_STOP, MSTR_CSYSREQ_REG, 1); + masked_writel(base, AXI_CLK_STOP, MSTR_ACLK_STOP, 0); + masked_writel(base, AXI_CLK_STOP, SLV_CSYSREQ_REG, 1); + masked_writel(base, AXI_CLK_STOP, SLV_ACLK_STOP, 0); + masked_writel(base, AXI_CLK_STOP, DBI_CSYSREQ_REG, 1); + masked_writel(base, AXI_CLK_STOP, DBI_ACLK_STOP, 0); + + /* + * 10: De assert PHY reset + * 11: De assert LINK's PMC reset + */ + masked_writel(base, RESET_CONTROL_1, PWUP_RST_N_REG, 1); + masked_writel(base, RESET_CONTROL_1, BUTTON_RST_N_REG, 1); + + /* 12: PHY auto + * 13: Wrapper auto + * 14-17: PHY auto + * 18: Wrapper auto + * 19: Update registers through DBI AXI Slave interface + */ + pci_synquacer_dbi_init(pcie->dbi_base); + + or_writel(pcie->dbi_base, PCI_COMMAND, + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + + /* Force link speed change to Gen2 at link up */ + or_writel(pcie->dbi_base, GEN2_CONTROL_OFF, DIRECT_SPEED_CHANGE); + + /* Region 0: MMIO32 range */ + pcie_sq_prog_outbound_atu(pcie->dbi_base, 0, + pcie->mem.phys_start, + pcie->mem.bus_start, + pcie->mem.size, + IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_MEM | + IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TH, + IATU_REGION_CTRL_2_OFF_OUTBOUND_0_MSG_CODE_32BIT); + + /* Region 1: Type 0 config space */ + pcie_sq_prog_outbound_atu(pcie->dbi_base, 1, + (u64)pcie->cfg_base, + 0, + SIZE_64KB, + IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_CFG0, + IATU_REGION_CTRL_2_OFF_OUTBOUND_0_CFG_SHIFT_MODE); + + /* Region 2: Type 1 config space */ + pcie_sq_prog_outbound_atu(pcie->dbi_base, 2, + (u64)pcie->cfg_base + SIZE_64KB, + 0, + (u64)pcie->io.phys_start - (u64)pcie->cfg_base - SIZE_64KB, + IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_CFG1, + IATU_REGION_CTRL_2_OFF_OUTBOUND_0_CFG_SHIFT_MODE); + + /* Region 3: port I/O range */ + pcie_sq_prog_outbound_atu(pcie->dbi_base, 3, + pcie->io.phys_start, + pcie->io.bus_start, + pcie->io.size, + IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_IO, + 0); + + /* Region 4: MMIO64 range */ + pcie_sq_prog_outbound_atu(pcie->dbi_base, 4, + pcie->mem64.phys_start, + pcie->mem64.bus_start, + pcie->mem64.size, + IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TYPE_MEM | + IATU_REGION_CTRL_1_OFF_OUTBOUND_0_TH, + IATU_REGION_CTRL_2_OFF_OUTBOUND_0_MSG_CODE_32BIT); + + /* enable link */ + if (masked_readl(base, CORE_CONTROL, APP_LTSSM_ENABLE) == 0) + masked_writel(base, CORE_CONTROL, APP_LTSSM_ENABLE, 1); +} + +static int pci_synquacer_ecam_probe(struct udevice *dev) +{ + struct synquacer_ecam_pcie *pcie = dev_get_priv(dev); + struct udevice *ctlr = pci_get_controller(dev); + struct pci_controller *hose = dev_get_uclass_priv(ctlr); + + debug("Probe synquacer pcie for bus %d\n", dev_seq(dev)); + pcie->first_busno = dev_seq(dev); + + /* Store the IO and MEM windows settings for configuring ATU */ + pcie->io.phys_start = hose->regions[0].phys_start; /* IO base */ + pcie->io.bus_start = hose->regions[0].bus_start; /* IO_bus_addr */ + pcie->io.size = hose->regions[0].size; /* IO size */ + + pcie->mem.phys_start = hose->regions[1].phys_start; /* MEM base */ + pcie->mem.bus_start = hose->regions[1].bus_start; /* MEM_bus_addr */ + pcie->mem.size = hose->regions[1].size; /* MEM size */ + + pcie->mem64.phys_start = hose->regions[2].phys_start; /* MEM64 base */ + pcie->mem64.bus_start = hose->regions[2].bus_start; /* MEM64_bus_addr */ + pcie->mem64.size = hose->regions[2].size; /* MEM64 size */ + + pci_synquacer_pre_init(pcie); + + mdelay(150); + + pci_synquacer_post_init(pcie); + + /* It takes a while to stabilize the PCIe bus for scanning */ + mdelay(100); + + return 0; +} + +static const struct dm_pci_ops pci_synquacer_ecam_ops = { + .read_config = pci_synquacer_ecam_read_config, + .write_config = pci_synquacer_ecam_write_config, +}; + +static const struct udevice_id pci_synquacer_ecam_ids[] = { + { .compatible = "socionext,synquacer-pcie-ecam" }, + { } +}; + +U_BOOT_DRIVER(pci_synquacer_ecam) = { + .name = "pci_synquacer_ecam", + .id = UCLASS_PCI, + .of_match = pci_synquacer_ecam_ids, + .ops = &pci_synquacer_ecam_ops, + .probe = pci_synquacer_ecam_probe, + .of_to_plat = pci_synquacer_ecam_of_to_plat, + .priv_auto = sizeof(struct synquacer_ecam_pcie), +}; diff --git a/drivers/pinctrl/mscc/mscc-common.h b/drivers/pinctrl/mscc/mscc-common.h index 3c5c1faf840..49c84a9f410 100644 --- a/drivers/pinctrl/mscc/mscc-common.h +++ b/drivers/pinctrl/mscc/mscc-common.h @@ -61,6 +61,6 @@ int mscc_pinctrl_probe(struct udevice *dev, int num_func, const struct mscc_pin_data *mscc_pins, int num_pins, char * const *function_names, const unsigned long *mscc_gpios); -const struct pinctrl_ops mscc_pinctrl_ops; +extern const struct pinctrl_ops mscc_pinctrl_ops; -const struct dm_gpio_ops mscc_gpio_ops; +extern const struct dm_gpio_ops mscc_gpio_ops; diff --git a/drivers/serial/serial_msm.c b/drivers/serial/serial_msm.c index d8c6c2f6b5f..d8dd5c1104b 100644 --- a/drivers/serial/serial_msm.c +++ b/drivers/serial/serial_msm.c @@ -23,6 +23,7 @@ /* Serial registers - this driver works in uartdm mode*/ #define UARTDM_DMRX 0x34 /* Max RX transfer length */ +#define UARTDM_DMEN 0x3C /* DMA/data-packing mode */ #define UARTDM_NCF_TX 0x40 /* Number of chars to TX */ #define UARTDM_RXFS 0x50 /* RX channel status register */ @@ -197,6 +198,9 @@ static void uart_dm_init(struct msm_serial_data *priv) writel(MSM_BOOT_UART_DM_8_N_1_MODE, priv->base + UARTDM_MR2); writel(MSM_BOOT_UART_DM_CMD_RESET_RX, priv->base + UARTDM_CR); writel(MSM_BOOT_UART_DM_CMD_RESET_TX, priv->base + UARTDM_CR); + + /* Make sure BAM/single character mode is disabled */ + writel(0x0, priv->base + UARTDM_DMEN); } static int msm_serial_probe(struct udevice *dev) { diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index e317d8a2c64..5c2a60a2142 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -488,4 +488,12 @@ config MXC_SPI Enable the MXC SPI controller driver. This driver can be used on various i.MX SoCs such as i.MX31/35/51/6/7. +config SYNQUACER_SPI + bool "Socionext SynQuacer HS-SPI driver" + depends on ARCH_SYNQUACER + help + Enable the Socionext HS-SPI driver for SynQuacer. This driver can + be used to access the SPI interface and SPI NOR flash on platforms + embedding this HS-SPI IP core. + endif # menu "SPI Support" diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 3dc83089b8f..f70851e4bc6 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_EXYNOS_SPI) += exynos_spi.o obj-$(CONFIG_FSL_DSPI) += fsl_dspi.o obj-$(CONFIG_FSL_ESPI) += fsl_espi.o obj-$(CONFIG_FSL_QSPI) += fsl_qspi.o +obj-$(CONFIG_SYNQUACER_SPI) += spi-synquacer.o obj-$(CONFIG_ICH_SPI) += ich.o obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o obj-$(CONFIG_MESON_SPIFC) += meson_spifc.o diff --git a/drivers/spi/spi-synquacer.c b/drivers/spi/spi-synquacer.c new file mode 100644 index 00000000000..ce558c4bc07 --- /dev/null +++ b/drivers/spi/spi-synquacer.c @@ -0,0 +1,491 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * spi-synquacer.c - Socionext Synquacer SPI driver + * Copyright 2021 Linaro Ltd. + * Copyright 2021 Socionext, Inc. + */ + +#include <clk.h> +#include <common.h> +#include <dm.h> +#include <log.h> +#include <time.h> +#include <dm/device_compat.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <spi.h> +#include <wait_bit.h> + +#define MCTRL 0x0 +#define MEN 0 +#define CSEN 1 +#define IPCLK 3 +#define MES 4 +#define SYNCON 5 + +#define PCC0 0x4 +#define PCC(n) (PCC0 + (n) * 4) +#define RTM 3 +#define ACES 2 +#define SAFESYNC 16 +#define CPHA 0 +#define CPOL 1 +#define SSPOL 4 +#define SDIR 7 +#define SS2CD 5 +#define SENDIAN 8 +#define CDRS_SHIFT 9 +#define CDRS_MASK 0x7f + +#define TXF 0x14 +#define TXE 0x18 +#define TXC 0x1c +#define RXF 0x20 +#define RXE 0x24 +#define RXC 0x28 +#define TFLETE 4 +#define RFMTE 5 + +#define FAULTF 0x2c +#define FAULTC 0x30 + +#define DMCFG 0x34 +#define SSDC 1 +#define MSTARTEN 2 + +#define DMSTART 0x38 +#define TRIGGER 0 +#define DMSTOP 8 +#define CS_MASK 3 +#define CS_SHIFT 16 +#define DATA_TXRX 0 +#define DATA_RX 1 +#define DATA_TX 2 +#define DATA_MASK 3 +#define DATA_SHIFT 26 +#define BUS_WIDTH 24 + +#define DMBCC 0x3c +#define DMSTATUS 0x40 +#define RX_DATA_MASK 0x1f +#define RX_DATA_SHIFT 8 +#define TX_DATA_MASK 0x1f +#define TX_DATA_SHIFT 16 + +#define TXBITCNT 0x44 + +#define FIFOCFG 0x4c +#define BPW_MASK 0x3 +#define BPW_SHIFT 8 +#define RX_FLUSH 11 +#define TX_FLUSH 12 +#define RX_TRSHLD_MASK 0xf +#define RX_TRSHLD_SHIFT 0 +#define TX_TRSHLD_MASK 0xf +#define TX_TRSHLD_SHIFT 4 + +#define TXFIFO 0x50 +#define RXFIFO 0x90 +#define MID 0xfc + +#define FIFO_DEPTH 16 +#define TX_TRSHLD 4 +#define RX_TRSHLD (FIFO_DEPTH - TX_TRSHLD) + +#define TXBIT 1 +#define RXBIT 2 + +DECLARE_GLOBAL_DATA_PTR; + +struct synquacer_spi_plat { + void __iomem *base; + bool aces, rtm; +}; + +struct synquacer_spi_priv { + void __iomem *base; + bool aces, rtm; + int speed, cs, mode, rwflag; + void *rx_buf; + const void *tx_buf; + unsigned int tx_words, rx_words; +}; + +static void read_fifo(struct synquacer_spi_priv *priv) +{ + u32 len = readl(priv->base + DMSTATUS); + u8 *buf = priv->rx_buf; + int i; + + len = (len >> RX_DATA_SHIFT) & RX_DATA_MASK; + len = min_t(unsigned int, len, priv->rx_words); + + for (i = 0; i < len; i++) + *buf++ = readb(priv->base + RXFIFO); + + priv->rx_buf = buf; + priv->rx_words -= len; +} + +static void write_fifo(struct synquacer_spi_priv *priv) +{ + u32 len = readl(priv->base + DMSTATUS); + const u8 *buf = priv->tx_buf; + int i; + + len = (len >> TX_DATA_SHIFT) & TX_DATA_MASK; + len = min_t(unsigned int, FIFO_DEPTH - len, priv->tx_words); + + for (i = 0; i < len; i++) + writeb(*buf++, priv->base + TXFIFO); + + priv->tx_buf = buf; + priv->tx_words -= len; +} + +static void synquacer_cs_set(struct synquacer_spi_priv *priv, bool active) +{ + u32 val; + + val = readl(priv->base + DMSTART); + val &= ~(CS_MASK << CS_SHIFT); + val |= priv->cs << CS_SHIFT; + + if (active) { + writel(val, priv->base + DMSTART); + + val = readl(priv->base + DMSTART); + val &= ~BIT(DMSTOP); + writel(val, priv->base + DMSTART); + } else { + val |= BIT(DMSTOP); + writel(val, priv->base + DMSTART); + + if (priv->rx_buf) { + u32 buf[16]; + + priv->rx_buf = buf; + priv->rx_words = 16; + read_fifo(priv); + } + } +} + +static void synquacer_spi_config(struct udevice *dev, void *rx, const void *tx) +{ + struct udevice *bus = dev->parent; + struct synquacer_spi_priv *priv = dev_get_priv(bus); + struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); + u32 val, div, bus_width; + int rwflag; + + rwflag = (rx ? 1 : 0) | (tx ? 2 : 0); + + /* if nothing to do */ + if (slave_plat->mode == priv->mode && + rwflag == priv->rwflag && + slave_plat->cs == priv->cs && + slave_plat->max_hz == priv->speed) + return; + + priv->rwflag = rwflag; + priv->cs = slave_plat->cs; + priv->mode = slave_plat->mode; + priv->speed = slave_plat->max_hz; + + if (priv->mode & SPI_TX_BYTE) + bus_width = 1; + else if (priv->mode & SPI_TX_DUAL) + bus_width = 2; + else if (priv->mode & SPI_TX_QUAD) + bus_width = 4; + else if (priv->mode & SPI_TX_OCTAL) + bus_width = 8; + + div = DIV_ROUND_UP(125000000, priv->speed); + + val = readl(priv->base + PCC(priv->cs)); + val &= ~BIT(RTM); + val &= ~BIT(ACES); + val &= ~BIT(SAFESYNC); + if ((priv->mode & (SPI_TX_DUAL | SPI_RX_DUAL)) && div < 3) + val |= BIT(SAFESYNC); + if ((priv->mode & (SPI_TX_QUAD | SPI_RX_QUAD)) && div < 6) + val |= BIT(SAFESYNC); + + if (priv->mode & SPI_CPHA) + val |= BIT(CPHA); + else + val &= ~BIT(CPHA); + + if (priv->mode & SPI_CPOL) + val |= BIT(CPOL); + else + val &= ~BIT(CPOL); + + if (priv->mode & SPI_CS_HIGH) + val |= BIT(SSPOL); + else + val &= ~BIT(SSPOL); + + if (priv->mode & SPI_LSB_FIRST) + val |= BIT(SDIR); + else + val &= ~BIT(SDIR); + + if (priv->aces) + val |= BIT(ACES); + + if (priv->rtm) + val |= BIT(RTM); + + val |= (3 << SS2CD); + val |= BIT(SENDIAN); + + val &= ~(CDRS_MASK << CDRS_SHIFT); + val |= ((div >> 1) << CDRS_SHIFT); + + writel(val, priv->base + PCC(priv->cs)); + + val = readl(priv->base + FIFOCFG); + val &= ~(BPW_MASK << BPW_SHIFT); + val |= (0 << BPW_SHIFT); + writel(val, priv->base + FIFOCFG); + + val = readl(priv->base + DMSTART); + val &= ~(DATA_MASK << DATA_SHIFT); + + if (tx && rx) + val |= (DATA_TXRX << DATA_SHIFT); + else if (rx) + val |= (DATA_RX << DATA_SHIFT); + else + val |= (DATA_TX << DATA_SHIFT); + + val &= ~(3 << BUS_WIDTH); + val |= ((bus_width >> 1) << BUS_WIDTH); + writel(val, priv->base + DMSTART); +} + +static int synquacer_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *tx_buf, void *rx_buf, + unsigned long flags) +{ + struct udevice *bus = dev->parent; + struct synquacer_spi_priv *priv = dev_get_priv(bus); + u32 val, words, busy; + + val = readl(priv->base + FIFOCFG); + val |= (1 << RX_FLUSH); + val |= (1 << TX_FLUSH); + writel(val, priv->base + FIFOCFG); + + synquacer_spi_config(dev, rx_buf, tx_buf); + + priv->tx_buf = tx_buf; + priv->rx_buf = rx_buf; + + words = bitlen / 8; + + if (tx_buf) { + busy |= BIT(TXBIT); + priv->tx_words = words; + } else { + busy &= ~BIT(TXBIT); + priv->tx_words = 0; + } + + if (rx_buf) { + busy |= BIT(RXBIT); + priv->rx_words = words; + } else { + busy &= ~BIT(RXBIT); + priv->rx_words = 0; + } + + if (flags & SPI_XFER_BEGIN) + synquacer_cs_set(priv, true); + + if (tx_buf) + write_fifo(priv); + + if (rx_buf) { + val = readl(priv->base + FIFOCFG); + val &= ~(RX_TRSHLD_MASK << RX_TRSHLD_SHIFT); + val |= ((priv->rx_words > FIFO_DEPTH ? + RX_TRSHLD : priv->rx_words) << RX_TRSHLD_SHIFT); + writel(val, priv->base + FIFOCFG); + } + + writel(~0, priv->base + TXC); + writel(~0, priv->base + RXC); + + /* Trigger */ + val = readl(priv->base + DMSTART); + val |= BIT(TRIGGER); + writel(val, priv->base + DMSTART); + + while (busy & (BIT(RXBIT) | BIT(TXBIT))) { + if (priv->rx_words) + read_fifo(priv); + else + busy &= ~BIT(RXBIT); + + if (priv->tx_words) { + write_fifo(priv); + } else { + u32 len; + + do { /* wait for shifter to empty out */ + cpu_relax(); + len = readl(priv->base + DMSTATUS); + len = (len >> TX_DATA_SHIFT) & TX_DATA_MASK; + } while (tx_buf && len); + busy &= ~BIT(TXBIT); + } + } + + if (flags & SPI_XFER_END) + synquacer_cs_set(priv, false); + + return 0; +} + +static int synquacer_spi_set_speed(struct udevice *bus, uint speed) +{ + return 0; +} + +static int synquacer_spi_set_mode(struct udevice *bus, uint mode) +{ + return 0; +} + +static int synquacer_spi_claim_bus(struct udevice *dev) +{ + return 0; +} + +static int synquacer_spi_release_bus(struct udevice *dev) +{ + return 0; +} + +static void synquacer_spi_disable_module(struct synquacer_spi_priv *priv) +{ + writel(0, priv->base + MCTRL); + while (readl(priv->base + MCTRL) & BIT(MES)) + cpu_relax(); +} + +static void synquacer_spi_init(struct synquacer_spi_priv *priv) +{ + u32 val; + + synquacer_spi_disable_module(priv); + + writel(0, priv->base + TXE); + writel(0, priv->base + RXE); + val = readl(priv->base + TXF); + writel(val, priv->base + TXC); + val = readl(priv->base + RXF); + writel(val, priv->base + RXC); + val = readl(priv->base + FAULTF); + writel(val, priv->base + FAULTC); + + val = readl(priv->base + DMCFG); + val &= ~BIT(SSDC); + val &= ~BIT(MSTARTEN); + writel(val, priv->base + DMCFG); + + /* Enable module with direct mode */ + val = readl(priv->base + MCTRL); + val &= ~BIT(IPCLK); + val &= ~BIT(CSEN); + val |= BIT(MEN); + val |= BIT(SYNCON); + writel(val, priv->base + MCTRL); +} + +static void synquacer_spi_exit(struct synquacer_spi_priv *priv) +{ + u32 val; + + synquacer_spi_disable_module(priv); + + /* Enable module with command sequence mode */ + val = readl(priv->base + MCTRL); + val &= ~BIT(IPCLK); + val |= BIT(CSEN); + val |= BIT(MEN); + val |= BIT(SYNCON); + writel(val, priv->base + MCTRL); + + while (!(readl(priv->base + MCTRL) & BIT(MES))) + cpu_relax(); +} + +static int synquacer_spi_probe(struct udevice *bus) +{ + struct synquacer_spi_plat *plat = dev_get_plat(bus); + struct synquacer_spi_priv *priv = dev_get_priv(bus); + + priv->base = plat->base; + priv->aces = plat->aces; + priv->rtm = plat->rtm; + + synquacer_spi_init(priv); + return 0; +} + +static int synquacer_spi_remove(struct udevice *bus) +{ + struct synquacer_spi_priv *priv = dev_get_priv(bus); + + synquacer_spi_exit(priv); + return 0; +} + +static int synquacer_spi_of_to_plat(struct udevice *bus) +{ + struct synquacer_spi_plat *plat = dev_get_plat(bus); + struct clk clk; + + plat->base = dev_read_addr_ptr(bus); + + plat->aces = dev_read_bool(bus, "socionext,set-aces"); + plat->rtm = dev_read_bool(bus, "socionext,use-rtm"); + + clk_get_by_name(bus, "iHCLK", &clk); + clk_enable(&clk); + + return 0; +} + +static const struct dm_spi_ops synquacer_spi_ops = { + .claim_bus = synquacer_spi_claim_bus, + .release_bus = synquacer_spi_release_bus, + .xfer = synquacer_spi_xfer, + .set_speed = synquacer_spi_set_speed, + .set_mode = synquacer_spi_set_mode, +}; + +static const struct udevice_id synquacer_spi_ids[] = { + { .compatible = "socionext,synquacer-spi" }, + { /* Sentinel */ } +}; + +U_BOOT_DRIVER(synquacer_spi) = { + .name = "synquacer_spi", + .id = UCLASS_SPI, + .of_match = synquacer_spi_ids, + .ops = &synquacer_spi_ops, + .of_to_plat = synquacer_spi_of_to_plat, + .plat_auto = sizeof(struct synquacer_spi_plat), + .priv_auto = sizeof(struct synquacer_spi_priv), + .probe = synquacer_spi_probe, + .flags = DM_FLAG_OS_PREPARE, + .remove = synquacer_spi_remove, +}; diff --git a/drivers/w1/w1-gpio.c b/drivers/w1/w1-gpio.c index 3b0ead6f6dc..9346f810ce1 100644 --- a/drivers/w1/w1-gpio.c +++ b/drivers/w1/w1-gpio.c @@ -156,7 +156,7 @@ static int w1_gpio_of_to_plat(struct udevice *dev) struct w1_gpio_pdata *pdata = dev_get_plat(dev); int ret; - ret = gpio_request_by_name(dev, "gpios", 0, &pdata->gpio, 0); + ret = gpio_request_by_name(dev, "gpios", 0, &pdata->gpio, GPIOD_IS_IN); if (ret < 0) printf("Error claiming GPIO %d\n", ret); |