mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
spi: airoha: driver fixes & improvements
Merge series from Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>: This patch series greatly improve airoha snfi driver and fix a number of serious bugs. Fixed bugs: * Fix reading/writing of flashes with more than one plane per lun * Fill the buffer with 0xff before writing * Fix reading of flashes supporting continuous reading mode * Fix error paths Improvements: * Add support of dual/quad wires spi modes in exec_op(). This also fix flash reading/writing if dirmap can't be created. * Support of dualio/quadio flash reading commands * Remove dirty hack that reads flash page settings from SNFI registers during driver startup * Add support of EN7523 SoC Patched kernel tests: root@OpenWrt:/lib/modules/6.6.79# insmod mtd_oobtest.ko dev=1 [ 263.191711] [ 263.193218] ================================================= [ 263.199014] mtd_oobtest: MTD device: 1 [ 263.202768] mtd_oobtest: MTD device size 268304384, eraseblock size 131072, page size 2048, count of eraseblocks 2047, pages per eraseblock 64, OOB size 128 [ 263.216791] mtd_test: scanning for bad eraseblocks [ 263.221956] mtd_test: scanned 2047 eraseblocks, 0 are bad [ 263.227361] mtd_oobtest: test 1 of 5 [ 265.077216] mtd_oobtest: writing OOBs of whole device [ 265.121767] mtd_oobtest: written up to eraseblock 0 [ 275.174147] mtd_oobtest: written up to eraseblock 256 [ 285.210279] mtd_oobtest: written up to eraseblock 512 [ 295.241724] mtd_oobtest: written up to eraseblock 768 [ 305.280167] mtd_oobtest: written up to eraseblock 1024 [ 315.326883] mtd_oobtest: written up to eraseblock 1280 [ 325.364049] mtd_oobtest: written up to eraseblock 1536 [ 335.398609] mtd_oobtest: written up to eraseblock 1792 [ 345.358981] mtd_oobtest: written 2047 eraseblocks [ 345.363694] mtd_oobtest: verifying all eraseblocks [ 345.386088] mtd_oobtest: verified up to eraseblock 0 [ 349.830833] mtd_oobtest: verified up to eraseblock 256 [ 354.276245] mtd_oobtest: verified up to eraseblock 512 [ 358.721496] mtd_oobtest: verified up to eraseblock 768 [ 363.166881] mtd_oobtest: verified up to eraseblock 1024 [ 367.612694] mtd_oobtest: verified up to eraseblock 1280 [ 372.058211] mtd_oobtest: verified up to eraseblock 1536 [ 376.503820] mtd_oobtest: verified up to eraseblock 1792 [ 380.914843] mtd_oobtest: verified 2047 eraseblocks [ 380.919660] mtd_oobtest: test 2 of 5 [ 384.202620] mtd_oobtest: writing OOBs of whole device [ 384.247584] mtd_oobtest: written up to eraseblock 0 [ 394.305121] mtd_oobtest: written up to eraseblock 256 [ 404.342199] mtd_oobtest: written up to eraseblock 512 [ 414.374204] mtd_oobtest: written up to eraseblock 768 [ 424.409891] mtd_oobtest: written up to eraseblock 1024 [ 434.453378] mtd_oobtest: written up to eraseblock 1280 [ 444.494321] mtd_oobtest: written up to eraseblock 1536 [ 454.534480] mtd_oobtest: written up to eraseblock 1792 [ 464.490962] mtd_oobtest: written 2047 eraseblocks [ 464.495681] mtd_oobtest: verifying all eraseblocks [ 464.518015] mtd_oobtest: verified up to eraseblock 0 [ 468.955635] mtd_oobtest: verified up to eraseblock 256 [ 473.395502] mtd_oobtest: verified up to eraseblock 512 [ 477.834373] mtd_oobtest: verified up to eraseblock 768 [ 482.272717] mtd_oobtest: verified up to eraseblock 1024 [ 486.712148] mtd_oobtest: verified up to eraseblock 1280 [ 491.150704] mtd_oobtest: verified up to eraseblock 1536 [ 495.589439] mtd_oobtest: verified up to eraseblock 1792 [ 499.993138] mtd_oobtest: verified 2047 eraseblocks [ 499.997951] mtd_oobtest: test 3 of 5 [ 503.404228] mtd_oobtest: writing OOBs of whole device [ 503.448822] mtd_oobtest: written up to eraseblock 0 [ 513.480773] mtd_oobtest: written up to eraseblock 256 [ 523.489361] mtd_oobtest: written up to eraseblock 512 [ 533.506896] mtd_oobtest: written up to eraseblock 768 [ 543.506268] mtd_oobtest: written up to eraseblock 1024 [ 553.506503] mtd_oobtest: written up to eraseblock 1280 [ 563.511266] mtd_oobtest: written up to eraseblock 1536 [ 573.519567] mtd_oobtest: written up to eraseblock 1792 [ 583.455111] mtd_oobtest: written 2047 eraseblocks [ 583.459837] mtd_oobtest: verifying all eraseblocks [ 583.499358] mtd_oobtest: verified up to eraseblock 0 [ 592.382953] mtd_oobtest: verified up to eraseblock 256 [ 601.267297] mtd_oobtest: verified up to eraseblock 512 [ 610.150907] mtd_oobtest: verified up to eraseblock 768 [ 619.034702] mtd_oobtest: verified up to eraseblock 1024 [ 627.919683] mtd_oobtest: verified up to eraseblock 1280 [ 636.821168] mtd_oobtest: verified up to eraseblock 1536 [ 645.705487] mtd_oobtest: verified up to eraseblock 1792 [ 654.520336] mtd_oobtest: verified 2047 eraseblocks [ 654.525134] mtd_oobtest: test 4 of 5 [ 657.578146] mtd_oobtest: attempting to start write past end of OOB [ 657.584336] mtd_oobtest: an error is expected... [ 657.588974] mtd_oobtest: error occurred as expected [ 657.593848] mtd_oobtest: attempting to start read past end of OOB [ 657.599953] mtd_oobtest: an error is expected... [ 657.604569] mtd_oobtest: error occurred as expected [ 657.609450] mtd_oobtest: attempting to write past end of device [ 657.615367] mtd_oobtest: an error is expected... [ 657.619990] mtd_oobtest: error occurred as expected [ 657.624864] mtd_oobtest: attempting to read past end of device [ 657.630715] mtd_oobtest: an error is expected... [ 657.635333] mtd_oobtest: error occurred as expected [ 657.641043] mtd_oobtest: attempting to write past end of device [ 657.646966] mtd_oobtest: an error is expected... [ 657.651574] mtd_oobtest: error occurred as expected [ 657.656451] mtd_oobtest: attempting to read past end of device [ 657.662277] mtd_oobtest: an error is expected... [ 657.666901] mtd_oobtest: error occurred as expected [ 657.671774] mtd_oobtest: test 5 of 5 [ 659.382333] mtd_oobtest: writing OOBs of whole device [ 659.388056] mtd_oobtest: written up to eraseblock 0 [ 659.393526] mtd_oobtest: written up to eraseblock 0 [ 659.704525] mtd_oobtest: written up to eraseblock 256 [ 659.710187] mtd_oobtest: written up to eraseblock 256 [ 660.021093] mtd_oobtest: written up to eraseblock 512 [ 660.026752] mtd_oobtest: written up to eraseblock 512 [ 660.338427] mtd_oobtest: written up to eraseblock 768 [ 660.344048] mtd_oobtest: written up to eraseblock 768 [ 660.655718] mtd_oobtest: written up to eraseblock 1024 [ 660.661462] mtd_oobtest: written up to eraseblock 1024 [ 660.970676] mtd_oobtest: written up to eraseblock 1280 [ 660.976386] mtd_oobtest: written up to eraseblock 1280 [ 661.286858] mtd_oobtest: written up to eraseblock 1536 [ 661.292587] mtd_oobtest: written up to eraseblock 1536 [ 661.605397] mtd_oobtest: written up to eraseblock 1792 [ 661.611142] mtd_oobtest: written up to eraseblock 1792 [ 661.918754] mtd_oobtest: written 2046 eraseblocks [ 661.923458] mtd_oobtest: verifying all eraseblocks [ 661.928812] mtd_oobtest: verified up to eraseblock 0 [ 662.072499] mtd_oobtest: verified up to eraseblock 256 [ 662.216152] mtd_oobtest: verified up to eraseblock 512 [ 662.359956] mtd_oobtest: verified up to eraseblock 768 [ 662.503238] mtd_oobtest: verified up to eraseblock 1024 [ 662.646847] mtd_oobtest: verified up to eraseblock 1280 [ 662.790603] mtd_oobtest: verified up to eraseblock 1536 [ 662.934269] mtd_oobtest: verified up to eraseblock 1792 [ 663.076329] mtd_oobtest: verified 2046 eraseblocks [ 663.081114] mtd_oobtest: finished with 0 errors [ 663.085647] ================================================= root@OpenWrt:/lib/modules/6.6.79# insmod mtd_pagetest.ko dev=1 [ 1142.213082] [ 1142.214590] ================================================= [ 1142.220433] mtd_pagetest: MTD device: 1 [ 1142.224278] mtd_pagetest: MTD device size 268304384, eraseblock size 131072, page size 2048, count of eraseblocks 2047, pages per eraseblock 64, OOB size 128 [ 1142.238388] mtd_test: scanning for bad eraseblocks [ 1142.243536] mtd_test: scanned 2047 eraseblocks, 0 are bad [ 1142.248935] mtd_pagetest: erasing whole device [ 1143.962562] mtd_pagetest: erased 2047 eraseblocks [ 1143.967301] mtd_pagetest: writing whole device [ 1144.011729] mtd_pagetest: written up to eraseblock 0 [ 1154.137933] mtd_pagetest: written up to eraseblock 256 [ 1164.265201] mtd_pagetest: written up to eraseblock 512 [ 1174.393365] mtd_pagetest: written up to eraseblock 768 [ 1184.525700] mtd_pagetest: written up to eraseblock 1024 [ 1194.650920] mtd_pagetest: written up to eraseblock 1280 [ 1204.773676] mtd_pagetest: written up to eraseblock 1536 [ 1214.896934] mtd_pagetest: written up to eraseblock 1792 [ 1224.942600] mtd_pagetest: written 2047 eraseblocks [ 1224.947410] mtd_pagetest: verifying all eraseblocks [ 1225.053133] mtd_pagetest: verified up to eraseblock 0 [ 1250.760034] mtd_pagetest: verified up to eraseblock 256 [ 1276.448242] mtd_pagetest: verified up to eraseblock 512 [ 1302.138825] mtd_pagetest: verified up to eraseblock 768 [ 1327.824020] mtd_pagetest: verified up to eraseblock 1024 [ 1353.532178] mtd_pagetest: verified up to eraseblock 1280 [ 1379.234385] mtd_pagetest: verified up to eraseblock 1536 [ 1404.943865] mtd_pagetest: verified up to eraseblock 1792 [ 1430.468816] mtd_pagetest: verified 2047 eraseblocks [ 1430.473702] mtd_pagetest: crosstest [ 1430.477717] mtd_pagetest: reading page at 0x0 [ 1430.482328] mtd_pagetest: reading page at 0xffdf800 [ 1430.487469] mtd_pagetest: reading page at 0x0 [ 1430.492084] mtd_pagetest: verifying pages read at 0x0 match [ 1430.497668] mtd_pagetest: crosstest ok [ 1430.501409] mtd_pagetest: erasecrosstest [ 1430.505323] mtd_pagetest: erasing block 0 [ 1430.511511] mtd_pagetest: writing 1st page of block 0 [ 1430.517166] mtd_pagetest: reading 1st page of block 0 [ 1430.522505] mtd_pagetest: verifying 1st page of block 0 [ 1430.527739] mtd_pagetest: erasing block 0 [ 1430.532565] mtd_pagetest: writing 1st page of block 0 [ 1430.538229] mtd_pagetest: erasing block 2046 [ 1430.544181] mtd_pagetest: reading 1st page of block 0 [ 1430.549498] mtd_pagetest: verifying 1st page of block 0 [ 1430.554718] mtd_pagetest: erasecrosstest ok [ 1430.558900] mtd_pagetest: erasetest [ 1430.562381] mtd_pagetest: erasing block 0 [ 1430.567208] mtd_pagetest: writing 1st page of block 0 [ 1430.572858] mtd_pagetest: erasing block 0 [ 1430.577680] mtd_pagetest: reading 1st page of block 0 [ 1430.582990] mtd_pagetest: verifying 1st page of block 0 is all 0xff [ 1430.589279] mtd_pagetest: erasetest ok [ 1430.593023] mtd_pagetest: finished with 0 errors [ 1430.597651] ================================================= root@OpenWrt:/lib/modules/6.6.79# insmod mtd_readtest.ko dev=1 [ 1478.691648] [ 1478.693158] ================================================= [ 1478.698981] mtd_readtest: MTD device: 1 [ 1478.702829] mtd_readtest: MTD device size 268304384, eraseblock size 131072, page size 2048, count of eraseblocks 2047, pages per eraseblock 64, OOB size 128 [ 1478.716939] mtd_test: scanning for bad eraseblocks [ 1478.722072] mtd_test: scanned 2047 eraseblocks, 0 are bad [ 1478.727475] mtd_readtest: testing page read [ 1548.352125] mtd_readtest: finished [ 1548.355553] ================================================= root@OpenWrt:/lib/modules/6.6.79# insmod mtd_speedtest.ko dev=1 [ 1617.353002] [ 1617.354511] ================================================= [ 1617.360332] mtd_speedtest: MTD device: 1 [ 1617.364258] mtd_speedtest: MTD device size 268304384, eraseblock size 131072, page size 2048, count of eraseblocks 2047, pages per eraseblock 64, OOB size 128 [ 1617.380150] mtd_test: scanning for bad eraseblocks [ 1617.385428] mtd_test: scanned 2047 eraseblocks, 0 are bad [ 1621.021861] mtd_speedtest: testing eraseblock write speed [ 1700.915306] mtd_speedtest: eraseblock write speed is 3279 KiB/s [ 1700.921250] mtd_speedtest: testing eraseblock read speed [ 1734.931886] mtd_speedtest: eraseblock read speed is 7705 KiB/s [ 1738.682742] mtd_speedtest: testing page write speed [ 1818.818644] mtd_speedtest: page write speed is 3269 KiB/s [ 1818.824058] mtd_speedtest: testing page read speed [ 1852.913595] mtd_speedtest: page read speed is 7687 KiB/s [ 1856.674492] mtd_speedtest: testing 2 page write speed [ 1936.437284] mtd_speedtest: 2 page write speed is 3285 KiB/s [ 1936.442869] mtd_speedtest: testing 2 page read speed [ 1970.498124] mtd_speedtest: 2 page read speed is 7694 KiB/s [ 1970.503624] mtd_speedtest: Testing erase speed [ 1974.343389] mtd_speedtest: erase speed is 68316 KiB/s [ 1974.348479] mtd_speedtest: Testing 2x multi-block erase speed [ 1976.068855] mtd_speedtest: 2x multi-block erase speed is 152811 KiB/s [ 1976.075309] mtd_speedtest: Testing 4x multi-block erase speed [ 1977.790232] mtd_speedtest: 4x multi-block erase speed is 153301 KiB/s [ 1977.796693] mtd_speedtest: Testing 8x multi-block erase speed [ 1979.511905] mtd_speedtest: 8x multi-block erase speed is 153273 KiB/s [ 1979.518367] mtd_speedtest: Testing 16x multi-block erase speed [ 1981.230700] mtd_speedtest: 16x multi-block erase speed is 153539 KiB/s [ 1981.237249] mtd_speedtest: Testing 32x multi-block erase speed [ 1982.948381] mtd_speedtest: 32x multi-block erase speed is 153648 KiB/s [ 1982.954918] mtd_speedtest: Testing 64x multi-block erase speed [ 1984.665992] mtd_speedtest: 64x multi-block erase speed is 153655 KiB/s [ 1984.672531] mtd_speedtest: finished [ 1984.676054] ================================================= root@OpenWrt:/lib/modules/6.6.79# insmod mtd_stresstest.ko dev=1 [ 2190.651750] [ 2190.653263] ================================================= [ 2190.659087] mtd_stresstest: MTD device: 1 [ 2190.663105] mtd_stresstest: MTD device size 268304384, eraseblock size 131072, page size 2048, count of eraseblocks 2047, pages per eraseblock 64, OOB size 128 [ 2190.679846] mtd_test: scanning for bad eraseblocks [ 2190.684981] mtd_test: scanned 2047 eraseblocks, 0 are bad [ 2190.690389] mtd_stresstest: doing operations [ 2190.694655] mtd_stresstest: 0 operations done [ 2214.262705] mtd_stresstest: 1024 operations done [ 2239.019612] mtd_stresstest: 2048 operations done [ 2262.820899] mtd_stresstest: 3072 operations done [ 2285.061376] mtd_stresstest: 4096 operations done [ 2308.297322] mtd_stresstest: 5120 operations done [ 2330.530459] mtd_stresstest: 6144 operations done [ 2352.651759] mtd_stresstest: 7168 operations done [ 2375.188275] mtd_stresstest: 8192 operations done [ 2397.738174] mtd_stresstest: 9216 operations done [ 2414.792572] mtd_stresstest: finished, 10000 operations done [ 2414.798257] ================================================= Speed test of original driver (with patch to fix support of flashes with more than one plane per lun) root@OpenWrt:/lib/modules/6.6.79# insmod mtd_speedtest.ko dev=1 [ 2894.142208] [ 2894.143719] ================================================= [ 2894.149556] mtd_speedtest: MTD device: 1 [ 2894.153486] mtd_speedtest: MTD device size 268304384, eraseblock size 131072, page size 2048, count of eraseblocks 2047, pages per eraseblock 64, OOB size 128 [ 2894.168888] mtd_test: scanning for bad eraseblocks [ 2894.174023] mtd_test: scanned 2047 eraseblocks, 0 are bad [ 2897.500416] mtd_speedtest: testing eraseblock write speed [ 2977.807233] mtd_speedtest: eraseblock write speed is 3262 KiB/s [ 2977.813171] mtd_speedtest: testing eraseblock read speed [ 3013.906597] mtd_speedtest: eraseblock read speed is 7260 KiB/s [ 3017.440320] mtd_speedtest: testing page write speed [ 3097.833394] mtd_speedtest: page write speed is 3259 KiB/s [ 3097.838812] mtd_speedtest: testing page read speed [ 3134.004981] mtd_speedtest: page read speed is 7245 KiB/s [ 3137.538423] mtd_speedtest: testing 2 page write speed [ 3217.906288] mtd_speedtest: 2 page write speed is 3260 KiB/s [ 3217.911883] mtd_speedtest: testing 2 page read speed [ 3254.049757] mtd_speedtest: 2 page read speed is 7251 KiB/s [ 3254.055254] mtd_speedtest: Testing erase speed [ 3257.599146] mtd_speedtest: erase speed is 74027 KiB/s [ 3257.604213] mtd_speedtest: Testing 2x multi-block erase speed [ 3259.320945] mtd_speedtest: 2x multi-block erase speed is 153139 KiB/s [ 3259.327413] mtd_speedtest: Testing 4x multi-block erase speed [ 3261.044585] mtd_speedtest: 4x multi-block erase speed is 153098 KiB/s [ 3261.051047] mtd_speedtest: Testing 8x multi-block erase speed [ 3262.786520] mtd_speedtest: 8x multi-block erase speed is 151479 KiB/s [ 3262.792979] mtd_speedtest: Testing 16x multi-block erase speed [ 3264.509898] mtd_speedtest: 16x multi-block erase speed is 153130 KiB/s [ 3264.516454] mtd_speedtest: Testing 32x multi-block erase speed [ 3266.233403] mtd_speedtest: 32x multi-block erase speed is 153125 KiB/s [ 3266.239961] mtd_speedtest: Testing 64x multi-block erase speed [ 3267.957985] mtd_speedtest: 64x multi-block erase speed is 153029 KiB/s [ 3267.964525] mtd_speedtest: finished [ 3267.968039] ================================================= It looks like a patched driver is a bit faster write speed: 3260 KiB/s vs 3277 KiB/s read speed: 7252 KiB/s vs 7695 KiB/s
This commit is contained in:
@@ -147,6 +147,8 @@
|
||||
#define SPI_NFI_CUS_SEC_SIZE_EN BIT(16)
|
||||
|
||||
#define REG_SPI_NFI_RD_CTL2 0x0510
|
||||
#define SPI_NFI_DATA_READ_CMD GENMASK(7, 0)
|
||||
|
||||
#define REG_SPI_NFI_RD_CTL3 0x0514
|
||||
|
||||
#define REG_SPI_NFI_PG_CTL1 0x0524
|
||||
@@ -179,7 +181,9 @@
|
||||
#define SPI_NAND_OP_READ_FROM_CACHE_SINGLE 0x03
|
||||
#define SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST 0x0b
|
||||
#define SPI_NAND_OP_READ_FROM_CACHE_DUAL 0x3b
|
||||
#define SPI_NAND_OP_READ_FROM_CACHE_DUALIO 0xbb
|
||||
#define SPI_NAND_OP_READ_FROM_CACHE_QUAD 0x6b
|
||||
#define SPI_NAND_OP_READ_FROM_CACHE_QUADIO 0xeb
|
||||
#define SPI_NAND_OP_WRITE_ENABLE 0x06
|
||||
#define SPI_NAND_OP_WRITE_DISABLE 0x04
|
||||
#define SPI_NAND_OP_PROGRAM_LOAD_SINGLE 0x02
|
||||
@@ -192,6 +196,14 @@
|
||||
#define SPI_NAND_OP_RESET 0xff
|
||||
#define SPI_NAND_OP_DIE_SELECT 0xc2
|
||||
|
||||
/* SNAND FIFO commands */
|
||||
#define SNAND_FIFO_TX_BUSWIDTH_SINGLE 0x08
|
||||
#define SNAND_FIFO_TX_BUSWIDTH_DUAL 0x09
|
||||
#define SNAND_FIFO_TX_BUSWIDTH_QUAD 0x0a
|
||||
#define SNAND_FIFO_RX_BUSWIDTH_SINGLE 0x0c
|
||||
#define SNAND_FIFO_RX_BUSWIDTH_DUAL 0x0e
|
||||
#define SNAND_FIFO_RX_BUSWIDTH_QUAD 0x0f
|
||||
|
||||
#define SPI_NAND_CACHE_SIZE (SZ_4K + SZ_256)
|
||||
#define SPI_MAX_TRANSFER_SIZE 511
|
||||
|
||||
@@ -211,13 +223,6 @@ struct airoha_snand_ctrl {
|
||||
struct regmap *regmap_ctrl;
|
||||
struct regmap *regmap_nfi;
|
||||
struct clk *spi_clk;
|
||||
|
||||
struct {
|
||||
size_t page_size;
|
||||
size_t sec_size;
|
||||
u8 sec_num;
|
||||
u8 spare_size;
|
||||
} nfi_cfg;
|
||||
};
|
||||
|
||||
static int airoha_snand_set_fifo_op(struct airoha_snand_ctrl *as_ctrl,
|
||||
@@ -387,10 +392,26 @@ static int airoha_snand_set_mode(struct airoha_snand_ctrl *as_ctrl,
|
||||
return regmap_write(as_ctrl->regmap_ctrl, REG_SPI_CTRL_DUMMY, 0);
|
||||
}
|
||||
|
||||
static int airoha_snand_write_data(struct airoha_snand_ctrl *as_ctrl, u8 cmd,
|
||||
const u8 *data, int len)
|
||||
static int airoha_snand_write_data(struct airoha_snand_ctrl *as_ctrl,
|
||||
const u8 *data, int len, int buswidth)
|
||||
{
|
||||
int i, data_len;
|
||||
u8 cmd;
|
||||
|
||||
switch (buswidth) {
|
||||
case 0:
|
||||
case 1:
|
||||
cmd = SNAND_FIFO_TX_BUSWIDTH_SINGLE;
|
||||
break;
|
||||
case 2:
|
||||
cmd = SNAND_FIFO_TX_BUSWIDTH_DUAL;
|
||||
break;
|
||||
case 4:
|
||||
cmd = SNAND_FIFO_TX_BUSWIDTH_QUAD;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i += data_len) {
|
||||
int err;
|
||||
@@ -409,16 +430,32 @@ static int airoha_snand_write_data(struct airoha_snand_ctrl *as_ctrl, u8 cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int airoha_snand_read_data(struct airoha_snand_ctrl *as_ctrl, u8 *data,
|
||||
int len)
|
||||
static int airoha_snand_read_data(struct airoha_snand_ctrl *as_ctrl,
|
||||
u8 *data, int len, int buswidth)
|
||||
{
|
||||
int i, data_len;
|
||||
u8 cmd;
|
||||
|
||||
switch (buswidth) {
|
||||
case 0:
|
||||
case 1:
|
||||
cmd = SNAND_FIFO_RX_BUSWIDTH_SINGLE;
|
||||
break;
|
||||
case 2:
|
||||
cmd = SNAND_FIFO_RX_BUSWIDTH_DUAL;
|
||||
break;
|
||||
case 4:
|
||||
cmd = SNAND_FIFO_RX_BUSWIDTH_QUAD;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i += data_len) {
|
||||
int err;
|
||||
|
||||
data_len = min(len - i, SPI_MAX_TRANSFER_SIZE);
|
||||
err = airoha_snand_set_fifo_op(as_ctrl, 0xc, data_len);
|
||||
err = airoha_snand_set_fifo_op(as_ctrl, cmd, data_len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -446,92 +483,6 @@ static int airoha_snand_nfi_init(struct airoha_snand_ctrl *as_ctrl)
|
||||
SPI_NFI_ALL_IRQ_EN, SPI_NFI_AHB_DONE_EN);
|
||||
}
|
||||
|
||||
static int airoha_snand_nfi_config(struct airoha_snand_ctrl *as_ctrl)
|
||||
{
|
||||
int err;
|
||||
u32 val;
|
||||
|
||||
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
|
||||
SPI_NFI_FIFO_FLUSH | SPI_NFI_RST);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* auto FDM */
|
||||
err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
|
||||
SPI_NFI_AUTO_FDM_EN);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* HW ECC */
|
||||
err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
|
||||
SPI_NFI_HW_ECC_EN);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* DMA Burst */
|
||||
err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
|
||||
SPI_NFI_DMA_BURST_EN);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* page format */
|
||||
switch (as_ctrl->nfi_cfg.spare_size) {
|
||||
case 26:
|
||||
val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x1);
|
||||
break;
|
||||
case 27:
|
||||
val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x2);
|
||||
break;
|
||||
case 28:
|
||||
val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x3);
|
||||
break;
|
||||
default:
|
||||
val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x0);
|
||||
break;
|
||||
}
|
||||
|
||||
err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_PAGEFMT,
|
||||
SPI_NFI_SPARE_SIZE, val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (as_ctrl->nfi_cfg.page_size) {
|
||||
case 2048:
|
||||
val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x1);
|
||||
break;
|
||||
case 4096:
|
||||
val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x2);
|
||||
break;
|
||||
default:
|
||||
val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x0);
|
||||
break;
|
||||
}
|
||||
|
||||
err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_PAGEFMT,
|
||||
SPI_NFI_PAGE_SIZE, val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* sec num */
|
||||
val = FIELD_PREP(SPI_NFI_SEC_NUM, as_ctrl->nfi_cfg.sec_num);
|
||||
err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
|
||||
SPI_NFI_SEC_NUM, val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* enable cust sec size */
|
||||
err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE,
|
||||
SPI_NFI_CUS_SEC_SIZE_EN);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* set cust sec size */
|
||||
val = FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, as_ctrl->nfi_cfg.sec_size);
|
||||
return regmap_update_bits(as_ctrl->regmap_nfi,
|
||||
REG_SPI_NFI_SECCUS_SIZE,
|
||||
SPI_NFI_CUS_SEC_SIZE, val);
|
||||
}
|
||||
|
||||
static bool airoha_snand_is_page_ops(const struct spi_mem_op *op)
|
||||
{
|
||||
if (op->addr.nbytes != 2)
|
||||
@@ -564,33 +515,6 @@ static bool airoha_snand_is_page_ops(const struct spi_mem_op *op)
|
||||
}
|
||||
}
|
||||
|
||||
static int airoha_snand_adjust_op_size(struct spi_mem *mem,
|
||||
struct spi_mem_op *op)
|
||||
{
|
||||
size_t max_len;
|
||||
|
||||
if (airoha_snand_is_page_ops(op)) {
|
||||
struct airoha_snand_ctrl *as_ctrl;
|
||||
|
||||
as_ctrl = spi_controller_get_devdata(mem->spi->controller);
|
||||
max_len = as_ctrl->nfi_cfg.sec_size;
|
||||
max_len += as_ctrl->nfi_cfg.spare_size;
|
||||
max_len *= as_ctrl->nfi_cfg.sec_num;
|
||||
|
||||
if (op->data.nbytes > max_len)
|
||||
op->data.nbytes = max_len;
|
||||
} else {
|
||||
max_len = 1 + op->addr.nbytes + op->dummy.nbytes;
|
||||
if (max_len >= 160)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (op->data.nbytes > 160 - max_len)
|
||||
op->data.nbytes = 160 - max_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool airoha_snand_supports_op(struct spi_mem *mem,
|
||||
const struct spi_mem_op *op)
|
||||
{
|
||||
@@ -618,6 +542,10 @@ static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc)
|
||||
if (desc->info.offset + desc->info.length > U32_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
/* continuous reading is not supported */
|
||||
if (desc->info.length > SPI_NAND_CACHE_SIZE)
|
||||
return -E2BIG;
|
||||
|
||||
if (!airoha_snand_supports_op(desc->mem, &desc->info.op_tmpl))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
@@ -627,40 +555,97 @@ static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc)
|
||||
static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
|
||||
u64 offs, size_t len, void *buf)
|
||||
{
|
||||
struct spi_mem_op *op = &desc->info.op_tmpl;
|
||||
struct spi_device *spi = desc->mem->spi;
|
||||
struct airoha_snand_ctrl *as_ctrl;
|
||||
u8 *txrx_buf = spi_get_ctldata(spi);
|
||||
dma_addr_t dma_addr;
|
||||
u32 val, rd_mode;
|
||||
u32 val, rd_mode, opcode;
|
||||
size_t bytes;
|
||||
int err;
|
||||
|
||||
switch (op->cmd.opcode) {
|
||||
as_ctrl = spi_controller_get_devdata(spi->controller);
|
||||
|
||||
/* minimum oob size is 64 */
|
||||
bytes = round_up(offs + len, 64);
|
||||
|
||||
/*
|
||||
* DUALIO and QUADIO opcodes are not supported by the spi controller,
|
||||
* replace them with supported opcodes.
|
||||
*/
|
||||
opcode = desc->info.op_tmpl.cmd.opcode;
|
||||
switch (opcode) {
|
||||
case SPI_NAND_OP_READ_FROM_CACHE_SINGLE:
|
||||
case SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST:
|
||||
rd_mode = 0;
|
||||
break;
|
||||
case SPI_NAND_OP_READ_FROM_CACHE_DUAL:
|
||||
case SPI_NAND_OP_READ_FROM_CACHE_DUALIO:
|
||||
opcode = SPI_NAND_OP_READ_FROM_CACHE_DUAL;
|
||||
rd_mode = 1;
|
||||
break;
|
||||
case SPI_NAND_OP_READ_FROM_CACHE_QUAD:
|
||||
case SPI_NAND_OP_READ_FROM_CACHE_QUADIO:
|
||||
opcode = SPI_NAND_OP_READ_FROM_CACHE_QUAD;
|
||||
rd_mode = 2;
|
||||
break;
|
||||
default:
|
||||
rd_mode = 0;
|
||||
break;
|
||||
/* unknown opcode */
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
as_ctrl = spi_controller_get_devdata(spi->controller);
|
||||
err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = airoha_snand_nfi_config(as_ctrl);
|
||||
/* NFI reset */
|
||||
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
|
||||
SPI_NFI_FIFO_FLUSH | SPI_NFI_RST);
|
||||
if (err)
|
||||
return err;
|
||||
goto error_dma_mode_off;
|
||||
|
||||
/* NFI configure:
|
||||
* - No AutoFDM (custom sector size (SECCUS) register will be used)
|
||||
* - No SoC's hardware ECC (flash internal ECC will be used)
|
||||
* - Use burst mode (faster, but requires 16 byte alignment for addresses)
|
||||
* - Setup for reading (SPI_NFI_READ_MODE)
|
||||
* - Setup reading command: FIELD_PREP(SPI_NFI_OPMODE, 6)
|
||||
* - Use DMA instead of PIO for data reading
|
||||
*/
|
||||
err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
|
||||
SPI_NFI_DMA_MODE |
|
||||
SPI_NFI_READ_MODE |
|
||||
SPI_NFI_DMA_BURST_EN |
|
||||
SPI_NFI_HW_ECC_EN |
|
||||
SPI_NFI_AUTO_FDM_EN |
|
||||
SPI_NFI_OPMODE,
|
||||
SPI_NFI_DMA_MODE |
|
||||
SPI_NFI_READ_MODE |
|
||||
SPI_NFI_DMA_BURST_EN |
|
||||
FIELD_PREP(SPI_NFI_OPMODE, 6));
|
||||
if (err)
|
||||
goto error_dma_mode_off;
|
||||
|
||||
/* Set number of sector will be read */
|
||||
err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
|
||||
SPI_NFI_SEC_NUM,
|
||||
FIELD_PREP(SPI_NFI_SEC_NUM, 1));
|
||||
if (err)
|
||||
goto error_dma_mode_off;
|
||||
|
||||
/* Set custom sector size */
|
||||
err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE,
|
||||
SPI_NFI_CUS_SEC_SIZE |
|
||||
SPI_NFI_CUS_SEC_SIZE_EN,
|
||||
FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, bytes) |
|
||||
SPI_NFI_CUS_SEC_SIZE_EN);
|
||||
if (err)
|
||||
goto error_dma_mode_off;
|
||||
|
||||
dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE,
|
||||
DMA_FROM_DEVICE);
|
||||
err = dma_mapping_error(as_ctrl->dev, dma_addr);
|
||||
if (err)
|
||||
return err;
|
||||
goto error_dma_mode_off;
|
||||
|
||||
/* set dma addr */
|
||||
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR,
|
||||
@@ -668,18 +653,24 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
|
||||
if (err)
|
||||
goto error_dma_unmap;
|
||||
|
||||
/* set cust sec size */
|
||||
val = as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num;
|
||||
val = FIELD_PREP(SPI_NFI_READ_DATA_BYTE_NUM, val);
|
||||
/*
|
||||
* Setup transfer length
|
||||
* ---------------------
|
||||
* The following rule MUST be met:
|
||||
* transfer_length =
|
||||
* = NFI_SNF_MISC_CTL2.read_data_byte_number =
|
||||
* = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size
|
||||
*/
|
||||
err = regmap_update_bits(as_ctrl->regmap_nfi,
|
||||
REG_SPI_NFI_SNF_MISC_CTL2,
|
||||
SPI_NFI_READ_DATA_BYTE_NUM, val);
|
||||
SPI_NFI_READ_DATA_BYTE_NUM,
|
||||
FIELD_PREP(SPI_NFI_READ_DATA_BYTE_NUM, bytes));
|
||||
if (err)
|
||||
goto error_dma_unmap;
|
||||
|
||||
/* set read command */
|
||||
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL2,
|
||||
op->cmd.opcode);
|
||||
FIELD_PREP(SPI_NFI_DATA_READ_CMD, opcode));
|
||||
if (err)
|
||||
goto error_dma_unmap;
|
||||
|
||||
@@ -689,20 +680,9 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
|
||||
if (err)
|
||||
goto error_dma_unmap;
|
||||
|
||||
/* set read addr */
|
||||
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL3, 0x0);
|
||||
if (err)
|
||||
goto error_dma_unmap;
|
||||
|
||||
/* set nfi read */
|
||||
err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
|
||||
SPI_NFI_OPMODE,
|
||||
FIELD_PREP(SPI_NFI_OPMODE, 6));
|
||||
if (err)
|
||||
goto error_dma_unmap;
|
||||
|
||||
err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
|
||||
SPI_NFI_READ_MODE | SPI_NFI_DMA_MODE);
|
||||
/* set read addr: zero page offset + descriptor read offset */
|
||||
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL3,
|
||||
desc->info.offset);
|
||||
if (err)
|
||||
goto error_dma_unmap;
|
||||
|
||||
@@ -710,7 +690,7 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
|
||||
if (err)
|
||||
goto error_dma_unmap;
|
||||
|
||||
/* trigger dma start read */
|
||||
/* trigger dma reading */
|
||||
err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
|
||||
SPI_NFI_RD_TRIG);
|
||||
if (err)
|
||||
@@ -760,87 +740,138 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
|
||||
error_dma_unmap:
|
||||
dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE,
|
||||
DMA_FROM_DEVICE);
|
||||
error_dma_mode_off:
|
||||
airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL);
|
||||
return err;
|
||||
}
|
||||
|
||||
static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
|
||||
u64 offs, size_t len, const void *buf)
|
||||
{
|
||||
struct spi_mem_op *op = &desc->info.op_tmpl;
|
||||
struct spi_device *spi = desc->mem->spi;
|
||||
u8 *txrx_buf = spi_get_ctldata(spi);
|
||||
struct airoha_snand_ctrl *as_ctrl;
|
||||
dma_addr_t dma_addr;
|
||||
u32 wr_mode, val;
|
||||
u32 wr_mode, val, opcode;
|
||||
size_t bytes;
|
||||
int err;
|
||||
|
||||
as_ctrl = spi_controller_get_devdata(spi->controller);
|
||||
err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL);
|
||||
|
||||
/* minimum oob size is 64 */
|
||||
bytes = round_up(offs + len, 64);
|
||||
|
||||
opcode = desc->info.op_tmpl.cmd.opcode;
|
||||
switch (opcode) {
|
||||
case SPI_NAND_OP_PROGRAM_LOAD_SINGLE:
|
||||
case SPI_NAND_OP_PROGRAM_LOAD_RAMDOM_SINGLE:
|
||||
wr_mode = 0;
|
||||
break;
|
||||
case SPI_NAND_OP_PROGRAM_LOAD_QUAD:
|
||||
case SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD:
|
||||
wr_mode = 2;
|
||||
break;
|
||||
default:
|
||||
/* unknown opcode */
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (offs > 0)
|
||||
memset(txrx_buf, 0xff, offs);
|
||||
memcpy(txrx_buf + offs, buf, len);
|
||||
if (bytes > offs + len)
|
||||
memset(txrx_buf + offs + len, 0xff, bytes - offs - len);
|
||||
|
||||
err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
memcpy(txrx_buf + offs, buf, len);
|
||||
/* NFI reset */
|
||||
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
|
||||
SPI_NFI_FIFO_FLUSH | SPI_NFI_RST);
|
||||
if (err)
|
||||
goto error_dma_mode_off;
|
||||
|
||||
/*
|
||||
* NFI configure:
|
||||
* - No AutoFDM (custom sector size (SECCUS) register will be used)
|
||||
* - No SoC's hardware ECC (flash internal ECC will be used)
|
||||
* - Use burst mode (faster, but requires 16 byte alignment for addresses)
|
||||
* - Setup for writing (SPI_NFI_READ_MODE bit is cleared)
|
||||
* - Setup writing command: FIELD_PREP(SPI_NFI_OPMODE, 3)
|
||||
* - Use DMA instead of PIO for data writing
|
||||
*/
|
||||
err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
|
||||
SPI_NFI_DMA_MODE |
|
||||
SPI_NFI_READ_MODE |
|
||||
SPI_NFI_DMA_BURST_EN |
|
||||
SPI_NFI_HW_ECC_EN |
|
||||
SPI_NFI_AUTO_FDM_EN |
|
||||
SPI_NFI_OPMODE,
|
||||
SPI_NFI_DMA_MODE |
|
||||
SPI_NFI_DMA_BURST_EN |
|
||||
FIELD_PREP(SPI_NFI_OPMODE, 3));
|
||||
if (err)
|
||||
goto error_dma_mode_off;
|
||||
|
||||
/* Set number of sector will be written */
|
||||
err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
|
||||
SPI_NFI_SEC_NUM,
|
||||
FIELD_PREP(SPI_NFI_SEC_NUM, 1));
|
||||
if (err)
|
||||
goto error_dma_mode_off;
|
||||
|
||||
/* Set custom sector size */
|
||||
err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE,
|
||||
SPI_NFI_CUS_SEC_SIZE |
|
||||
SPI_NFI_CUS_SEC_SIZE_EN,
|
||||
FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, bytes) |
|
||||
SPI_NFI_CUS_SEC_SIZE_EN);
|
||||
if (err)
|
||||
goto error_dma_mode_off;
|
||||
|
||||
dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE,
|
||||
DMA_TO_DEVICE);
|
||||
err = dma_mapping_error(as_ctrl->dev, dma_addr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA);
|
||||
if (err < 0)
|
||||
goto error_dma_unmap;
|
||||
|
||||
err = airoha_snand_nfi_config(as_ctrl);
|
||||
if (err)
|
||||
goto error_dma_unmap;
|
||||
|
||||
if (op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_QUAD ||
|
||||
op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD)
|
||||
wr_mode = BIT(1);
|
||||
else
|
||||
wr_mode = 0;
|
||||
goto error_dma_mode_off;
|
||||
|
||||
/* set dma addr */
|
||||
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR,
|
||||
dma_addr);
|
||||
if (err)
|
||||
goto error_dma_unmap;
|
||||
|
||||
val = FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM,
|
||||
as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num);
|
||||
/*
|
||||
* Setup transfer length
|
||||
* ---------------------
|
||||
* The following rule MUST be met:
|
||||
* transfer_length =
|
||||
* = NFI_SNF_MISC_CTL2.write_data_byte_number =
|
||||
* = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size
|
||||
*/
|
||||
err = regmap_update_bits(as_ctrl->regmap_nfi,
|
||||
REG_SPI_NFI_SNF_MISC_CTL2,
|
||||
SPI_NFI_PROG_LOAD_BYTE_NUM, val);
|
||||
SPI_NFI_PROG_LOAD_BYTE_NUM,
|
||||
FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM, bytes));
|
||||
if (err)
|
||||
goto error_dma_unmap;
|
||||
|
||||
/* set write command */
|
||||
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL1,
|
||||
FIELD_PREP(SPI_NFI_PG_LOAD_CMD,
|
||||
op->cmd.opcode));
|
||||
FIELD_PREP(SPI_NFI_PG_LOAD_CMD, opcode));
|
||||
if (err)
|
||||
goto error_dma_unmap;
|
||||
|
||||
/* set write mode */
|
||||
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL,
|
||||
FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, wr_mode));
|
||||
if (err)
|
||||
goto error_dma_unmap;
|
||||
|
||||
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL2, 0x0);
|
||||
if (err)
|
||||
goto error_dma_unmap;
|
||||
|
||||
err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
|
||||
SPI_NFI_READ_MODE);
|
||||
if (err)
|
||||
goto error_dma_unmap;
|
||||
|
||||
err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
|
||||
SPI_NFI_OPMODE,
|
||||
FIELD_PREP(SPI_NFI_OPMODE, 3));
|
||||
if (err)
|
||||
goto error_dma_unmap;
|
||||
|
||||
err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
|
||||
SPI_NFI_DMA_MODE);
|
||||
/* set write addr: zero page offset + descriptor write offset */
|
||||
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL2,
|
||||
desc->info.offset);
|
||||
if (err)
|
||||
goto error_dma_unmap;
|
||||
|
||||
@@ -848,6 +879,7 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
|
||||
if (err)
|
||||
goto error_dma_unmap;
|
||||
|
||||
/* trigger dma writing */
|
||||
err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
|
||||
SPI_NFI_WR_TRIG);
|
||||
if (err)
|
||||
@@ -892,18 +924,36 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
|
||||
error_dma_unmap:
|
||||
dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE,
|
||||
DMA_TO_DEVICE);
|
||||
error_dma_mode_off:
|
||||
airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int airoha_snand_exec_op(struct spi_mem *mem,
|
||||
const struct spi_mem_op *op)
|
||||
{
|
||||
u8 data[8], cmd, opcode = op->cmd.opcode;
|
||||
struct airoha_snand_ctrl *as_ctrl;
|
||||
int op_len, addr_len, dummy_len;
|
||||
u8 buf[20], *data;
|
||||
int i, err;
|
||||
|
||||
as_ctrl = spi_controller_get_devdata(mem->spi->controller);
|
||||
|
||||
op_len = op->cmd.nbytes;
|
||||
addr_len = op->addr.nbytes;
|
||||
dummy_len = op->dummy.nbytes;
|
||||
|
||||
if (op_len + dummy_len + addr_len > sizeof(buf))
|
||||
return -EIO;
|
||||
|
||||
data = buf;
|
||||
for (i = 0; i < op_len; i++)
|
||||
*data++ = op->cmd.opcode >> (8 * (op_len - i - 1));
|
||||
for (i = 0; i < addr_len; i++)
|
||||
*data++ = op->addr.val >> (8 * (addr_len - i - 1));
|
||||
for (i = 0; i < dummy_len; i++)
|
||||
*data++ = 0xff;
|
||||
|
||||
/* switch to manual mode */
|
||||
err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL);
|
||||
if (err < 0)
|
||||
@@ -914,40 +964,40 @@ static int airoha_snand_exec_op(struct spi_mem *mem,
|
||||
return err;
|
||||
|
||||
/* opcode */
|
||||
err = airoha_snand_write_data(as_ctrl, 0x8, &opcode, sizeof(opcode));
|
||||
data = buf;
|
||||
err = airoha_snand_write_data(as_ctrl, data, op_len,
|
||||
op->cmd.buswidth);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* addr part */
|
||||
cmd = opcode == SPI_NAND_OP_GET_FEATURE ? 0x11 : 0x8;
|
||||
put_unaligned_be64(op->addr.val, data);
|
||||
|
||||
for (i = ARRAY_SIZE(data) - op->addr.nbytes;
|
||||
i < ARRAY_SIZE(data); i++) {
|
||||
err = airoha_snand_write_data(as_ctrl, cmd, &data[i],
|
||||
sizeof(data[0]));
|
||||
data += op_len;
|
||||
if (addr_len) {
|
||||
err = airoha_snand_write_data(as_ctrl, data, addr_len,
|
||||
op->addr.buswidth);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* dummy */
|
||||
data[0] = 0xff;
|
||||
for (i = 0; i < op->dummy.nbytes; i++) {
|
||||
err = airoha_snand_write_data(as_ctrl, 0x8, &data[0],
|
||||
sizeof(data[0]));
|
||||
data += addr_len;
|
||||
if (dummy_len) {
|
||||
err = airoha_snand_write_data(as_ctrl, data, dummy_len,
|
||||
op->dummy.buswidth);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* data */
|
||||
if (op->data.dir == SPI_MEM_DATA_IN) {
|
||||
err = airoha_snand_read_data(as_ctrl, op->data.buf.in,
|
||||
op->data.nbytes);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
err = airoha_snand_write_data(as_ctrl, 0x8, op->data.buf.out,
|
||||
op->data.nbytes);
|
||||
if (op->data.nbytes) {
|
||||
if (op->data.dir == SPI_MEM_DATA_IN)
|
||||
err = airoha_snand_read_data(as_ctrl, op->data.buf.in,
|
||||
op->data.nbytes,
|
||||
op->data.buswidth);
|
||||
else
|
||||
err = airoha_snand_write_data(as_ctrl, op->data.buf.out,
|
||||
op->data.nbytes,
|
||||
op->data.buswidth);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@@ -956,7 +1006,6 @@ static int airoha_snand_exec_op(struct spi_mem *mem,
|
||||
}
|
||||
|
||||
static const struct spi_controller_mem_ops airoha_snand_mem_ops = {
|
||||
.adjust_op_size = airoha_snand_adjust_op_size,
|
||||
.supports_op = airoha_snand_supports_op,
|
||||
.exec_op = airoha_snand_exec_op,
|
||||
.dirmap_create = airoha_snand_dirmap_create,
|
||||
@@ -981,36 +1030,6 @@ static int airoha_snand_setup(struct spi_device *spi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int airoha_snand_nfi_setup(struct airoha_snand_ctrl *as_ctrl)
|
||||
{
|
||||
u32 val, sec_size, sec_num;
|
||||
int err;
|
||||
|
||||
err = regmap_read(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
sec_num = FIELD_GET(SPI_NFI_SEC_NUM, val);
|
||||
|
||||
err = regmap_read(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, &val);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
sec_size = FIELD_GET(SPI_NFI_CUS_SEC_SIZE, val);
|
||||
|
||||
/* init default value */
|
||||
as_ctrl->nfi_cfg.sec_size = sec_size;
|
||||
as_ctrl->nfi_cfg.sec_num = sec_num;
|
||||
as_ctrl->nfi_cfg.page_size = round_down(sec_size * sec_num, 1024);
|
||||
as_ctrl->nfi_cfg.spare_size = 16;
|
||||
|
||||
err = airoha_snand_nfi_init(as_ctrl);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return airoha_snand_nfi_config(as_ctrl);
|
||||
}
|
||||
|
||||
static const struct regmap_config spi_ctrl_regmap_config = {
|
||||
.name = "ctrl",
|
||||
.reg_bits = 32,
|
||||
@@ -1084,7 +1103,7 @@ static int airoha_snand_probe(struct platform_device *pdev)
|
||||
ctrl->setup = airoha_snand_setup;
|
||||
device_set_node(&ctrl->dev, dev_fwnode(dev));
|
||||
|
||||
err = airoha_snand_nfi_setup(as_ctrl);
|
||||
err = airoha_snand_nfi_init(as_ctrl);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
||||
@@ -286,7 +286,7 @@ static int aml_sfc_set_bus_width(struct aml_sfc *sfc, u8 buswidth, u32 mask)
|
||||
|
||||
for (i = 0; i <= LANE_MAX; i++) {
|
||||
if (buswidth == 1 << i) {
|
||||
conf = i << __bf_shf(mask);
|
||||
conf = i << __ffs(mask);
|
||||
return regmap_update_bits(sfc->regmap_base, SFC_SPI_CFG,
|
||||
mask, conf);
|
||||
}
|
||||
@@ -566,7 +566,7 @@ static int aml_sfc_raw_io_op(struct aml_sfc *sfc, const struct spi_mem_op *op)
|
||||
if (!op->data.nbytes)
|
||||
goto end_xfer;
|
||||
|
||||
conf = (op->data.nbytes >> RAW_SIZE_BW) << __bf_shf(RAW_EXT_SIZE);
|
||||
conf = (op->data.nbytes >> RAW_SIZE_BW) << __ffs(RAW_EXT_SIZE);
|
||||
ret = regmap_update_bits(sfc->regmap_base, SFC_SPI_CFG, RAW_EXT_SIZE, conf);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
@@ -1995,7 +1995,7 @@ static int cqspi_probe(struct platform_device *pdev)
|
||||
if (cqspi->use_direct_mode) {
|
||||
ret = cqspi_request_mmap_dma(cqspi);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
goto probe_setup_failed;
|
||||
goto probe_dma_failed;
|
||||
}
|
||||
|
||||
if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
|
||||
@@ -2019,9 +2019,10 @@ static int cqspi_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
probe_setup_failed:
|
||||
cqspi_controller_enable(cqspi, 0);
|
||||
if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM)))
|
||||
pm_runtime_disable(dev);
|
||||
probe_dma_failed:
|
||||
cqspi_controller_enable(cqspi, 0);
|
||||
probe_reset_failed:
|
||||
if (cqspi->is_jh7110)
|
||||
cqspi_jh7110_disable_clk(pdev, cqspi);
|
||||
|
||||
@@ -404,6 +404,10 @@ struct nxp_fspi {
|
||||
#define FSPI_NEED_INIT BIT(0)
|
||||
#define FSPI_DTR_MODE BIT(1)
|
||||
int flags;
|
||||
/* save the previous operation clock rate */
|
||||
unsigned long pre_op_rate;
|
||||
/* the max clock rate fspi output to device */
|
||||
unsigned long max_rate;
|
||||
};
|
||||
|
||||
static inline int needs_ip_only(struct nxp_fspi *f)
|
||||
@@ -685,10 +689,13 @@ static void nxp_fspi_select_rx_sample_clk_source(struct nxp_fspi *f,
|
||||
* change the mode back to mode 0.
|
||||
*/
|
||||
reg = fspi_readl(f, f->iobase + FSPI_MCR0);
|
||||
if (op_is_dtr)
|
||||
if (op_is_dtr) {
|
||||
reg |= FSPI_MCR0_RXCLKSRC(3);
|
||||
else /*select mode 0 */
|
||||
f->max_rate = 166000000;
|
||||
} else { /*select mode 0 */
|
||||
reg &= ~FSPI_MCR0_RXCLKSRC(3);
|
||||
f->max_rate = 66000000;
|
||||
}
|
||||
fspi_writel(f, reg, f->iobase + FSPI_MCR0);
|
||||
}
|
||||
|
||||
@@ -719,6 +726,12 @@ static void nxp_fspi_dll_calibration(struct nxp_fspi *f)
|
||||
0, POLL_TOUT, true);
|
||||
if (ret)
|
||||
dev_warn(f->dev, "DLL lock failed, please fix it!\n");
|
||||
|
||||
/*
|
||||
* For ERR050272, DLL lock status bit is not accurate,
|
||||
* wait for 4us more as a workaround.
|
||||
*/
|
||||
udelay(4);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -780,11 +793,17 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
|
||||
uint64_t size_kb;
|
||||
|
||||
/*
|
||||
* Return, if previously selected target device is same as current
|
||||
* requested target device. Also the DTR or STR mode do not change.
|
||||
* Return when following condition all meet,
|
||||
* 1, if previously selected target device is same as current
|
||||
* requested target device.
|
||||
* 2, the DTR or STR mode do not change.
|
||||
* 3, previous operation max rate equals current one.
|
||||
*
|
||||
* For other case, need to re-config.
|
||||
*/
|
||||
if ((f->selected == spi_get_chipselect(spi, 0)) &&
|
||||
(!!(f->flags & FSPI_DTR_MODE) == op_is_dtr))
|
||||
(!!(f->flags & FSPI_DTR_MODE) == op_is_dtr) &&
|
||||
(f->pre_op_rate == op->max_freq))
|
||||
return;
|
||||
|
||||
/* Reset FLSHxxCR0 registers */
|
||||
@@ -802,6 +821,7 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
|
||||
dev_dbg(f->dev, "Target device [CS:%x] selected\n", spi_get_chipselect(spi, 0));
|
||||
|
||||
nxp_fspi_select_rx_sample_clk_source(f, op_is_dtr);
|
||||
rate = min(f->max_rate, op->max_freq);
|
||||
|
||||
if (op_is_dtr) {
|
||||
f->flags |= FSPI_DTR_MODE;
|
||||
@@ -832,6 +852,8 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
|
||||
else
|
||||
nxp_fspi_dll_override(f);
|
||||
|
||||
f->pre_op_rate = op->max_freq;
|
||||
|
||||
f->selected = spi_get_chipselect(spi, 0);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user