192192#define SPI_NAND_OP_RESET 0xff
193193#define SPI_NAND_OP_DIE_SELECT 0xc2
194194
195+ /* SNAND FIFO commands */
196+ #define SNAND_FIFO_TX_BUSWIDTH_SINGLE 0x08
197+ #define SNAND_FIFO_TX_BUSWIDTH_DUAL 0x09
198+ #define SNAND_FIFO_TX_BUSWIDTH_QUAD 0x0a
199+ #define SNAND_FIFO_RX_BUSWIDTH_SINGLE 0x0c
200+ #define SNAND_FIFO_RX_BUSWIDTH_DUAL 0x0e
201+ #define SNAND_FIFO_RX_BUSWIDTH_QUAD 0x0f
202+
195203#define SPI_NAND_CACHE_SIZE (SZ_4K + SZ_256)
196204#define SPI_MAX_TRANSFER_SIZE 511
197205
@@ -387,10 +395,26 @@ static int airoha_snand_set_mode(struct airoha_snand_ctrl *as_ctrl,
387395 return regmap_write (as_ctrl -> regmap_ctrl , REG_SPI_CTRL_DUMMY , 0 );
388396}
389397
390- static int airoha_snand_write_data (struct airoha_snand_ctrl * as_ctrl , u8 cmd ,
391- const u8 * data , int len )
398+ static int airoha_snand_write_data (struct airoha_snand_ctrl * as_ctrl ,
399+ const u8 * data , int len , int buswidth )
392400{
393401 int i , data_len ;
402+ u8 cmd ;
403+
404+ switch (buswidth ) {
405+ case 0 :
406+ case 1 :
407+ cmd = SNAND_FIFO_TX_BUSWIDTH_SINGLE ;
408+ break ;
409+ case 2 :
410+ cmd = SNAND_FIFO_TX_BUSWIDTH_DUAL ;
411+ break ;
412+ case 4 :
413+ cmd = SNAND_FIFO_TX_BUSWIDTH_QUAD ;
414+ break ;
415+ default :
416+ return - EINVAL ;
417+ }
394418
395419 for (i = 0 ; i < len ; i += data_len ) {
396420 int err ;
@@ -409,16 +433,32 @@ static int airoha_snand_write_data(struct airoha_snand_ctrl *as_ctrl, u8 cmd,
409433 return 0 ;
410434}
411435
412- static int airoha_snand_read_data (struct airoha_snand_ctrl * as_ctrl , u8 * data ,
413- int len )
436+ static int airoha_snand_read_data (struct airoha_snand_ctrl * as_ctrl ,
437+ u8 * data , int len , int buswidth )
414438{
415439 int i , data_len ;
440+ u8 cmd ;
441+
442+ switch (buswidth ) {
443+ case 0 :
444+ case 1 :
445+ cmd = SNAND_FIFO_RX_BUSWIDTH_SINGLE ;
446+ break ;
447+ case 2 :
448+ cmd = SNAND_FIFO_RX_BUSWIDTH_DUAL ;
449+ break ;
450+ case 4 :
451+ cmd = SNAND_FIFO_RX_BUSWIDTH_QUAD ;
452+ break ;
453+ default :
454+ return - EINVAL ;
455+ }
416456
417457 for (i = 0 ; i < len ; i += data_len ) {
418458 int err ;
419459
420460 data_len = min (len - i , SPI_MAX_TRANSFER_SIZE );
421- err = airoha_snand_set_fifo_op (as_ctrl , 0xc , data_len );
461+ err = airoha_snand_set_fifo_op (as_ctrl , cmd , data_len );
422462 if (err )
423463 return err ;
424464
@@ -618,6 +658,10 @@ static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc)
618658 if (desc -> info .offset + desc -> info .length > U32_MAX )
619659 return - EINVAL ;
620660
661+ /* continuous reading is not supported */
662+ if (desc -> info .length > SPI_NAND_CACHE_SIZE )
663+ return - E2BIG ;
664+
621665 if (!airoha_snand_supports_op (desc -> mem , & desc -> info .op_tmpl ))
622666 return - EOPNOTSUPP ;
623667
@@ -654,13 +698,13 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
654698
655699 err = airoha_snand_nfi_config (as_ctrl );
656700 if (err )
657- return err ;
701+ goto error_dma_mode_off ;
658702
659703 dma_addr = dma_map_single (as_ctrl -> dev , txrx_buf , SPI_NAND_CACHE_SIZE ,
660704 DMA_FROM_DEVICE );
661705 err = dma_mapping_error (as_ctrl -> dev , dma_addr );
662706 if (err )
663- return err ;
707+ goto error_dma_mode_off ;
664708
665709 /* set dma addr */
666710 err = regmap_write (as_ctrl -> regmap_nfi , REG_SPI_NFI_STRADDR ,
@@ -689,8 +733,9 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
689733 if (err )
690734 goto error_dma_unmap ;
691735
692- /* set read addr */
693- err = regmap_write (as_ctrl -> regmap_nfi , REG_SPI_NFI_RD_CTL3 , 0x0 );
736+ /* set read addr: zero page offset + descriptor read offset */
737+ err = regmap_write (as_ctrl -> regmap_nfi , REG_SPI_NFI_RD_CTL3 ,
738+ desc -> info .offset );
694739 if (err )
695740 goto error_dma_unmap ;
696741
@@ -760,6 +805,8 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
760805error_dma_unmap :
761806 dma_unmap_single (as_ctrl -> dev , dma_addr , SPI_NAND_CACHE_SIZE ,
762807 DMA_FROM_DEVICE );
808+ error_dma_mode_off :
809+ airoha_snand_set_mode (as_ctrl , SPI_MODE_MANUAL );
763810 return err ;
764811}
765812
@@ -824,7 +871,9 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
824871 if (err )
825872 goto error_dma_unmap ;
826873
827- err = regmap_write (as_ctrl -> regmap_nfi , REG_SPI_NFI_PG_CTL2 , 0x0 );
874+ /* set write addr: zero page offset + descriptor write offset */
875+ err = regmap_write (as_ctrl -> regmap_nfi , REG_SPI_NFI_PG_CTL2 ,
876+ desc -> info .offset );
828877 if (err )
829878 goto error_dma_unmap ;
830879
@@ -892,18 +941,35 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
892941error_dma_unmap :
893942 dma_unmap_single (as_ctrl -> dev , dma_addr , SPI_NAND_CACHE_SIZE ,
894943 DMA_TO_DEVICE );
944+ airoha_snand_set_mode (as_ctrl , SPI_MODE_MANUAL );
895945 return err ;
896946}
897947
898948static int airoha_snand_exec_op (struct spi_mem * mem ,
899949 const struct spi_mem_op * op )
900950{
901- u8 data [8 ], cmd , opcode = op -> cmd .opcode ;
902951 struct airoha_snand_ctrl * as_ctrl ;
952+ int op_len , addr_len , dummy_len ;
953+ u8 buf [20 ], * data ;
903954 int i , err ;
904955
905956 as_ctrl = spi_controller_get_devdata (mem -> spi -> controller );
906957
958+ op_len = op -> cmd .nbytes ;
959+ addr_len = op -> addr .nbytes ;
960+ dummy_len = op -> dummy .nbytes ;
961+
962+ if (op_len + dummy_len + addr_len > sizeof (buf ))
963+ return - EIO ;
964+
965+ data = buf ;
966+ for (i = 0 ; i < op_len ; i ++ )
967+ * data ++ = op -> cmd .opcode >> (8 * (op_len - i - 1 ));
968+ for (i = 0 ; i < addr_len ; i ++ )
969+ * data ++ = op -> addr .val >> (8 * (addr_len - i - 1 ));
970+ for (i = 0 ; i < dummy_len ; i ++ )
971+ * data ++ = 0xff ;
972+
907973 /* switch to manual mode */
908974 err = airoha_snand_set_mode (as_ctrl , SPI_MODE_MANUAL );
909975 if (err < 0 )
@@ -914,40 +980,40 @@ static int airoha_snand_exec_op(struct spi_mem *mem,
914980 return err ;
915981
916982 /* opcode */
917- err = airoha_snand_write_data (as_ctrl , 0x8 , & opcode , sizeof (opcode ));
983+ data = buf ;
984+ err = airoha_snand_write_data (as_ctrl , data , op_len ,
985+ op -> cmd .buswidth );
918986 if (err )
919987 return err ;
920988
921989 /* addr part */
922- cmd = opcode == SPI_NAND_OP_GET_FEATURE ? 0x11 : 0x8 ;
923- put_unaligned_be64 (op -> addr .val , data );
924-
925- for (i = ARRAY_SIZE (data ) - op -> addr .nbytes ;
926- i < ARRAY_SIZE (data ); i ++ ) {
927- err = airoha_snand_write_data (as_ctrl , cmd , & data [i ],
928- sizeof (data [0 ]));
990+ data += op_len ;
991+ if (addr_len ) {
992+ err = airoha_snand_write_data (as_ctrl , data , addr_len ,
993+ op -> addr .buswidth );
929994 if (err )
930995 return err ;
931996 }
932997
933998 /* dummy */
934- data [ 0 ] = 0xff ;
935- for ( i = 0 ; i < op -> dummy . nbytes ; i ++ ) {
936- err = airoha_snand_write_data (as_ctrl , 0x8 , & data [ 0 ] ,
937- sizeof ( data [ 0 ]) );
999+ data += addr_len ;
1000+ if ( dummy_len ) {
1001+ err = airoha_snand_write_data (as_ctrl , data , dummy_len ,
1002+ op -> dummy . buswidth );
9381003 if (err )
9391004 return err ;
9401005 }
9411006
9421007 /* data */
943- if (op -> data .dir == SPI_MEM_DATA_IN ) {
944- err = airoha_snand_read_data (as_ctrl , op -> data .buf .in ,
945- op -> data .nbytes );
946- if (err )
947- return err ;
948- } else {
949- err = airoha_snand_write_data (as_ctrl , 0x8 , op -> data .buf .out ,
950- op -> data .nbytes );
1008+ if (op -> data .nbytes ) {
1009+ if (op -> data .dir == SPI_MEM_DATA_IN )
1010+ err = airoha_snand_read_data (as_ctrl , op -> data .buf .in ,
1011+ op -> data .nbytes ,
1012+ op -> data .buswidth );
1013+ else
1014+ err = airoha_snand_write_data (as_ctrl , op -> data .buf .out ,
1015+ op -> data .nbytes ,
1016+ op -> data .buswidth );
9511017 if (err )
9521018 return err ;
9531019 }
0 commit comments