|
@@ -8,16 +8,16 @@
|
|
*/
|
|
*/
|
|
|
|
|
|
#include <common.h>
|
|
#include <common.h>
|
|
|
|
+#include <clk.h>
|
|
|
|
+#include <dm.h>
|
|
|
|
+#include <errno.h>
|
|
#include <malloc.h>
|
|
#include <malloc.h>
|
|
|
|
+#include <reset.h>
|
|
#include <spi.h>
|
|
#include <spi.h>
|
|
#include <spi_flash.h>
|
|
#include <spi_flash.h>
|
|
#include <asm/io.h>
|
|
#include <asm/io.h>
|
|
-#include <dm.h>
|
|
|
|
-#include <errno.h>
|
|
|
|
#include <asm/arch/stm32.h>
|
|
#include <asm/arch/stm32.h>
|
|
-#include <clk.h>
|
|
|
|
-
|
|
|
|
-DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
|
|
+#include <linux/ioport.h>
|
|
|
|
|
|
struct stm32_qspi_regs {
|
|
struct stm32_qspi_regs {
|
|
u32 cr; /* 0x00 */
|
|
u32 cr; /* 0x00 */
|
|
@@ -155,6 +155,8 @@ enum STM32_QSPI_CCR_FMODE {
|
|
/* default SCK frequency, unit: HZ */
|
|
/* default SCK frequency, unit: HZ */
|
|
#define STM32_QSPI_DEFAULT_SCK_FREQ 108000000
|
|
#define STM32_QSPI_DEFAULT_SCK_FREQ 108000000
|
|
|
|
|
|
|
|
+#define STM32_MAX_NORCHIP 2
|
|
|
|
+
|
|
struct stm32_qspi_platdata {
|
|
struct stm32_qspi_platdata {
|
|
u32 base;
|
|
u32 base;
|
|
u32 memory_map;
|
|
u32 memory_map;
|
|
@@ -206,11 +208,18 @@ static void _stm32_qspi_wait_for_ftf(struct stm32_qspi_priv *priv)
|
|
static void _stm32_qspi_set_flash_size(struct stm32_qspi_priv *priv, u32 size)
|
|
static void _stm32_qspi_set_flash_size(struct stm32_qspi_priv *priv, u32 size)
|
|
{
|
|
{
|
|
u32 fsize = fls(size) - 1;
|
|
u32 fsize = fls(size) - 1;
|
|
|
|
+
|
|
clrsetbits_le32(&priv->regs->dcr,
|
|
clrsetbits_le32(&priv->regs->dcr,
|
|
STM32_QSPI_DCR_FSIZE_MASK << STM32_QSPI_DCR_FSIZE_SHIFT,
|
|
STM32_QSPI_DCR_FSIZE_MASK << STM32_QSPI_DCR_FSIZE_SHIFT,
|
|
fsize << STM32_QSPI_DCR_FSIZE_SHIFT);
|
|
fsize << STM32_QSPI_DCR_FSIZE_SHIFT);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void _stm32_qspi_set_cs(struct stm32_qspi_priv *priv, unsigned int cs)
|
|
|
|
+{
|
|
|
|
+ clrsetbits_le32(&priv->regs->cr, STM32_QSPI_CR_FSEL,
|
|
|
|
+ cs ? STM32_QSPI_CR_FSEL : 0);
|
|
|
|
+}
|
|
|
|
+
|
|
static unsigned int _stm32_qspi_gen_ccr(struct stm32_qspi_priv *priv)
|
|
static unsigned int _stm32_qspi_gen_ccr(struct stm32_qspi_priv *priv)
|
|
{
|
|
{
|
|
unsigned int ccr_reg = 0;
|
|
unsigned int ccr_reg = 0;
|
|
@@ -255,13 +264,15 @@ static unsigned int _stm32_qspi_gen_ccr(struct stm32_qspi_priv *priv)
|
|
}
|
|
}
|
|
|
|
|
|
static void _stm32_qspi_enable_mmap(struct stm32_qspi_priv *priv,
|
|
static void _stm32_qspi_enable_mmap(struct stm32_qspi_priv *priv,
|
|
- struct spi_flash *flash)
|
|
|
|
|
|
+ struct spi_flash *flash)
|
|
{
|
|
{
|
|
|
|
+ unsigned int ccr_reg;
|
|
|
|
+
|
|
priv->command = flash->read_cmd | CMD_HAS_ADR | CMD_HAS_DATA
|
|
priv->command = flash->read_cmd | CMD_HAS_ADR | CMD_HAS_DATA
|
|
| CMD_HAS_DUMMY;
|
|
| CMD_HAS_DUMMY;
|
|
priv->dummycycles = flash->dummy_byte * 8;
|
|
priv->dummycycles = flash->dummy_byte * 8;
|
|
|
|
|
|
- unsigned int ccr_reg = _stm32_qspi_gen_ccr(priv);
|
|
|
|
|
|
+ ccr_reg = _stm32_qspi_gen_ccr(priv);
|
|
ccr_reg |= (STM32_QSPI_CCR_MEM_MAP << STM32_QSPI_CCR_FMODE_SHIFT);
|
|
ccr_reg |= (STM32_QSPI_CCR_MEM_MAP << STM32_QSPI_CCR_FMODE_SHIFT);
|
|
|
|
|
|
_stm32_qspi_wait_for_not_busy(priv);
|
|
_stm32_qspi_wait_for_not_busy(priv);
|
|
@@ -291,10 +302,12 @@ static void _stm32_qspi_start_xfer(struct stm32_qspi_priv *priv, u32 cr_reg)
|
|
}
|
|
}
|
|
|
|
|
|
static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv,
|
|
static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv,
|
|
- struct spi_flash *flash, unsigned int bitlen,
|
|
|
|
- const u8 *dout, u8 *din, unsigned long flags)
|
|
|
|
|
|
+ struct spi_flash *flash, unsigned int bitlen,
|
|
|
|
+ const u8 *dout, u8 *din, unsigned long flags)
|
|
{
|
|
{
|
|
unsigned int words = bitlen / 8;
|
|
unsigned int words = bitlen / 8;
|
|
|
|
+ u32 ccr_reg;
|
|
|
|
+ int i;
|
|
|
|
|
|
if (flags & SPI_XFER_MMAP) {
|
|
if (flags & SPI_XFER_MMAP) {
|
|
_stm32_qspi_enable_mmap(priv, flash);
|
|
_stm32_qspi_enable_mmap(priv, flash);
|
|
@@ -346,7 +359,7 @@ static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv,
|
|
}
|
|
}
|
|
|
|
|
|
if (flags & SPI_XFER_END) {
|
|
if (flags & SPI_XFER_END) {
|
|
- u32 ccr_reg = _stm32_qspi_gen_ccr(priv);
|
|
|
|
|
|
+ ccr_reg = _stm32_qspi_gen_ccr(priv);
|
|
ccr_reg |= STM32_QSPI_CCR_IND_WRITE
|
|
ccr_reg |= STM32_QSPI_CCR_IND_WRITE
|
|
<< STM32_QSPI_CCR_FMODE_SHIFT;
|
|
<< STM32_QSPI_CCR_FMODE_SHIFT;
|
|
|
|
|
|
@@ -365,7 +378,7 @@ static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv,
|
|
|
|
|
|
debug("%s: words:%d data:", __func__, words);
|
|
debug("%s: words:%d data:", __func__, words);
|
|
|
|
|
|
- int i = 0;
|
|
|
|
|
|
+ i = 0;
|
|
while (words > i) {
|
|
while (words > i) {
|
|
writeb(dout[i], &priv->regs->dr);
|
|
writeb(dout[i], &priv->regs->dr);
|
|
debug("%02x ", dout[i]);
|
|
debug("%02x ", dout[i]);
|
|
@@ -379,7 +392,7 @@ static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (din) {
|
|
} else if (din) {
|
|
- u32 ccr_reg = _stm32_qspi_gen_ccr(priv);
|
|
|
|
|
|
+ ccr_reg = _stm32_qspi_gen_ccr(priv);
|
|
ccr_reg |= STM32_QSPI_CCR_IND_READ
|
|
ccr_reg |= STM32_QSPI_CCR_IND_READ
|
|
<< STM32_QSPI_CCR_FMODE_SHIFT;
|
|
<< STM32_QSPI_CCR_FMODE_SHIFT;
|
|
|
|
|
|
@@ -394,7 +407,7 @@ static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv,
|
|
|
|
|
|
debug("%s: data:", __func__);
|
|
debug("%s: data:", __func__);
|
|
|
|
|
|
- int i = 0;
|
|
|
|
|
|
+ i = 0;
|
|
while (words > i) {
|
|
while (words > i) {
|
|
din[i] = readb(&priv->regs->dr);
|
|
din[i] = readb(&priv->regs->dr);
|
|
debug("%02x ", din[i]);
|
|
debug("%02x ", din[i]);
|
|
@@ -408,27 +421,23 @@ static int _stm32_qspi_xfer(struct stm32_qspi_priv *priv,
|
|
|
|
|
|
static int stm32_qspi_ofdata_to_platdata(struct udevice *bus)
|
|
static int stm32_qspi_ofdata_to_platdata(struct udevice *bus)
|
|
{
|
|
{
|
|
- struct fdt_resource res_regs, res_mem;
|
|
|
|
|
|
+ struct resource res_regs, res_mem;
|
|
struct stm32_qspi_platdata *plat = bus->platdata;
|
|
struct stm32_qspi_platdata *plat = bus->platdata;
|
|
- const void *blob = gd->fdt_blob;
|
|
|
|
- int node = dev_of_offset(bus);
|
|
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
- ret = fdt_get_named_resource(blob, node, "reg", "reg-names",
|
|
|
|
- "QuadSPI", &res_regs);
|
|
|
|
|
|
+ ret = dev_read_resource_byname(bus, "qspi", &res_regs);
|
|
if (ret) {
|
|
if (ret) {
|
|
debug("Error: can't get regs base addresses(ret = %d)!\n", ret);
|
|
debug("Error: can't get regs base addresses(ret = %d)!\n", ret);
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
- ret = fdt_get_named_resource(blob, node, "reg", "reg-names",
|
|
|
|
- "QuadSPI-memory", &res_mem);
|
|
|
|
|
|
+ ret = dev_read_resource_byname(bus, "qspi_mm", &res_mem);
|
|
if (ret) {
|
|
if (ret) {
|
|
debug("Error: can't get mmap base address(ret = %d)!\n", ret);
|
|
debug("Error: can't get mmap base address(ret = %d)!\n", ret);
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
}
|
|
}
|
|
|
|
|
|
- plat->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency",
|
|
|
|
- STM32_QSPI_DEFAULT_SCK_FREQ);
|
|
|
|
|
|
+ plat->max_hz = dev_read_u32_default(bus, "spi-max-frequency",
|
|
|
|
+ STM32_QSPI_DEFAULT_SCK_FREQ);
|
|
|
|
|
|
plat->base = res_regs.start;
|
|
plat->base = res_regs.start;
|
|
plat->memory_map = res_mem.start;
|
|
plat->memory_map = res_mem.start;
|
|
@@ -448,6 +457,9 @@ static int stm32_qspi_probe(struct udevice *bus)
|
|
struct stm32_qspi_platdata *plat = dev_get_platdata(bus);
|
|
struct stm32_qspi_platdata *plat = dev_get_platdata(bus);
|
|
struct stm32_qspi_priv *priv = dev_get_priv(bus);
|
|
struct stm32_qspi_priv *priv = dev_get_priv(bus);
|
|
struct dm_spi_bus *dm_spi_bus;
|
|
struct dm_spi_bus *dm_spi_bus;
|
|
|
|
+ struct clk clk;
|
|
|
|
+ struct reset_ctl reset_ctl;
|
|
|
|
+ int ret;
|
|
|
|
|
|
dm_spi_bus = bus->uclass_priv;
|
|
dm_spi_bus = bus->uclass_priv;
|
|
|
|
|
|
@@ -457,9 +469,6 @@ static int stm32_qspi_probe(struct udevice *bus)
|
|
|
|
|
|
priv->max_hz = plat->max_hz;
|
|
priv->max_hz = plat->max_hz;
|
|
|
|
|
|
-#ifdef CONFIG_CLK
|
|
|
|
- int ret;
|
|
|
|
- struct clk clk;
|
|
|
|
ret = clk_get_by_index(bus, 0, &clk);
|
|
ret = clk_get_by_index(bus, 0, &clk);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
return ret;
|
|
return ret;
|
|
@@ -477,7 +486,19 @@ static int stm32_qspi_probe(struct udevice *bus)
|
|
return priv->clock_rate;
|
|
return priv->clock_rate;
|
|
}
|
|
}
|
|
|
|
|
|
-#endif
|
|
|
|
|
|
+ ret = reset_get_by_index(bus, 0, &reset_ctl);
|
|
|
|
+ if (ret) {
|
|
|
|
+ if (ret != -ENOENT) {
|
|
|
|
+ dev_err(bus, "failed to get reset\n");
|
|
|
|
+ clk_disable(&clk);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ /* Reset QSPI controller */
|
|
|
|
+ reset_assert(&reset_ctl);
|
|
|
|
+ udelay(2);
|
|
|
|
+ reset_deassert(&reset_ctl);
|
|
|
|
+ }
|
|
|
|
|
|
setbits_le32(&priv->regs->cr, STM32_QSPI_CR_SSHIFT);
|
|
setbits_le32(&priv->regs->cr, STM32_QSPI_CR_SSHIFT);
|
|
|
|
|
|
@@ -494,10 +515,17 @@ static int stm32_qspi_claim_bus(struct udevice *dev)
|
|
struct stm32_qspi_priv *priv;
|
|
struct stm32_qspi_priv *priv;
|
|
struct udevice *bus;
|
|
struct udevice *bus;
|
|
struct spi_flash *flash;
|
|
struct spi_flash *flash;
|
|
|
|
+ struct dm_spi_slave_platdata *slave_plat;
|
|
|
|
|
|
bus = dev->parent;
|
|
bus = dev->parent;
|
|
priv = dev_get_priv(bus);
|
|
priv = dev_get_priv(bus);
|
|
flash = dev_get_uclass_priv(dev);
|
|
flash = dev_get_uclass_priv(dev);
|
|
|
|
+ slave_plat = dev_get_parent_platdata(dev);
|
|
|
|
+
|
|
|
|
+ if (slave_plat->cs >= STM32_MAX_NORCHIP)
|
|
|
|
+ return -ENODEV;
|
|
|
|
+
|
|
|
|
+ _stm32_qspi_set_cs(priv, slave_plat->cs);
|
|
|
|
|
|
_stm32_qspi_set_flash_size(priv, flash->size);
|
|
_stm32_qspi_set_flash_size(priv, flash->size);
|
|
|
|
|
|
@@ -520,7 +548,7 @@ static int stm32_qspi_release_bus(struct udevice *dev)
|
|
}
|
|
}
|
|
|
|
|
|
static int stm32_qspi_xfer(struct udevice *dev, unsigned int bitlen,
|
|
static int stm32_qspi_xfer(struct udevice *dev, unsigned int bitlen,
|
|
- const void *dout, void *din, unsigned long flags)
|
|
|
|
|
|
+ const void *dout, void *din, unsigned long flags)
|
|
{
|
|
{
|
|
struct stm32_qspi_priv *priv;
|
|
struct stm32_qspi_priv *priv;
|
|
struct udevice *bus;
|
|
struct udevice *bus;
|
|
@@ -538,12 +566,13 @@ static int stm32_qspi_set_speed(struct udevice *bus, uint speed)
|
|
{
|
|
{
|
|
struct stm32_qspi_platdata *plat = bus->platdata;
|
|
struct stm32_qspi_platdata *plat = bus->platdata;
|
|
struct stm32_qspi_priv *priv = dev_get_priv(bus);
|
|
struct stm32_qspi_priv *priv = dev_get_priv(bus);
|
|
|
|
+ u32 qspi_clk = priv->clock_rate;
|
|
|
|
+ u32 prescaler = 255;
|
|
|
|
+ u32 csht;
|
|
|
|
|
|
if (speed > plat->max_hz)
|
|
if (speed > plat->max_hz)
|
|
speed = plat->max_hz;
|
|
speed = plat->max_hz;
|
|
|
|
|
|
- u32 qspi_clk = priv->clock_rate;
|
|
|
|
- u32 prescaler = 255;
|
|
|
|
if (speed > 0) {
|
|
if (speed > 0) {
|
|
prescaler = DIV_ROUND_UP(qspi_clk, speed) - 1;
|
|
prescaler = DIV_ROUND_UP(qspi_clk, speed) - 1;
|
|
if (prescaler > 255)
|
|
if (prescaler > 255)
|
|
@@ -552,7 +581,7 @@ static int stm32_qspi_set_speed(struct udevice *bus, uint speed)
|
|
prescaler = 0;
|
|
prescaler = 0;
|
|
}
|
|
}
|
|
|
|
|
|
- u32 csht = DIV_ROUND_UP((5 * qspi_clk) / (prescaler + 1), 100000000);
|
|
|
|
|
|
+ csht = DIV_ROUND_UP((5 * qspi_clk) / (prescaler + 1), 100000000);
|
|
csht = (csht - 1) & STM32_QSPI_DCR_CSHT_MASK;
|
|
csht = (csht - 1) & STM32_QSPI_DCR_CSHT_MASK;
|
|
|
|
|
|
_stm32_qspi_wait_for_not_busy(priv);
|
|
_stm32_qspi_wait_for_not_busy(priv);
|
|
@@ -562,7 +591,6 @@ static int stm32_qspi_set_speed(struct udevice *bus, uint speed)
|
|
STM32_QSPI_CR_PRESCALER_SHIFT,
|
|
STM32_QSPI_CR_PRESCALER_SHIFT,
|
|
prescaler << STM32_QSPI_CR_PRESCALER_SHIFT);
|
|
prescaler << STM32_QSPI_CR_PRESCALER_SHIFT);
|
|
|
|
|
|
-
|
|
|
|
clrsetbits_le32(&priv->regs->dcr,
|
|
clrsetbits_le32(&priv->regs->dcr,
|
|
STM32_QSPI_DCR_CSHT_MASK << STM32_QSPI_DCR_CSHT_SHIFT,
|
|
STM32_QSPI_DCR_CSHT_MASK << STM32_QSPI_DCR_CSHT_SHIFT,
|
|
csht << STM32_QSPI_DCR_CSHT_SHIFT);
|
|
csht << STM32_QSPI_DCR_CSHT_SHIFT);
|
|
@@ -632,6 +660,7 @@ static const struct dm_spi_ops stm32_qspi_ops = {
|
|
|
|
|
|
static const struct udevice_id stm32_qspi_ids[] = {
|
|
static const struct udevice_id stm32_qspi_ids[] = {
|
|
{ .compatible = "st,stm32-qspi" },
|
|
{ .compatible = "st,stm32-qspi" },
|
|
|
|
+ { .compatible = "st,stm32f469-qspi" },
|
|
{ }
|
|
{ }
|
|
};
|
|
};
|
|
|
|
|