diff options
Diffstat (limited to 'firmware/target/mips/ingenic_x1000/sfc-x1000.h')
-rw-r--r-- | firmware/target/mips/ingenic_x1000/sfc-x1000.h | 152 |
1 files changed, 86 insertions, 66 deletions
diff --git a/firmware/target/mips/ingenic_x1000/sfc-x1000.h b/firmware/target/mips/ingenic_x1000/sfc-x1000.h index 5784198b93..d28bcb6740 100644 --- a/firmware/target/mips/ingenic_x1000/sfc-x1000.h +++ b/firmware/target/mips/ingenic_x1000/sfc-x1000.h | |||
@@ -19,87 +19,107 @@ | |||
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | 21 | ||
22 | #ifndef __SFC_X1000_H__ | ||
23 | #define __SFC_X1000_H__ | ||
24 | |||
25 | #include "x1000/sfc.h" | ||
22 | #include <stdint.h> | 26 | #include <stdint.h> |
23 | #include <stdbool.h> | 27 | #include <stdbool.h> |
24 | #include "clk-x1000.h" | ||
25 | #include "x1000/sfc.h" | ||
26 | 28 | ||
27 | /* SPI flash controller interface -- this is a low-level driver upon which | 29 | /* SPI transfer mode. SFC_TMODE_X_Y_Z means: |
28 | * you can build NAND/NOR flash drivers. The main function is sfc_exec(), | 30 | * |
29 | * used to issue commands, transfer data, etc. | 31 | * - X lines for command phase |
32 | * - Y lines for address+dummy phase | ||
33 | * - Z lines for data phase | ||
30 | */ | 34 | */ |
35 | #define SFC_TMODE_1_1_1 0 | ||
36 | #define SFC_TMODE_1_1_2 1 | ||
37 | #define SFC_TMODE_1_2_2 2 | ||
38 | #define SFC_TMODE_2_2_2 3 | ||
39 | #define SFC_TMODE_1_1_4 4 | ||
40 | #define SFC_TMODE_1_4_4 5 | ||
41 | #define SFC_TMODE_4_4_4 6 | ||
31 | 42 | ||
32 | #define SFC_FLAG_READ 0x01 /* Read data */ | 43 | /* Phase format |
33 | #define SFC_FLAG_WRITE 0x02 /* Write data */ | 44 | * _____________________ |
34 | #define SFC_FLAG_DUMMYFIRST 0x04 /* Do dummy bits before sending address. | 45 | * / SFC_PFMT_ADDR_FIRST \ |
35 | * Default is dummy bits after address. | 46 | * +-----+-------+-------+------+ |
36 | */ | 47 | * | cmd | addr | dummy | data | |
48 | * +-----+-------+-------+------+ | ||
49 | * ______________________ | ||
50 | * / SFC_PFMT_DUMMY_FIRST \ | ||
51 | * +-----+-------+-------+------+ | ||
52 | * | cmd | dummy | addr | data | | ||
53 | * +-----+-------+-------+------+ | ||
54 | */ | ||
55 | #define SFC_PFMT_ADDR_FIRST 0 | ||
56 | #define SFC_PFMT_DUMMY_FIRST 1 | ||
37 | 57 | ||
38 | /* SPI transfer mode. If in doubt, check with the X1000 manual and confirm | 58 | /* Direction of transfer flag */ |
39 | * the transfer format is what you expect. | 59 | #define SFC_READ 0 |
60 | #define SFC_WRITE (1 << 31) | ||
61 | |||
62 | /** \brief Macro to generate an SFC command for use with sfc_exec() | ||
63 | * \param cmd Command number (up to 16 bits) | ||
64 | * \param tmode SPI transfer mode | ||
65 | * \param awidth Number of address bytes | ||
66 | * \param dwidth Number of dummy cycles (1 cycle = 1 bit) | ||
67 | * \param pfmt Phase format (address first or dummy first) | ||
68 | * \param data_en 1 to enable data phase, 0 to omit it | ||
40 | */ | 69 | */ |
41 | #define SFC_MODE_STANDARD 0 | 70 | #define SFC_CMD(cmd, tmode, awidth, dwidth, pfmt, data_en) \ |
42 | #define SFC_MODE_DUAL_IN_DUAL_OUT 1 | 71 | jz_orf(SFC_TRAN_CONF, COMMAND(cmd), CMD_EN(1), \ |
43 | #define SFC_MODE_DUAL_IO 2 | 72 | MODE(tmode), ADDR_WIDTH(awidth), DUMMY_BITS(dwidth), \ |
44 | #define SFC_MODE_FULL_DUAL_IO 3 | 73 | PHASE_FMT(pfmt), DATA_EN(data_en)) |
45 | #define SFC_MODE_QUAD_IN_QUAD_OUT 4 | ||
46 | #define SFC_MODE_QUAD_IO 5 | ||
47 | #define SFC_MODE_FULL_QUAD_IO 6 | ||
48 | 74 | ||
49 | /* Return status codes for sfc_exec() */ | 75 | /* Open/close SFC hardware */ |
50 | #define SFC_STATUS_OK 0 | 76 | extern void sfc_open(void); |
51 | #define SFC_STATUS_OVERFLOW 1 | 77 | extern void sfc_close(void); |
52 | #define SFC_STATUS_UNDERFLOW 2 | ||
53 | #define SFC_STATUS_LOCKUP 3 | ||
54 | 78 | ||
55 | typedef struct sfc_op { | 79 | /* Enable IRQ mode, instead of busy waiting for operations to complete. |
56 | int command; /* Command number */ | 80 | * Needs to be called separately after sfc_open(), because the SPL has to |
57 | int mode; /* SPI transfer mode */ | 81 | * use busy waiting, but we cannot #ifdef it for the SPL due to limitations |
58 | int flags; /* Flags for this op */ | 82 | * of the build system. */ |
59 | int addr_bytes; /* Number of address bytes */ | 83 | extern void sfc_irq_begin(void); |
60 | int dummy_bits; /* Number of dummy bits (yes: bits, not bytes) */ | 84 | extern void sfc_irq_end(void); |
61 | uint32_t addr_lo; /* Lower 32 bits of address */ | ||
62 | uint32_t addr_hi; /* Upper 32 bits of address */ | ||
63 | int data_bytes; /* Number of data bytes to read/write */ | ||
64 | void* buffer; /* Data buffer -- MUST be word-aligned */ | ||
65 | } sfc_op; | ||
66 | 85 | ||
67 | /* One-time driver init for mutexes/etc needed for handling interrupts. | 86 | /* Change the SFC clock frequency */ |
68 | * This can be safely called multiple times; only the first call will | 87 | extern void sfc_set_clock(uint32_t freq); |
69 | * actually perform the init. | 88 | |
70 | */ | 89 | /* Set the device configuration register */ |
71 | extern void sfc_init(void); | 90 | inline void sfc_set_dev_conf(uint32_t conf) |
91 | { | ||
92 | REG_SFC_DEV_CONF = conf; | ||
93 | } | ||
72 | 94 | ||
73 | /* Controller mutex -- lock before touching the driver */ | 95 | /* Control the state of the write protect pin */ |
74 | extern void sfc_lock(void); | 96 | inline void sfc_set_wp_enable(bool en) |
75 | extern void sfc_unlock(void); | 97 | { |
98 | jz_writef(SFC_GLB, WP_EN(en ? 1 : 0)); | ||
99 | } | ||
76 | 100 | ||
77 | /* Open/close the driver. The driver must be open in order to do operations. | 101 | /** \brief Execute a command |
78 | * Closing the driver shuts off the hardware; the driver can be re-opened at | 102 | * \param cmd Command encoded by `SFC_CMD` macro. |
79 | * a later time when it's needed again. | 103 | * \param addr Address up to 32 bits; pass 0 if the command doesn't need it |
104 | * \param data Buffer for data transfer commands, must be cache-aligned | ||
105 | * \param size Number of data bytes / direction of transfer flag | ||
106 | * \returns SFC status code: 0 on success and < 0 on failure. | ||
80 | * | 107 | * |
81 | * After opening the driver, you must also program a valid device configuration | 108 | * - Non-data commands must pass `data = NULL` and `size = 0` in order to |
82 | * and clock rate using sfc_set_dev_conf() and sfc_set_clock(). | 109 | * get correct results. |
110 | * | ||
111 | * - Data commands must specify a direction of transfer using the high bit | ||
112 | * of the `size` argument by OR'ing in `SFC_READ` or `SFC_WRITE`. | ||
83 | */ | 113 | */ |
84 | extern void sfc_open(void); | 114 | extern void sfc_exec(uint32_t cmd, uint32_t addr, void* data, uint32_t size); |
85 | extern void sfc_close(void); | ||
86 | 115 | ||
87 | /* These functions can be called at any time while the driver is open, but | 116 | /* NOTE: the above will need to be changed if we need better performance |
88 | * must not be called while there is an operation in progress. It's the | 117 | * The hardware can do multiple commands in a sequence, including polling, |
89 | * caller's job to ensure the configuration will work with the device and | 118 | * and emit an interrupt only at the end. |
90 | * be capable of reading back data correctly. | ||
91 | * | 119 | * |
92 | * - sfc_set_dev_conf() writes its argument to the SFC_DEV_CONF register. | 120 | * Also, some chips need more than 4 address bytes even though the block |
93 | * - sfc_set_wp_enable() sets the state of the write-protect pin (WP). | 121 | * and page numbers would still fit in 32 bits; the current API cannot |
94 | * - sfc_set_clock() sets the controller clock frequency (in Hz). | 122 | * handle this. |
95 | */ | 123 | */ |
96 | #define sfc_set_dev_conf(dev_conf) \ | ||
97 | do { REG_SFC_DEV_CONF = (dev_conf); } while(0) | ||
98 | |||
99 | #define sfc_set_wp_enable(en) \ | ||
100 | jz_writef(SFC_GLB, WP_EN((en) ? 1 : 0)) | ||
101 | |||
102 | extern void sfc_set_clock(uint32_t freq); | ||
103 | 124 | ||
104 | /* Execute an operation. Returns zero on success, nonzero on failure. */ | 125 | #endif /* __SFC_X1000_H__ */ |
105 | extern int sfc_exec(const sfc_op* op); | ||