mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-09-27 23:20:26 +09:00
Xilinx changes for v2021.04-rc3
qspi: - Support for dual/quad mode - Fix speed handling clk: - Add clock enable function for zynq/zynqmp/versal gem: - Enable clock for Versal - Fix error path - Fix mdio deregistration path fpga: - Fix buffer alignment for ZynqMP xilinx: - Fix reset reason clearing in ZynqMP - Show silicon version in SPL for Zynq/ZynqMP - Fix DTB selection for ZynqMP - Rename zc1275 to zcu1275 to match DT name -----BEGIN PGP SIGNATURE----- iF0EABECAB0WIQQbPNTMvXmYlBPRwx7KSWXLKUoMIQUCYDUezQAKCRDKSWXLKUoM IbtgAJ9jZ+BOtwFaHR19TENC2DsHTINnnwCfSDn3fU0OFJRI0HD7pRxXr4xrb3M= =Kr8x -----END PGP SIGNATURE----- Merge tag 'xilinx-for-v2021.04-rc3' of https://gitlab.denx.de/u-boot/custodians/u-boot-microblaze Xilinx changes for v2021.04-rc3 qspi: - Support for dual/quad mode - Fix speed handling clk: - Add clock enable function for zynq/zynqmp/versal gem: - Enable clock for Versal - Fix error path - Fix mdio deregistration path fpga: - Fix buffer alignment for ZynqMP xilinx: - Fix reset reason clearing in ZynqMP - Show silicon version in SPL for Zynq/ZynqMP - Fix DTB selection for ZynqMP - Rename zc1275 to zcu1275 to match DT name
This commit is contained in:
commit
cbe607b920
@ -128,8 +128,8 @@ struct apu_regs {
|
|||||||
|
|
||||||
#define ZYNQMP_CSU_VERSION_EMPTY_SHIFT 20
|
#define ZYNQMP_CSU_VERSION_EMPTY_SHIFT 20
|
||||||
|
|
||||||
#define ZYNQMP_SILICON_VER_MASK 0xF000
|
#define ZYNQMP_SILICON_VER_MASK 0xF
|
||||||
#define ZYNQMP_SILICON_VER_SHIFT 12
|
#define ZYNQMP_SILICON_VER_SHIFT 0
|
||||||
|
|
||||||
struct csu_regs {
|
struct csu_regs {
|
||||||
u32 reserved0[4];
|
u32 reserved0[4];
|
||||||
|
@ -327,7 +327,7 @@ void *board_fdt_blob_setup(void)
|
|||||||
|
|
||||||
if (!IS_ENABLED(CONFIG_SPL_BUILD) &&
|
if (!IS_ENABLED(CONFIG_SPL_BUILD) &&
|
||||||
!IS_ENABLED(CONFIG_VERSAL_NO_DDR) &&
|
!IS_ENABLED(CONFIG_VERSAL_NO_DDR) &&
|
||||||
!IS_ENABLED(CONFIG_VERSAL_NO_DDR)) {
|
!IS_ENABLED(CONFIG_ZYNQMP_NO_DDR)) {
|
||||||
fdt_blob = (void *)CONFIG_XILINX_OF_BOARD_DTB_ADDR;
|
fdt_blob = (void *)CONFIG_XILINX_OF_BOARD_DTB_ADDR;
|
||||||
|
|
||||||
if (fdt_magic(fdt_blob) == FDT_MAGIC)
|
if (fdt_magic(fdt_blob) == FDT_MAGIC)
|
||||||
|
@ -25,6 +25,9 @@ DECLARE_GLOBAL_DATA_PTR;
|
|||||||
|
|
||||||
int board_init(void)
|
int board_init(void)
|
||||||
{
|
{
|
||||||
|
if (IS_ENABLED(CONFIG_SPL_BUILD))
|
||||||
|
printf("Silicon version:\t%d\n", zynq_get_silicon_version());
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,6 +329,7 @@ int board_init(void)
|
|||||||
if (sizeof(CONFIG_ZYNQMP_SPL_PM_CFG_OBJ_FILE) > 1)
|
if (sizeof(CONFIG_ZYNQMP_SPL_PM_CFG_OBJ_FILE) > 1)
|
||||||
zynqmp_pmufw_load_config_object(zynqmp_pm_cfg_obj,
|
zynqmp_pmufw_load_config_object(zynqmp_pm_cfg_obj,
|
||||||
zynqmp_pm_cfg_obj_size);
|
zynqmp_pm_cfg_obj_size);
|
||||||
|
printf("Silicon version:\t%d\n", zynqmp_get_silicon_version());
|
||||||
#else
|
#else
|
||||||
if (CONFIG_IS_ENABLED(DM_I2C) && CONFIG_IS_ENABLED(I2C_EEPROM))
|
if (CONFIG_IS_ENABLED(DM_I2C) && CONFIG_IS_ENABLED(I2C_EEPROM))
|
||||||
xilinx_read_eeprom();
|
xilinx_read_eeprom();
|
||||||
@ -496,11 +497,7 @@ static int reset_reason(void)
|
|||||||
|
|
||||||
env_set("reset_reason", reason);
|
env_set("reset_reason", reason);
|
||||||
|
|
||||||
ret = zynqmp_mmio_write((ulong)&crlapb_base->reset_reason, ~0, ~0);
|
return 0;
|
||||||
if (ret)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_fdtfile(void)
|
static int set_fdtfile(void)
|
||||||
|
@ -718,9 +718,20 @@ static ulong versal_clk_set_rate(struct clk *clk, ulong rate)
|
|||||||
return clk_rate;
|
return clk_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int versal_clk_enable(struct clk *clk)
|
||||||
|
{
|
||||||
|
struct versal_clk_priv *priv = dev_get_priv(clk->dev);
|
||||||
|
u32 clk_id;
|
||||||
|
|
||||||
|
clk_id = priv->clk[clk->id].clk_id;
|
||||||
|
|
||||||
|
return xilinx_pm_request(PM_CLOCK_ENABLE, clk_id, 0, 0, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static struct clk_ops versal_clk_ops = {
|
static struct clk_ops versal_clk_ops = {
|
||||||
.set_rate = versal_clk_set_rate,
|
.set_rate = versal_clk_set_rate,
|
||||||
.get_rate = versal_clk_get_rate,
|
.get_rate = versal_clk_get_rate,
|
||||||
|
.enable = versal_clk_enable,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct udevice_id versal_clk_ids[] = {
|
static const struct udevice_id versal_clk_ids[] = {
|
||||||
|
@ -445,11 +445,21 @@ static ulong zynq_clk_get_rate(struct clk *clk)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int dummy_enable(struct clk *clk)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Add implementation but by default all clocks are enabled
|
||||||
|
* after power up which is only one supported case now.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct clk_ops zynq_clk_ops = {
|
static struct clk_ops zynq_clk_ops = {
|
||||||
.get_rate = zynq_clk_get_rate,
|
.get_rate = zynq_clk_get_rate,
|
||||||
#ifndef CONFIG_SPL_BUILD
|
#ifndef CONFIG_SPL_BUILD
|
||||||
.set_rate = zynq_clk_set_rate,
|
.set_rate = zynq_clk_set_rate,
|
||||||
#endif
|
#endif
|
||||||
|
.enable = dummy_enable,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int zynq_clk_probe(struct udevice *dev)
|
static int zynq_clk_probe(struct udevice *dev)
|
||||||
|
@ -199,6 +199,8 @@ static u32 zynqmp_clk_get_register(enum zynqmp_clk id)
|
|||||||
return CRF_APB_DDR_CTRL;
|
return CRF_APB_DDR_CTRL;
|
||||||
case qspi_ref:
|
case qspi_ref:
|
||||||
return CRL_APB_QSPI_REF_CTRL;
|
return CRL_APB_QSPI_REF_CTRL;
|
||||||
|
case usb3_dual_ref:
|
||||||
|
return CRL_APB_USB3_DUAL_REF_CTRL;
|
||||||
case gem0_ref:
|
case gem0_ref:
|
||||||
return CRL_APB_GEM0_REF_CTRL;
|
return CRL_APB_GEM0_REF_CTRL;
|
||||||
case gem1_ref:
|
case gem1_ref:
|
||||||
@ -207,6 +209,10 @@ static u32 zynqmp_clk_get_register(enum zynqmp_clk id)
|
|||||||
return CRL_APB_GEM2_REF_CTRL;
|
return CRL_APB_GEM2_REF_CTRL;
|
||||||
case gem3_ref:
|
case gem3_ref:
|
||||||
return CRL_APB_GEM3_REF_CTRL;
|
return CRL_APB_GEM3_REF_CTRL;
|
||||||
|
case usb0_bus_ref:
|
||||||
|
return CRL_APB_USB0_BUS_REF_CTRL;
|
||||||
|
case usb1_bus_ref:
|
||||||
|
return CRL_APB_USB1_BUS_REF_CTRL;
|
||||||
case uart0_ref:
|
case uart0_ref:
|
||||||
return CRL_APB_UART0_REF_CTRL;
|
return CRL_APB_UART0_REF_CTRL;
|
||||||
case uart1_ref:
|
case uart1_ref:
|
||||||
@ -699,9 +705,52 @@ static int zynqmp_clk_probe(struct udevice *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int zynqmp_clk_enable(struct clk *clk)
|
||||||
|
{
|
||||||
|
enum zynqmp_clk id = clk->id;
|
||||||
|
u32 reg, clk_ctrl, clkact_shift, mask;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
reg = zynqmp_clk_get_register(id);
|
||||||
|
debug("%s, clk_id:%x, clk_base:0x%x\n", __func__, id, reg);
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case usb0_bus_ref ... usb1:
|
||||||
|
clkact_shift = 25;
|
||||||
|
mask = 0x1;
|
||||||
|
break;
|
||||||
|
case gem0_ref ... gem3_ref:
|
||||||
|
clkact_shift = 25;
|
||||||
|
mask = 0x3;
|
||||||
|
break;
|
||||||
|
case qspi_ref ... can1_ref:
|
||||||
|
clkact_shift = 24;
|
||||||
|
mask = 0x1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = zynqmp_mmio_read(reg, &clk_ctrl);
|
||||||
|
if (ret) {
|
||||||
|
printf("%s mio read fail\n", __func__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
clk_ctrl |= (mask << clkact_shift);
|
||||||
|
ret = zynqmp_mmio_write(reg, mask << clkact_shift, clk_ctrl);
|
||||||
|
if (ret) {
|
||||||
|
printf("%s mio write fail\n", __func__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static struct clk_ops zynqmp_clk_ops = {
|
static struct clk_ops zynqmp_clk_ops = {
|
||||||
.set_rate = zynqmp_clk_set_rate,
|
.set_rate = zynqmp_clk_set_rate,
|
||||||
.get_rate = zynqmp_clk_get_rate,
|
.get_rate = zynqmp_clk_get_rate,
|
||||||
|
.enable = zynqmp_clk_enable,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct udevice_id zynqmp_clk_ids[] = {
|
static const struct udevice_id zynqmp_clk_ids[] = {
|
||||||
|
@ -315,7 +315,7 @@ static u32 *zynq_align_dma_buffer(u32 *buf, u32 len, u32 swap)
|
|||||||
if (new_buf > buf) {
|
if (new_buf > buf) {
|
||||||
debug("%s: Aligned buffer is after buffer start\n",
|
debug("%s: Aligned buffer is after buffer start\n",
|
||||||
__func__);
|
__func__);
|
||||||
new_buf -= ARCH_DMA_MINALIGN;
|
new_buf = (u32 *)((u32)new_buf - ARCH_DMA_MINALIGN);
|
||||||
}
|
}
|
||||||
printf("%s: Align buffer at %x to %x(swap %d)\n", __func__,
|
printf("%s: Align buffer at %x to %x(swap %d)\n", __func__,
|
||||||
(u32)buf, (u32)new_buf, swap);
|
(u32)buf, (u32)new_buf, swap);
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
|
#include <dm/device_compat.h>
|
||||||
#include <dm/root.h>
|
#include <dm/root.h>
|
||||||
#include <i2c.h>
|
#include <i2c.h>
|
||||||
#include <fdtdec.h>
|
#include <fdtdec.h>
|
||||||
@ -481,6 +482,12 @@ static int cdns_i2c_of_to_plat(struct udevice *dev)
|
|||||||
|
|
||||||
i2c_bus->input_freq = clk_get_rate(&clk);
|
i2c_bus->input_freq = clk_get_rate(&clk);
|
||||||
|
|
||||||
|
ret = clk_enable(&clk);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "failed to enable clock\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,7 +577,7 @@ static int arasan_sdhci_probe(struct udevice *dev)
|
|||||||
debug("%s: CLK %ld\n", __func__, clock);
|
debug("%s: CLK %ld\n", __func__, clock);
|
||||||
|
|
||||||
ret = clk_enable(&clk);
|
ret = clk_enable(&clk);
|
||||||
if (ret && ret != -ENOSYS) {
|
if (ret) {
|
||||||
dev_err(dev, "failed to enable clock\n");
|
dev_err(dev, "failed to enable clock\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,8 @@
|
|||||||
#define ZYNQ_GEM_FREQUENCY_100 25000000UL
|
#define ZYNQ_GEM_FREQUENCY_100 25000000UL
|
||||||
#define ZYNQ_GEM_FREQUENCY_1000 125000000UL
|
#define ZYNQ_GEM_FREQUENCY_1000 125000000UL
|
||||||
|
|
||||||
|
#define RXCLK_EN BIT(0)
|
||||||
|
|
||||||
/* Device registers */
|
/* Device registers */
|
||||||
struct zynq_gem_regs {
|
struct zynq_gem_regs {
|
||||||
u32 nwctrl; /* 0x0 - Network Control reg */
|
u32 nwctrl; /* 0x0 - Network Control reg */
|
||||||
@ -205,10 +207,12 @@ struct zynq_gem_priv {
|
|||||||
struct phy_device *phydev;
|
struct phy_device *phydev;
|
||||||
ofnode phy_of_node;
|
ofnode phy_of_node;
|
||||||
struct mii_dev *bus;
|
struct mii_dev *bus;
|
||||||
struct clk clk;
|
struct clk rx_clk;
|
||||||
|
struct clk tx_clk;
|
||||||
u32 max_speed;
|
u32 max_speed;
|
||||||
bool int_pcs;
|
bool int_pcs;
|
||||||
bool dma_64bit;
|
bool dma_64bit;
|
||||||
|
u32 clk_en_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int phy_setup_op(struct zynq_gem_priv *priv, u32 phy_addr, u32 regnum,
|
static int phy_setup_op(struct zynq_gem_priv *priv, u32 phy_addr, u32 regnum,
|
||||||
@ -476,18 +480,25 @@ static int zynq_gem_init(struct udevice *dev)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = clk_set_rate(&priv->clk, clk_rate);
|
ret = clk_set_rate(&priv->tx_clk, clk_rate);
|
||||||
if (IS_ERR_VALUE(ret) && ret != (unsigned long)-ENOSYS) {
|
if (IS_ERR_VALUE(ret)) {
|
||||||
dev_err(dev, "failed to set tx clock rate\n");
|
dev_err(dev, "failed to set tx clock rate\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = clk_enable(&priv->clk);
|
ret = clk_enable(&priv->tx_clk);
|
||||||
if (ret && ret != -ENOSYS) {
|
if (ret) {
|
||||||
dev_err(dev, "failed to enable tx clock\n");
|
dev_err(dev, "failed to enable tx clock\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (priv->clk_en_info & RXCLK_EN) {
|
||||||
|
ret = clk_enable(&priv->rx_clk);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "failed to enable rx clock\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK |
|
setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK |
|
||||||
ZYNQ_GEM_NWCTRL_TXEN_MASK);
|
ZYNQ_GEM_NWCTRL_TXEN_MASK);
|
||||||
|
|
||||||
@ -694,10 +705,18 @@ static int zynq_gem_probe(struct udevice *dev)
|
|||||||
priv->tx_bd = (struct emac_bd *)bd_space;
|
priv->tx_bd = (struct emac_bd *)bd_space;
|
||||||
priv->rx_bd = (struct emac_bd *)((ulong)bd_space + BD_SEPRN_SPACE);
|
priv->rx_bd = (struct emac_bd *)((ulong)bd_space + BD_SEPRN_SPACE);
|
||||||
|
|
||||||
ret = clk_get_by_name(dev, "tx_clk", &priv->clk);
|
ret = clk_get_by_name(dev, "tx_clk", &priv->tx_clk);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(dev, "failed to get clock\n");
|
dev_err(dev, "failed to get tx_clock\n");
|
||||||
goto err1;
|
goto err2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->clk_en_info & RXCLK_EN) {
|
||||||
|
ret = clk_get_by_name(dev, "rx_clk", &priv->rx_clk);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(dev, "failed to get rx_clock\n");
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->bus = mdio_alloc();
|
priv->bus = mdio_alloc();
|
||||||
@ -711,14 +730,16 @@ static int zynq_gem_probe(struct udevice *dev)
|
|||||||
|
|
||||||
ret = zynq_phy_init(dev);
|
ret = zynq_phy_init(dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err2;
|
goto err3;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
err3:
|
||||||
|
mdio_unregister(priv->bus);
|
||||||
err2:
|
err2:
|
||||||
free(priv->rxbuffers);
|
|
||||||
err1:
|
|
||||||
free(priv->tx_bd);
|
free(priv->tx_bd);
|
||||||
|
err1:
|
||||||
|
free(priv->rxbuffers);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -792,11 +813,13 @@ static int zynq_gem_of_to_plat(struct udevice *dev)
|
|||||||
(ulong)priv->iobase, (ulong)priv->mdiobase, priv->phyaddr,
|
(ulong)priv->iobase, (ulong)priv->mdiobase, priv->phyaddr,
|
||||||
phy_string_for_interface(priv->interface));
|
phy_string_for_interface(priv->interface));
|
||||||
|
|
||||||
|
priv->clk_en_info = dev_get_driver_data(dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct udevice_id zynq_gem_ids[] = {
|
static const struct udevice_id zynq_gem_ids[] = {
|
||||||
{ .compatible = "cdns,versal-gem" },
|
{ .compatible = "cdns,versal-gem", .data = RXCLK_EN },
|
||||||
{ .compatible = "cdns,zynqmp-gem" },
|
{ .compatible = "cdns,zynqmp-gem" },
|
||||||
{ .compatible = "cdns,zynq-gem" },
|
{ .compatible = "cdns,zynq-gem" },
|
||||||
{ .compatible = "cdns,gem" },
|
{ .compatible = "cdns,gem" },
|
||||||
|
@ -127,7 +127,7 @@ static int zynq_serial_setbrg(struct udevice *dev, int baudrate)
|
|||||||
debug("%s: CLK %ld\n", __func__, clock);
|
debug("%s: CLK %ld\n", __func__, clock);
|
||||||
|
|
||||||
ret = clk_enable(&clk);
|
ret = clk_enable(&clk);
|
||||||
if (ret && ret != -ENOSYS) {
|
if (ret) {
|
||||||
dev_err(dev, "failed to enable clock\n");
|
dev_err(dev, "failed to enable clock\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -194,7 +194,7 @@ static int zynq_qspi_probe(struct udevice *bus)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = clk_enable(&clk);
|
ret = clk_enable(&clk);
|
||||||
if (ret && ret != -ENOSYS) {
|
if (ret) {
|
||||||
dev_err(bus, "failed to enable clock\n");
|
dev_err(bus, "failed to enable clock\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ static int zynq_spi_probe(struct udevice *bus)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = clk_enable(&clk);
|
ret = clk_enable(&clk);
|
||||||
if (ret && ret != -ENOSYS) {
|
if (ret) {
|
||||||
dev_err(bus, "failed to enable clock\n");
|
dev_err(bus, "failed to enable clock\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <memalign.h>
|
#include <memalign.h>
|
||||||
#include <spi.h>
|
#include <spi.h>
|
||||||
|
#include <spi-mem.h>
|
||||||
#include <ubi_uboot.h>
|
#include <ubi_uboot.h>
|
||||||
#include <wait_bit.h>
|
#include <wait_bit.h>
|
||||||
#include <dm/device_compat.h>
|
#include <dm/device_compat.h>
|
||||||
@ -172,8 +173,7 @@ struct zynqmp_qspi_priv {
|
|||||||
unsigned int len;
|
unsigned int len;
|
||||||
int bytes_to_transfer;
|
int bytes_to_transfer;
|
||||||
int bytes_to_receive;
|
int bytes_to_receive;
|
||||||
unsigned int is_inst;
|
const struct spi_mem_op *op;
|
||||||
unsigned int cs_change:1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int zynqmp_qspi_of_to_plat(struct udevice *bus)
|
static int zynqmp_qspi_of_to_plat(struct udevice *bus)
|
||||||
@ -222,6 +222,21 @@ static u32 zynqmp_qspi_bus_select(struct zynqmp_qspi_priv *priv)
|
|||||||
return gqspi_fifo_reg;
|
return gqspi_fifo_reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 zynqmp_qspi_genfifo_mode(u8 buswidth)
|
||||||
|
{
|
||||||
|
switch (buswidth) {
|
||||||
|
case 1:
|
||||||
|
return GQSPI_SPI_MODE_SPI;
|
||||||
|
case 2:
|
||||||
|
return GQSPI_SPI_MODE_DUAL_SPI;
|
||||||
|
case 4:
|
||||||
|
return GQSPI_SPI_MODE_QSPI;
|
||||||
|
default:
|
||||||
|
debug("Unsupported bus width %u\n", buswidth);
|
||||||
|
return GQSPI_SPI_MODE_SPI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void zynqmp_qspi_fill_gen_fifo(struct zynqmp_qspi_priv *priv,
|
static void zynqmp_qspi_fill_gen_fifo(struct zynqmp_qspi_priv *priv,
|
||||||
u32 gqspi_fifo_reg)
|
u32 gqspi_fifo_reg)
|
||||||
{
|
{
|
||||||
@ -306,12 +321,9 @@ static int zynqmp_qspi_set_speed(struct udevice *bus, uint speed)
|
|||||||
if (speed > plat->frequency)
|
if (speed > plat->frequency)
|
||||||
speed = plat->frequency;
|
speed = plat->frequency;
|
||||||
|
|
||||||
|
if (plat->speed_hz != speed) {
|
||||||
/* Set the clock frequency */
|
/* Set the clock frequency */
|
||||||
confr = readl(®s->confr);
|
/* If speed == 0, default to lowest speed */
|
||||||
if (speed == 0) {
|
|
||||||
/* Set baudrate x8, if the freq is 0 */
|
|
||||||
baud_rate_val = GQSPI_DFLT_BAUD_RATE_VAL;
|
|
||||||
} else if (plat->speed_hz != speed) {
|
|
||||||
while ((baud_rate_val < 8) &&
|
while ((baud_rate_val < 8) &&
|
||||||
((plat->frequency /
|
((plat->frequency /
|
||||||
(2 << baud_rate_val)) > speed))
|
(2 << baud_rate_val)) > speed))
|
||||||
@ -321,13 +333,15 @@ static int zynqmp_qspi_set_speed(struct udevice *bus, uint speed)
|
|||||||
baud_rate_val = GQSPI_DFLT_BAUD_RATE_VAL;
|
baud_rate_val = GQSPI_DFLT_BAUD_RATE_VAL;
|
||||||
|
|
||||||
plat->speed_hz = plat->frequency / (2 << baud_rate_val);
|
plat->speed_hz = plat->frequency / (2 << baud_rate_val);
|
||||||
}
|
|
||||||
|
confr = readl(®s->confr);
|
||||||
confr &= ~GQSPI_BAUD_DIV_MASK;
|
confr &= ~GQSPI_BAUD_DIV_MASK;
|
||||||
confr |= (baud_rate_val << 3);
|
confr |= (baud_rate_val << 3);
|
||||||
writel(confr, ®s->confr);
|
writel(confr, ®s->confr);
|
||||||
|
|
||||||
zynqmp_qspi_set_tapdelay(bus, baud_rate_val);
|
zynqmp_qspi_set_tapdelay(bus, baud_rate_val);
|
||||||
|
|
||||||
debug("regs=%p, speed=%d\n", priv->regs, plat->speed_hz);
|
debug("regs=%p, speed=%d\n", priv->regs, plat->speed_hz);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -359,7 +373,7 @@ static int zynqmp_qspi_probe(struct udevice *bus)
|
|||||||
debug("%s: CLK %ld\n", __func__, clock);
|
debug("%s: CLK %ld\n", __func__, clock);
|
||||||
|
|
||||||
ret = clk_enable(&clk);
|
ret = clk_enable(&clk);
|
||||||
if (ret && ret != -ENOSYS) {
|
if (ret) {
|
||||||
dev_err(bus, "failed to enable clock\n");
|
dev_err(bus, "failed to enable clock\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -446,21 +460,42 @@ static int zynqmp_qspi_fill_tx_fifo(struct zynqmp_qspi_priv *priv, u32 size)
|
|||||||
|
|
||||||
static void zynqmp_qspi_genfifo_cmd(struct zynqmp_qspi_priv *priv)
|
static void zynqmp_qspi_genfifo_cmd(struct zynqmp_qspi_priv *priv)
|
||||||
{
|
{
|
||||||
|
const struct spi_mem_op *op = priv->op;
|
||||||
u32 gen_fifo_cmd;
|
u32 gen_fifo_cmd;
|
||||||
u32 bytecount = 0;
|
u8 i, dummy_cycles, addr;
|
||||||
|
|
||||||
while (priv->len) {
|
/* Send opcode */
|
||||||
gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
|
gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
|
||||||
gen_fifo_cmd |= GQSPI_GFIFO_TX | GQSPI_SPI_MODE_SPI;
|
gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(op->cmd.buswidth);
|
||||||
gen_fifo_cmd |= *(u8 *)priv->tx_buf;
|
gen_fifo_cmd |= GQSPI_GFIFO_TX;
|
||||||
bytecount++;
|
gen_fifo_cmd |= op->cmd.opcode;
|
||||||
priv->len--;
|
zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
|
||||||
priv->tx_buf = (u8 *)priv->tx_buf + 1;
|
|
||||||
|
/* Send address */
|
||||||
|
for (i = 0; i < op->addr.nbytes; i++) {
|
||||||
|
addr = op->addr.val >> (8 * (op->addr.nbytes - i - 1));
|
||||||
|
|
||||||
|
gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
|
||||||
|
gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(op->addr.buswidth);
|
||||||
|
gen_fifo_cmd |= GQSPI_GFIFO_TX;
|
||||||
|
gen_fifo_cmd |= addr;
|
||||||
|
|
||||||
debug("GFIFO_CMD_Cmd = 0x%x\n", gen_fifo_cmd);
|
debug("GFIFO_CMD_Cmd = 0x%x\n", gen_fifo_cmd);
|
||||||
|
|
||||||
zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
|
zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Send dummy */
|
||||||
|
if (op->dummy.nbytes) {
|
||||||
|
dummy_cycles = op->dummy.nbytes * 8 / op->dummy.buswidth;
|
||||||
|
|
||||||
|
gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
|
||||||
|
gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(op->dummy.buswidth);
|
||||||
|
gen_fifo_cmd &= ~(GQSPI_GFIFO_TX | GQSPI_GFIFO_RX);
|
||||||
|
gen_fifo_cmd |= GQSPI_GFIFO_DATA_XFR_MASK;
|
||||||
|
gen_fifo_cmd |= dummy_cycles;
|
||||||
|
zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 zynqmp_qspi_calc_exp(struct zynqmp_qspi_priv *priv,
|
static u32 zynqmp_qspi_calc_exp(struct zynqmp_qspi_priv *priv,
|
||||||
@ -497,11 +532,10 @@ static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
|
gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
|
||||||
|
gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(priv->op->data.buswidth);
|
||||||
gen_fifo_cmd |= GQSPI_GFIFO_TX |
|
gen_fifo_cmd |= GQSPI_GFIFO_TX |
|
||||||
GQSPI_GFIFO_DATA_XFR_MASK;
|
GQSPI_GFIFO_DATA_XFR_MASK;
|
||||||
|
|
||||||
gen_fifo_cmd |= GQSPI_SPI_MODE_SPI;
|
|
||||||
|
|
||||||
while (priv->len) {
|
while (priv->len) {
|
||||||
len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd);
|
len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd);
|
||||||
zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
|
zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd);
|
||||||
@ -575,11 +609,10 @@ static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv *priv)
|
|||||||
u32 actuallen = priv->len;
|
u32 actuallen = priv->len;
|
||||||
|
|
||||||
gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
|
gen_fifo_cmd = zynqmp_qspi_bus_select(priv);
|
||||||
|
gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(priv->op->data.buswidth);
|
||||||
gen_fifo_cmd |= GQSPI_GFIFO_RX |
|
gen_fifo_cmd |= GQSPI_GFIFO_RX |
|
||||||
GQSPI_GFIFO_DATA_XFR_MASK;
|
GQSPI_GFIFO_DATA_XFR_MASK;
|
||||||
|
|
||||||
gen_fifo_cmd |= GQSPI_SPI_MODE_SPI;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if receive buffer is aligned to 4 byte and length
|
* Check if receive buffer is aligned to 4 byte and length
|
||||||
* is multiples of four byte as we are using dma to receive.
|
* is multiples of four byte as we are using dma to receive.
|
||||||
@ -596,62 +629,6 @@ static int zynqmp_qspi_genfifo_fill_rx(struct zynqmp_qspi_priv *priv)
|
|||||||
return zynqmp_qspi_start_dma(priv, gen_fifo_cmd, buf);
|
return zynqmp_qspi_start_dma(priv, gen_fifo_cmd, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int zynqmp_qspi_start_transfer(struct zynqmp_qspi_priv *priv)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (priv->is_inst) {
|
|
||||||
if (priv->tx_buf)
|
|
||||||
zynqmp_qspi_genfifo_cmd(priv);
|
|
||||||
else
|
|
||||||
return -EINVAL;
|
|
||||||
} else {
|
|
||||||
if (priv->tx_buf)
|
|
||||||
ret = zynqmp_qspi_genfifo_fill_tx(priv);
|
|
||||||
else if (priv->rx_buf)
|
|
||||||
ret = zynqmp_qspi_genfifo_fill_rx(priv);
|
|
||||||
else
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int zynqmp_qspi_transfer(struct zynqmp_qspi_priv *priv)
|
|
||||||
{
|
|
||||||
static unsigned int cs_change = 1;
|
|
||||||
int status = 0;
|
|
||||||
|
|
||||||
debug("%s\n", __func__);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
/* Select the chip if required */
|
|
||||||
if (cs_change)
|
|
||||||
zynqmp_qspi_chipselect(priv, 1);
|
|
||||||
|
|
||||||
cs_change = priv->cs_change;
|
|
||||||
|
|
||||||
if (!priv->tx_buf && !priv->rx_buf && priv->len) {
|
|
||||||
status = -EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Request the transfer */
|
|
||||||
if (priv->len) {
|
|
||||||
status = zynqmp_qspi_start_transfer(priv);
|
|
||||||
priv->is_inst = 0;
|
|
||||||
if (status < 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cs_change)
|
|
||||||
/* Deselect the chip */
|
|
||||||
zynqmp_qspi_chipselect(priv, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int zynqmp_qspi_claim_bus(struct udevice *dev)
|
static int zynqmp_qspi_claim_bus(struct udevice *dev)
|
||||||
{
|
{
|
||||||
struct udevice *bus = dev->parent;
|
struct udevice *bus = dev->parent;
|
||||||
@ -674,45 +651,43 @@ static int zynqmp_qspi_release_bus(struct udevice *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int zynqmp_qspi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout,
|
static int zynqmp_qspi_exec_op(struct spi_slave *slave,
|
||||||
void *din, unsigned long flags)
|
const struct spi_mem_op *op)
|
||||||
{
|
{
|
||||||
struct udevice *bus = dev->parent;
|
struct zynqmp_qspi_priv *priv = dev_get_priv(slave->dev->parent);
|
||||||
struct zynqmp_qspi_priv *priv = dev_get_priv(bus);
|
int ret = 0;
|
||||||
|
|
||||||
debug("%s: priv: 0x%08lx bitlen: %d dout: 0x%08lx ", __func__,
|
priv->op = op;
|
||||||
(unsigned long)priv, bitlen, (unsigned long)dout);
|
priv->tx_buf = op->data.buf.out;
|
||||||
debug("din: 0x%08lx flags: 0x%lx\n", (unsigned long)din, flags);
|
priv->rx_buf = op->data.buf.in;
|
||||||
|
priv->len = op->data.nbytes;
|
||||||
|
|
||||||
priv->tx_buf = dout;
|
zynqmp_qspi_chipselect(priv, 1);
|
||||||
priv->rx_buf = din;
|
|
||||||
priv->len = bitlen / 8;
|
|
||||||
|
|
||||||
/*
|
/* Send opcode, addr, dummy */
|
||||||
* Assume that the beginning of a transfer with bits to
|
zynqmp_qspi_genfifo_cmd(priv);
|
||||||
* transmit must contain a device command.
|
|
||||||
*/
|
|
||||||
if (dout && flags & SPI_XFER_BEGIN)
|
|
||||||
priv->is_inst = 1;
|
|
||||||
else
|
|
||||||
priv->is_inst = 0;
|
|
||||||
|
|
||||||
if (flags & SPI_XFER_END)
|
/* Request the transfer */
|
||||||
priv->cs_change = 1;
|
if (op->data.dir == SPI_MEM_DATA_IN)
|
||||||
else
|
ret = zynqmp_qspi_genfifo_fill_rx(priv);
|
||||||
priv->cs_change = 0;
|
else if (op->data.dir == SPI_MEM_DATA_OUT)
|
||||||
|
ret = zynqmp_qspi_genfifo_fill_tx(priv);
|
||||||
|
|
||||||
zynqmp_qspi_transfer(priv);
|
zynqmp_qspi_chipselect(priv, 0);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct spi_controller_mem_ops zynqmp_qspi_mem_ops = {
|
||||||
|
.exec_op = zynqmp_qspi_exec_op,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct dm_spi_ops zynqmp_qspi_ops = {
|
static const struct dm_spi_ops zynqmp_qspi_ops = {
|
||||||
.claim_bus = zynqmp_qspi_claim_bus,
|
.claim_bus = zynqmp_qspi_claim_bus,
|
||||||
.release_bus = zynqmp_qspi_release_bus,
|
.release_bus = zynqmp_qspi_release_bus,
|
||||||
.xfer = zynqmp_qspi_xfer,
|
|
||||||
.set_speed = zynqmp_qspi_set_speed,
|
.set_speed = zynqmp_qspi_set_speed,
|
||||||
.set_mode = zynqmp_qspi_set_mode,
|
.set_mode = zynqmp_qspi_set_mode,
|
||||||
|
.mem_ops = &zynqmp_qspi_mem_ops,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct udevice_id zynqmp_qspi_ids[] = {
|
static const struct udevice_id zynqmp_qspi_ids[] = {
|
||||||
|
@ -90,9 +90,8 @@ static int xlnx_wwdt_start(struct udevice *dev, u64 timeout, ulong flags)
|
|||||||
/* Calculate timeout count */
|
/* Calculate timeout count */
|
||||||
count = timeout * clock_f;
|
count = timeout * clock_f;
|
||||||
|
|
||||||
/* clk_enable will return -ENOSYS when it is not implemented */
|
|
||||||
ret = clk_enable(&wdt->clk);
|
ret = clk_enable(&wdt->clk);
|
||||||
if (ret && ret != -ENOSYS) {
|
if (ret) {
|
||||||
dev_err(dev, "failed to enable clock\n");
|
dev_err(dev, "failed to enable clock\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user