2 * This file is part of the coreboot project.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <device/mmio.h>
17 #include <console/console.h>
25 #define MTK_SPI_DEBUG 0
29 MTK_TXRX_TIMEOUT_US
= 1000 * 1000,
30 MTK_ARBITRARY_VALUE
= 0xdeaddead
35 MTK_SPI_PAUSE_IDLE
= 1
39 MTK_SPI_BUSY_STATUS
= 1,
40 MTK_SPI_PAUSE_FINISH_INT_STATUS
= 3
43 static inline struct mtk_spi_bus
*to_mtk_spi(const struct spi_slave
*slave
)
45 assert(slave
->bus
< SPI_BUS_NUMBER
);
46 return &spi_bus
[slave
->bus
];
49 static void spi_sw_reset(struct mtk_spi_regs
*regs
)
51 setbits32(®s
->spi_cmd_reg
, SPI_CMD_RST_EN
);
52 clrbits32(®s
->spi_cmd_reg
, SPI_CMD_RST_EN
);
55 void mtk_spi_init(unsigned int bus
, enum spi_pad_mask pad_select
,
56 unsigned int speed_hz
, unsigned int tick_dly
)
58 u32 div
, sck_ticks
, cs_ticks
;
60 assert(bus
< SPI_BUS_NUMBER
);
62 struct mtk_spi_bus
*slave
= &spi_bus
[bus
];
63 struct mtk_spi_regs
*regs
= slave
->regs
;
65 if (speed_hz
< SPI_HZ
/ 2)
66 div
= DIV_ROUND_UP(SPI_HZ
, speed_hz
);
70 sck_ticks
= DIV_ROUND_UP(div
, 2);
71 cs_ticks
= sck_ticks
* 2;
73 printk(BIOS_DEBUG
, "SPI%u(PAD%u) initialized at %u Hz\n",
74 bus
, pad_select
, SPI_HZ
/ (sck_ticks
* 2));
76 mtk_spi_set_timing(regs
, sck_ticks
, cs_ticks
, tick_dly
);
78 clrsetbits32(®s
->spi_cmd_reg
,
79 (SPI_CMD_CPHA_EN
| SPI_CMD_CPOL_EN
|
80 SPI_CMD_TX_ENDIAN_EN
| SPI_CMD_RX_ENDIAN_EN
|
81 SPI_CMD_TX_DMA_EN
| SPI_CMD_RX_DMA_EN
|
82 SPI_CMD_PAUSE_EN
| SPI_CMD_DEASSERT_EN
),
83 (SPI_CMD_TXMSBF_EN
| SPI_CMD_RXMSBF_EN
|
84 SPI_CMD_FINISH_IE_EN
| SPI_CMD_PAUSE_IE_EN
));
86 mtk_spi_set_gpio_pinmux(bus
, pad_select
);
88 clrsetbits32(®s
->spi_pad_macro_sel_reg
, SPI_PAD_SEL_MASK
,
91 gpio_output(slave
->cs_gpio
, 1);
94 static void mtk_spi_dump_data(const char *name
, const uint8_t *data
, int size
)
99 printk(BIOS_DEBUG
, "%s: 0x ", name
);
100 for (i
= 0; i
< size
; i
++)
101 printk(BIOS_INFO
, "%#x ", data
[i
]);
102 printk(BIOS_DEBUG
, "\n");
106 static int spi_ctrlr_claim_bus(const struct spi_slave
*slave
)
108 struct mtk_spi_bus
*mtk_slave
= to_mtk_spi(slave
);
109 struct mtk_spi_regs
*regs
= mtk_slave
->regs
;
111 setbits32(®s
->spi_cmd_reg
, 1 << SPI_CMD_PAUSE_EN_SHIFT
);
112 mtk_slave
->state
= MTK_SPI_IDLE
;
114 gpio_output(mtk_slave
->cs_gpio
, 0);
119 static int do_transfer(const struct spi_slave
*slave
, void *in
, const void *out
,
120 size_t *bytes_in
, size_t *bytes_out
)
122 struct mtk_spi_bus
*mtk_slave
= to_mtk_spi(slave
);
123 struct mtk_spi_regs
*regs
= mtk_slave
->regs
;
124 uint32_t reg_val
= 0;
131 else if (*bytes_in
== 0)
134 size
= MIN(*bytes_in
, *bytes_out
);
136 clrsetbits32(®s
->spi_cfg1_reg
,
137 SPI_CFG1_PACKET_LENGTH_MASK
| SPI_CFG1_PACKET_LOOP_MASK
,
138 ((size
- 1) << SPI_CFG1_PACKET_LENGTH_SHIFT
) |
139 (0 << SPI_CFG1_PACKET_LOOP_SHIFT
));
142 const uint8_t *outb
= (const uint8_t *)out
;
143 for (i
= 0; i
< size
; i
++) {
144 reg_val
|= outb
[i
] << ((i
% 4) * 8);
146 write32(®s
->spi_tx_data_reg
, reg_val
);
152 write32(®s
->spi_tx_data_reg
, reg_val
);
154 mtk_spi_dump_data("the outb data is",
155 (const uint8_t *)outb
, size
);
157 /* The SPI controller will transmit in full-duplex for RX,
158 * therefore we need arbitrary data on MOSI which the slave
161 uint32_t word_count
= DIV_ROUND_UP(size
, sizeof(u32
));
162 for (i
= 0; i
< word_count
; i
++)
163 write32(®s
->spi_tx_data_reg
, MTK_ARBITRARY_VALUE
);
166 if (mtk_slave
->state
== MTK_SPI_IDLE
) {
167 setbits32(®s
->spi_cmd_reg
, SPI_CMD_ACT_EN
);
168 mtk_slave
->state
= MTK_SPI_PAUSE_IDLE
;
169 } else if (mtk_slave
->state
== MTK_SPI_PAUSE_IDLE
) {
170 setbits32(®s
->spi_cmd_reg
, SPI_CMD_RESUME_EN
);
173 stopwatch_init_usecs_expire(&sw
, MTK_TXRX_TIMEOUT_US
);
174 while ((read32(®s
->spi_status1_reg
) & MTK_SPI_BUSY_STATUS
) == 0) {
175 if (stopwatch_expired(&sw
)) {
177 "Timeout waiting for status1 status.\n");
181 stopwatch_init_usecs_expire(&sw
, MTK_TXRX_TIMEOUT_US
);
182 while ((read32(®s
->spi_status0_reg
) &
183 MTK_SPI_PAUSE_FINISH_INT_STATUS
) == 0) {
184 if (stopwatch_expired(&sw
)) {
186 "Timeout waiting for status0 status.\n");
192 uint8_t *inb
= (uint8_t *)in
;
193 for (i
= 0; i
< size
; i
++) {
195 reg_val
= read32(®s
->spi_rx_data_reg
);
196 inb
[i
] = (reg_val
>> ((i
% 4) * 8)) & 0xff;
198 mtk_spi_dump_data("the inb data is", inb
, size
);
209 mtk_slave
->state
= MTK_SPI_IDLE
;
213 static int spi_ctrlr_xfer(const struct spi_slave
*slave
, const void *dout
,
214 size_t bytes_out
, void *din
, size_t bytes_in
)
216 while (bytes_out
|| bytes_in
) {
217 size_t in_now
= MIN(bytes_in
, MTK_FIFO_DEPTH
);
218 size_t out_now
= MIN(bytes_out
, MTK_FIFO_DEPTH
);
219 size_t in_rem
= in_now
;
220 size_t out_rem
= out_now
;
222 int ret
= do_transfer(slave
, din
, dout
, &in_rem
, &out_rem
);
227 size_t sent
= out_now
- out_rem
;
233 size_t received
= in_now
- in_rem
;
234 bytes_in
-= received
;
242 static void spi_ctrlr_release_bus(const struct spi_slave
*slave
)
244 struct mtk_spi_bus
*mtk_slave
= to_mtk_spi(slave
);
245 struct mtk_spi_regs
*regs
= mtk_slave
->regs
;
247 clrbits32(®s
->spi_cmd_reg
, SPI_CMD_PAUSE_EN
);
249 mtk_slave
->state
= MTK_SPI_IDLE
;
251 gpio_output(mtk_slave
->cs_gpio
, 1);
254 static int spi_ctrlr_setup(const struct spi_slave
*slave
)
256 struct mtk_spi_bus
*eslave
= to_mtk_spi(slave
);
257 assert(read32(&eslave
->regs
->spi_cfg0_reg
) != 0);
258 spi_sw_reset(eslave
->regs
);
262 const struct spi_ctrlr spi_ctrlr
= {
263 .setup
= spi_ctrlr_setup
,
264 .claim_bus
= spi_ctrlr_claim_bus
,
265 .release_bus
= spi_ctrlr_release_bus
,
266 .xfer
= spi_ctrlr_xfer
,
267 .max_xfer_size
= 65535,