2 * This file is part of the coreboot project.
4 * Copyright (C) 2019, The Linux Foundation. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 and
8 * only version 2 as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <spi-generic.h>
17 #include <spi_flash.h>
18 #include <arch/cache.h>
19 #include <device/mmio.h>
20 #include <soc/addressmap.h>
23 #include <soc/clock.h>
29 #define CACHE_LINE_SIZE 64
31 static int curr_desc_idx
= -1;
34 uint32_t data_address
;
35 uint32_t next_descriptor
;
37 uint32_t multi_io_mode
:3;
42 //------------------------//
45 uint32_t bounce_length
;
67 enum bus_xfer_direction
{
73 struct cmd_desc descriptors
[3];
74 uint8_t buffers
[3][CACHE_LINE_SIZE
];
75 } *dma
= (void *)_dma_coherent
;
77 static void dma_transfer_chain(struct cmd_desc
*chain
)
79 uint32_t mstr_int_status
;
81 write32(&sc7180_qspi
->mstr_int_sts
, 0xFFFFFFFF);
82 write32(&sc7180_qspi
->next_dma_desc_addr
, (uint32_t)(uintptr_t) chain
);
85 mstr_int_status
= read32(&sc7180_qspi
->mstr_int_sts
);
86 if (mstr_int_status
& DMA_CHAIN_DONE
)
91 static void flush_chain(void)
93 struct cmd_desc
*desc
= &dma
->descriptors
[0];
97 dma_transfer_chain(desc
);
100 if (desc
->direction
== MASTER_READ
) {
101 if (desc
->bounce_length
== 0)
102 dcache_invalidate_by_mva(
103 (void *)(uintptr_t) desc
->data_address
,
106 src
= (void *)(uintptr_t) desc
->bounce_src
;
107 dst
= (void *)(uintptr_t) desc
->bounce_dst
;
108 memcpy(dst
, src
, desc
->bounce_length
);
111 desc
= (void *)(uintptr_t) desc
->next_descriptor
;
116 static struct cmd_desc
*allocate_descriptor(void)
118 struct cmd_desc
*current
;
119 struct cmd_desc
*next
;
122 current
= (curr_desc_idx
== -1) ?
123 NULL
: &dma
->descriptors
[curr_desc_idx
];
125 index
= ++curr_desc_idx
;
126 next
= &dma
->descriptors
[index
];
128 next
->data_address
= (uint32_t) (uintptr_t) dma
->buffers
[index
];
130 next
->next_descriptor
= 0;
131 next
->direction
= MASTER_READ
;
132 next
->multi_io_mode
= 0;
137 next
->bounce_src
= 0;
138 next
->bounce_dst
= 0;
139 next
->bounce_length
= 0;
142 current
->next_descriptor
= (uint32_t)(uintptr_t) next
;
143 current
->fragment
= 1;
149 static void cs_change(enum cs_state state
)
151 gpio_set(GPIO(68), state
== CS_DEASSERT
);
154 static void configure_gpios(void)
156 gpio_output(GPIO(68), 1);
158 gpio_configure(GPIO(64), GPIO64_FUNC_QSPI_DATA_0
,
159 GPIO_NO_PULL
, GPIO_2MA
, GPIO_OUTPUT_ENABLE
);
161 gpio_configure(GPIO(65), GPIO65_FUNC_QSPI_DATA_1
,
162 GPIO_NO_PULL
, GPIO_2MA
, GPIO_OUTPUT_ENABLE
);
164 gpio_configure(GPIO(63), GPIO63_FUNC_QSPI_CLK
,
165 GPIO_NO_PULL
, GPIO_2MA
, GPIO_OUTPUT_ENABLE
);
168 static void queue_bounce_data(uint8_t *data
, uint32_t data_bytes
,
169 enum qspi_mode data_mode
, bool write
)
171 struct cmd_desc
*desc
;
174 desc
= allocate_descriptor();
175 desc
->direction
= write
;
176 desc
->multi_io_mode
= data_mode
;
177 ptr
= (void *)(uintptr_t) desc
->data_address
;
180 memcpy(ptr
, data
, data_bytes
);
182 desc
->bounce_src
= (uint32_t)(uintptr_t) ptr
;
183 desc
->bounce_dst
= (uint32_t)(uintptr_t) data
;
184 desc
->bounce_length
= data_bytes
;
187 desc
->length
= data_bytes
;
190 static void queue_direct_data(uint8_t *data
, uint32_t data_bytes
,
191 enum qspi_mode data_mode
, bool write
)
193 struct cmd_desc
*desc
;
195 desc
= allocate_descriptor();
196 desc
->direction
= write
;
197 desc
->multi_io_mode
= data_mode
;
198 desc
->data_address
= (uint32_t)(uintptr_t) data
;
199 desc
->length
= data_bytes
;
202 dcache_clean_by_mva(data
, data_bytes
);
204 dcache_invalidate_by_mva(data
, data_bytes
);
207 static void queue_data(uint8_t *data
, uint32_t data_bytes
,
208 enum qspi_mode data_mode
, bool write
)
210 uint8_t *aligned_ptr
;
212 uint32_t prolog_bytes
, aligned_bytes
, epilog_bytes
;
218 (uint8_t *)ALIGN_UP((uintptr_t)data
, CACHE_LINE_SIZE
);
220 prolog_bytes
= MIN(data_bytes
, aligned_ptr
- data
);
221 aligned_bytes
= ALIGN_DOWN(data_bytes
- prolog_bytes
, CACHE_LINE_SIZE
);
222 epilog_bytes
= data_bytes
- prolog_bytes
- aligned_bytes
;
224 epilog_ptr
= data
+ prolog_bytes
+ aligned_bytes
;
227 queue_bounce_data(data
, prolog_bytes
, data_mode
, write
);
229 queue_direct_data(aligned_ptr
, aligned_bytes
, data_mode
, write
);
231 queue_bounce_data(epilog_ptr
, epilog_bytes
, data_mode
, write
);
234 static void reg_init(void)
237 uint32_t tx_data_oe_delay
, tx_data_delay
;
238 uint32_t mstr_config
;
242 tx_data_oe_delay
= 0;
245 mstr_config
= (tx_data_oe_delay
<< TX_DATA_OE_DELAY_SHIFT
) |
246 (tx_data_delay
<< TX_DATA_DELAY_SHIFT
) | (SBL_EN
) |
247 (spi_mode
<< SPI_MODE_SHIFT
) |
253 write32(&sc7180_qspi
->mstr_cfg
, mstr_config
);
254 write32(&sc7180_qspi
->ahb_mstr_cfg
, 0xA42);
255 write32(&sc7180_qspi
->mstr_int_en
, 0x0);
256 write32(&sc7180_qspi
->mstr_int_sts
, 0xFFFFFFFF);
257 write32(&sc7180_qspi
->rd_fifo_cfg
, 0x0);
258 write32(&sc7180_qspi
->rd_fifo_rst
, RESET_FIFO
);
261 void quadspi_init(uint32_t hz
)
263 assert(dcache_line_bytes() == CACHE_LINE_SIZE
);
264 clock_configure_qspi(hz
* 4);
269 int sc7180_claim_bus(const struct spi_slave
*slave
)
271 cs_change(CS_ASSERT
);
275 void sc7180_release_bus(const struct spi_slave
*slave
)
277 cs_change(CS_DEASSERT
);
280 static int xfer(enum qspi_mode mode
, const void *dout
, size_t out_bytes
,
281 void *din
, size_t in_bytes
)
283 if ((out_bytes
&& !dout
) || (in_bytes
&& !din
) ||
284 (in_bytes
&& out_bytes
)) {
288 queue_data((uint8_t *) (out_bytes
? dout
: din
),
289 in_bytes
| out_bytes
, mode
, !!out_bytes
);
296 int sc7180_xfer(const struct spi_slave
*slave
, const void *dout
,
297 size_t out_bytes
, void *din
, size_t in_bytes
)
299 return xfer(SDR_1BIT
, dout
, out_bytes
, din
, in_bytes
);
302 int sc7180_xfer_dual(const struct spi_slave
*slave
, const void *dout
,
303 size_t out_bytes
, void *din
, size_t in_bytes
)
305 return xfer(SDR_2BIT
, dout
, out_bytes
, din
, in_bytes
);