mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-03-16 04:04:06 +00:00
Merge branch 'CR_2653_QSPI_5.15_ziv.xu' into 'jh7110-5.15.y-devel'
CR 2653 QSPI 5.15 ziv.xu See merge request sdk/linux!612
This commit is contained in:
commit
bb4b157c65
5 changed files with 163 additions and 43 deletions
|
@ -321,24 +321,43 @@
|
|||
#size-cells = <0>;
|
||||
reg = <0x0 0x13010000 0x0 0x10000
|
||||
0x0 0x21000000 0x0 0x400000>;
|
||||
clocks = <&clkgen JH7110_QSPI_CLK_REF>;
|
||||
clock-names = "clk_ref";
|
||||
interrupts = <25>;
|
||||
clocks = <&clkgen JH7110_QSPI_CLK_REF>,
|
||||
<&clkgen JH7110_QSPI_CLK_APB>,
|
||||
<&clkgen JH7110_AHB1>,
|
||||
<&clkgen JH7110_QSPI_CLK_AHB>;
|
||||
clock-names = "clk_ref",
|
||||
"clk_apb",
|
||||
"ahb1",
|
||||
"clk_ahb";
|
||||
resets = <&rstgen RSTN_U0_CDNS_QSPI_APB>,
|
||||
<&rstgen RSTN_U0_CDNS_QSPI_AHB>,
|
||||
<&rstgen RSTN_U0_CDNS_QSPI_REF>;
|
||||
resets-names = "rst_apb", "rst_ahb", "rst_ref";
|
||||
cdns,fifo-depth = <256>;
|
||||
cdns,fifo-width = <4>;
|
||||
cdns,trigger-address = <0x0>;
|
||||
spi-max-frequency = <250000000>;
|
||||
|
||||
nor_flash: nor-flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
reg=<0>;
|
||||
cdns,read-delay = <5>;
|
||||
spi-max-frequency = <100000000>;
|
||||
cdns,tshsl-ns = <1>;
|
||||
cdns,tsd2d-ns = <1>;
|
||||
cdns,tchsh-ns = <1>;
|
||||
cdns,tslch-ns = <1>;
|
||||
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
data@f00000 {
|
||||
reg = <0xf00000 0x100000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -88,6 +88,9 @@ CONFIG_PCI=y
|
|||
CONFIG_PCIE_PLDA=y
|
||||
CONFIG_DEVTMPFS=y
|
||||
CONFIG_DEVTMPFS_MOUNT=y
|
||||
CONFIG_MTD=y
|
||||
CONFIG_MTD_BLOCK=y
|
||||
CONFIG_MTD_SPI_NOR=y
|
||||
CONFIG_OF_CONFIGFS=y
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_VIRTIO_BLK=y
|
||||
|
@ -163,6 +166,7 @@ CONFIG_HW_RANDOM_VIRTIO=y
|
|||
CONFIG_I2C_CHARDEV=y
|
||||
CONFIG_I2C_DESIGNWARE_PLATFORM=y
|
||||
CONFIG_SPI=y
|
||||
CONFIG_SPI_CADENCE_QUADSPI=y
|
||||
CONFIG_SPI_PL022_STARFIVE=y
|
||||
CONFIG_SPI_SIFIVE=y
|
||||
CONFIG_SPI_SPIDEV=y
|
||||
|
@ -286,6 +290,7 @@ CONFIG_NTFS_RW=y
|
|||
CONFIG_TMPFS=y
|
||||
CONFIG_TMPFS_POSIX_ACL=y
|
||||
CONFIG_HUGETLBFS=y
|
||||
CONFIG_JFFS2_FS=y
|
||||
CONFIG_NFS_FS=y
|
||||
CONFIG_NFS_V4=y
|
||||
CONFIG_NFS_V4_1=y
|
||||
|
|
|
@ -10,13 +10,10 @@
|
|||
|
||||
static void gd25q256_default_init(struct spi_nor *nor)
|
||||
{
|
||||
/*
|
||||
* Some manufacturer like GigaDevice may use different
|
||||
* bit to set QE on different memories, so the MFR can't
|
||||
* indicate the quad_enable method for this case, we need
|
||||
* to set it in the default_init fixup hook.
|
||||
*/
|
||||
nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable;
|
||||
/* use Quad page program */
|
||||
nor->params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4;
|
||||
spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP_1_1_4],
|
||||
SPINOR_OP_PP_1_1_4, SNOR_PROTO_1_1_4);
|
||||
}
|
||||
|
||||
static struct spi_nor_fixups gd25q256_fixups = {
|
||||
|
@ -40,7 +37,7 @@ static const struct flash_info gigadevice_parts[] = {
|
|||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
|
||||
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
|
||||
{ "gd25lq128d", INFO(0xc86018, 0, 64 * 1024, 256,
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_SKIP_SFDP |
|
||||
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
|
||||
{ "gd25q128", INFO(0xc84018, 0, 64 * 1024, 256,
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
|
||||
|
@ -56,4 +53,5 @@ const struct spi_nor_manufacturer spi_nor_gigadevice = {
|
|||
.name = "gigadevice",
|
||||
.parts = gigadevice_parts,
|
||||
.nparts = ARRAY_SIZE(gigadevice_parts),
|
||||
.fixups = &gd25q256_fixups,
|
||||
};
|
||||
|
|
2
drivers/spi/Kconfig
Executable file → Normal file
2
drivers/spi/Kconfig
Executable file → Normal file
|
@ -219,7 +219,7 @@ config SPI_CADENCE
|
|||
|
||||
config SPI_CADENCE_QUADSPI
|
||||
tristate "Cadence Quad SPI controller"
|
||||
depends on OF && (ARM || ARM64 || X86 || COMPILE_TEST)
|
||||
depends on OF && (ARM || ARM64 || X86 || RISCV || COMPILE_TEST)
|
||||
help
|
||||
Enable support for the Cadence Quad SPI Flash controller.
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mtd/spi-nor.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
@ -39,6 +40,14 @@
|
|||
/* Capabilities */
|
||||
#define CQSPI_SUPPORTS_OCTAL BIT(0)
|
||||
|
||||
enum {
|
||||
CLK_QSPI_APB = 0,
|
||||
CLK_AHB1,
|
||||
CLK_QSPI_AHB,
|
||||
CLK_QSPI_REF,
|
||||
CLK_QSPI_NUM,
|
||||
};
|
||||
|
||||
struct cqspi_st;
|
||||
|
||||
struct cqspi_flash_pdata {
|
||||
|
@ -60,6 +69,7 @@ struct cqspi_st {
|
|||
struct platform_device *pdev;
|
||||
|
||||
struct clk *clk;
|
||||
struct clk *clks[CLK_QSPI_NUM];
|
||||
unsigned int sclk;
|
||||
|
||||
void __iomem *iobase;
|
||||
|
@ -249,7 +259,14 @@ struct cqspi_driver_platdata {
|
|||
CQSPI_REG_IRQ_WATERMARK | \
|
||||
CQSPI_REG_IRQ_UNDERFLOW)
|
||||
|
||||
#define CQSPI_IRQ_STATUS_MASK 0x1FFFF
|
||||
#define CQSPI_IRQ_STATUS_MASK 0x1FFFF
|
||||
|
||||
#define CQSPI_DEFAULT_FREQ 2000000
|
||||
#define CQSPI_READ_ID_FREQ 1000000
|
||||
#define CQSPI_WRITE_DATA_FREQ 12000000
|
||||
|
||||
#define STARFIVE_RESET_REG_BASE_ADDR 0x13020000
|
||||
#define QSPI_RESET_REG_OFFSET 0x2fc
|
||||
|
||||
static int cqspi_wait_for_bit(void __iomem *reg, const u32 mask, bool clr)
|
||||
{
|
||||
|
@ -356,6 +373,7 @@ static int cqspi_set_protocol(struct cqspi_flash_pdata *f_pdata,
|
|||
|
||||
/* Right now we only support 8-8-8 DTR mode. */
|
||||
if (f_pdata->dtr) {
|
||||
|
||||
switch (op->cmd.buswidth) {
|
||||
case 0:
|
||||
break;
|
||||
|
@ -1082,6 +1100,7 @@ static ssize_t cqspi_write(struct cqspi_flash_pdata *f_pdata,
|
|||
struct cqspi_st *cqspi = f_pdata->cqspi;
|
||||
loff_t to = op->addr.val;
|
||||
size_t len = op->data.nbytes;
|
||||
|
||||
const u_char *buf = op->data.buf.out;
|
||||
int ret;
|
||||
|
||||
|
@ -1205,7 +1224,13 @@ static int cqspi_mem_process(struct spi_mem *mem, const struct spi_mem_op *op)
|
|||
struct cqspi_flash_pdata *f_pdata;
|
||||
|
||||
f_pdata = &cqspi->f_pdata[mem->spi->chip_select];
|
||||
cqspi_configure(f_pdata, mem->spi->max_speed_hz);
|
||||
|
||||
if (op->cmd.opcode == SPINOR_OP_RDID)
|
||||
cqspi_configure(f_pdata, CQSPI_READ_ID_FREQ);
|
||||
else if (op->cmd.opcode == SPINOR_OP_PP_1_1_4)
|
||||
cqspi_configure(f_pdata, CQSPI_WRITE_DATA_FREQ);
|
||||
else
|
||||
cqspi_configure(f_pdata, CQSPI_DEFAULT_FREQ);
|
||||
|
||||
if (op->data.dir == SPI_MEM_DATA_IN && op->data.buf.in) {
|
||||
if (!op->addr.nbytes)
|
||||
|
@ -1225,6 +1250,7 @@ static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
|
|||
int ret;
|
||||
|
||||
ret = cqspi_mem_process(mem, op);
|
||||
|
||||
if (ret)
|
||||
dev_err(&mem->spi->dev, "operation failed with %d\n", ret);
|
||||
|
||||
|
@ -1364,6 +1390,7 @@ static void cqspi_controller_init(struct cqspi_st *cqspi)
|
|||
|
||||
static int cqspi_request_mmap_dma(struct cqspi_st *cqspi)
|
||||
{
|
||||
int ret;
|
||||
dma_cap_mask_t mask;
|
||||
|
||||
dma_cap_zero(mask);
|
||||
|
@ -1371,7 +1398,7 @@ static int cqspi_request_mmap_dma(struct cqspi_st *cqspi)
|
|||
|
||||
cqspi->rx_chan = dma_request_chan_by_mask(&mask);
|
||||
if (IS_ERR(cqspi->rx_chan)) {
|
||||
int ret = PTR_ERR(cqspi->rx_chan);
|
||||
ret = PTR_ERR(cqspi->rx_chan);
|
||||
cqspi->rx_chan = NULL;
|
||||
return dev_err_probe(&cqspi->pdev->dev, ret, "No Rx DMA available\n");
|
||||
}
|
||||
|
@ -1432,15 +1459,74 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cadence_quadspi_clk_init(struct platform_device *pdev, struct cqspi_st *cqspi)
|
||||
{
|
||||
static struct clk_bulk_data qspiclk[] = {
|
||||
{ .id = "clk_apb" },
|
||||
{ .id = "ahb1" },
|
||||
{ .id = "clk_ahb" },
|
||||
{ .id = "clk_ref" },
|
||||
};
|
||||
|
||||
int ret = 0;
|
||||
|
||||
ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(qspiclk), qspiclk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "%s: failed to get qspi clocks\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
cqspi->clks[CLK_QSPI_APB] = qspiclk[0].clk;
|
||||
cqspi->clks[CLK_AHB1] = qspiclk[1].clk;
|
||||
cqspi->clks[CLK_QSPI_AHB] = qspiclk[2].clk;
|
||||
cqspi->clks[CLK_QSPI_REF] = qspiclk[3].clk;
|
||||
|
||||
ret = clk_prepare_enable(cqspi->clks[CLK_QSPI_APB]);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "%s: failed to enable CLK_QSPI_APB\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(cqspi->clks[CLK_AHB1]);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "%s: failed to enable CLK_AHB1\n", __func__);
|
||||
goto disable_apb_clk;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(cqspi->clks[CLK_QSPI_AHB]);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "%s: failed to enable CLK_QSPI_AHB\n", __func__);
|
||||
goto disable_ahb1;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(cqspi->clks[CLK_QSPI_REF]);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "%s: failed to enable CLK_QSPI_REF\n", __func__);
|
||||
goto disable_ahb_clk;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
disable_ahb_clk:
|
||||
clk_disable_unprepare(cqspi->clks[CLK_QSPI_AHB]);
|
||||
disable_ahb1:
|
||||
clk_disable_unprepare(cqspi->clks[CLK_AHB1]);
|
||||
disable_apb_clk:
|
||||
clk_disable_unprepare(cqspi->clks[CLK_QSPI_APB]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cqspi_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct cqspi_driver_platdata *ddata;
|
||||
struct reset_control *rstc, *rstc_ocp;
|
||||
struct reset_control *rst_apb, *rst_ahb, *rst_ref;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct spi_master *master;
|
||||
struct resource *res_ahb;
|
||||
struct cqspi_st *cqspi;
|
||||
struct resource *res;
|
||||
void __iomem *reset_res;
|
||||
int ret;
|
||||
int irq;
|
||||
|
||||
|
@ -1449,7 +1535,8 @@ static int cqspi_probe(struct platform_device *pdev)
|
|||
dev_err(&pdev->dev, "spi_alloc_master failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
master->mode_bits = SPI_RX_QUAD | SPI_RX_DUAL;
|
||||
master->mode_bits = SPI_RX_QUAD | SPI_TX_QUAD;
|
||||
master->buswidth_override_bits = SPI_RX_QUAD | SPI_TX_QUAD;
|
||||
master->mem_ops = &cqspi_mem_ops;
|
||||
master->dev.of_node = pdev->dev.of_node;
|
||||
|
||||
|
@ -1466,14 +1553,6 @@ static int cqspi_probe(struct platform_device *pdev)
|
|||
goto probe_master_put;
|
||||
}
|
||||
|
||||
/* Obtain QSPI clock. */
|
||||
cqspi->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(cqspi->clk)) {
|
||||
dev_err(dev, "Cannot claim QSPI clock.\n");
|
||||
ret = PTR_ERR(cqspi->clk);
|
||||
goto probe_master_put;
|
||||
}
|
||||
|
||||
/* Obtain and remap controller address. */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
cqspi->iobase = devm_ioremap_resource(dev, res);
|
||||
|
@ -1491,6 +1570,7 @@ static int cqspi_probe(struct platform_device *pdev)
|
|||
ret = PTR_ERR(cqspi->ahb_base);
|
||||
goto probe_master_put;
|
||||
}
|
||||
|
||||
cqspi->mmap_phys_base = (dma_addr_t)res_ahb->start;
|
||||
cqspi->ahb_size = resource_size(res_ahb);
|
||||
|
||||
|
@ -1510,42 +1590,52 @@ static int cqspi_probe(struct platform_device *pdev)
|
|||
goto probe_master_put;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(cqspi->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Cannot enable QSPI clock.\n");
|
||||
/* Obtain QSPI clock. */
|
||||
ret = cadence_quadspi_clk_init(pdev, cqspi);
|
||||
if (ret)
|
||||
goto probe_clk_failed;
|
||||
}
|
||||
|
||||
/* Obtain QSPI reset control */
|
||||
rstc = devm_reset_control_get_optional_exclusive(dev, "qspi");
|
||||
if (IS_ERR(rstc)) {
|
||||
ret = PTR_ERR(rstc);
|
||||
dev_err(dev, "Cannot get QSPI reset.\n");
|
||||
rst_apb = devm_reset_control_get_optional_exclusive(dev, "rst_apb");
|
||||
if (IS_ERR(rst_apb)) {
|
||||
ret = PTR_ERR(rst_apb);
|
||||
dev_err(dev, "Cannot get APB reset.\n");
|
||||
goto probe_reset_failed;
|
||||
}
|
||||
|
||||
rstc_ocp = devm_reset_control_get_optional_exclusive(dev, "qspi-ocp");
|
||||
if (IS_ERR(rstc_ocp)) {
|
||||
ret = PTR_ERR(rstc_ocp);
|
||||
dev_err(dev, "Cannot get QSPI OCP reset.\n");
|
||||
rst_ahb = devm_reset_control_get_optional_exclusive(dev, "rst_ahb");
|
||||
if (IS_ERR(rst_ahb)) {
|
||||
ret = PTR_ERR(rst_ahb);
|
||||
dev_err(dev, "Cannot get QSPI ahb reset.\n");
|
||||
goto probe_reset_failed;
|
||||
}
|
||||
|
||||
reset_control_assert(rstc);
|
||||
reset_control_deassert(rstc);
|
||||
rst_ref = devm_reset_control_get_optional_exclusive(dev, "rst_ref");
|
||||
if (IS_ERR(rst_ref)) {
|
||||
ret = PTR_ERR(rst_ref);
|
||||
dev_err(dev, "Cannot get QSPI ref reset.\n");
|
||||
goto probe_reset_failed;
|
||||
}
|
||||
|
||||
reset_control_assert(rstc_ocp);
|
||||
reset_control_deassert(rstc_ocp);
|
||||
/*
|
||||
* Due to the problem of reset in the current QSPI driver
|
||||
* we temporarily reset QSPI by writing register
|
||||
*/
|
||||
reset_res = ioremap(STARFIVE_RESET_REG_BASE_ADDR, 0x300);
|
||||
writel(0X7E7FE00, reset_res + QSPI_RESET_REG_OFFSET);
|
||||
|
||||
cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clks[CLK_QSPI_REF]);
|
||||
|
||||
cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clk);
|
||||
master->max_speed_hz = cqspi->master_ref_clk_hz;
|
||||
ddata = of_device_get_match_data(dev);
|
||||
if (ddata) {
|
||||
if (ddata->quirks & CQSPI_NEEDS_WR_DELAY)
|
||||
cqspi->wr_delay = 50 * DIV_ROUND_UP(NSEC_PER_SEC,
|
||||
cqspi->master_ref_clk_hz);
|
||||
|
||||
if (ddata->hwcaps_mask & CQSPI_SUPPORTS_OCTAL)
|
||||
master->mode_bits |= SPI_RX_OCTAL | SPI_TX_OCTAL;
|
||||
|
||||
if (!(ddata->quirks & CQSPI_DISABLE_DAC_MODE))
|
||||
cqspi->use_direct_mode = true;
|
||||
}
|
||||
|
@ -1583,15 +1673,20 @@ static int cqspi_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
return 0;
|
||||
|
||||
probe_setup_failed:
|
||||
cqspi_controller_enable(cqspi, 0);
|
||||
probe_reset_failed:
|
||||
clk_disable_unprepare(cqspi->clk);
|
||||
clk_disable_unprepare(cqspi->clks[CLK_QSPI_REF]);
|
||||
clk_disable_unprepare(cqspi->clks[CLK_QSPI_AHB]);
|
||||
clk_disable_unprepare(cqspi->clks[CLK_AHB1]);
|
||||
clk_disable_unprepare(cqspi->clks[CLK_QSPI_APB]);
|
||||
probe_clk_failed:
|
||||
pm_runtime_put_sync(dev);
|
||||
pm_runtime_disable(dev);
|
||||
probe_master_put:
|
||||
spi_master_put(master);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1604,7 +1699,10 @@ static int cqspi_remove(struct platform_device *pdev)
|
|||
if (cqspi->rx_chan)
|
||||
dma_release_channel(cqspi->rx_chan);
|
||||
|
||||
clk_disable_unprepare(cqspi->clk);
|
||||
clk_disable_unprepare(cqspi->clks[CLK_QSPI_REF]);
|
||||
clk_disable_unprepare(cqspi->clks[CLK_QSPI_AHB]);
|
||||
clk_disable_unprepare(cqspi->clks[CLK_AHB1]);
|
||||
clk_disable_unprepare(cqspi->clks[CLK_QSPI_APB]);
|
||||
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
|
Loading…
Add table
Reference in a new issue