coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
qupv3_spi.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <assert.h>
4 #include <lib.h>
5 #include <soc/clock.h>
6 #include <soc/gpio.h>
7 #include <soc/qcom_qup_se.h>
10 #include <soc/qupv3_spi_common.h>
11 #include <types.h>
12 
13 /* SE_SPI_LOOPBACK register fields */
14 #define LOOPBACK_ENABLE 0x1
15 
16 /* SE_SPI_WORD_LEN register fields */
17 #define WORD_LEN_MSK QC_GENMASK(9, 0)
18 #define MIN_WORD_LEN 4
19 
20 /* SPI_TX/SPI_RX_TRANS_LEN fields */
21 #define TRANS_LEN_MSK QC_GENMASK(23, 0)
22 
23 /* M_CMD OP codes for SPI */
24 #define SPI_TX_ONLY 1
25 #define SPI_RX_ONLY 2
26 #define SPI_FULL_DUPLEX 3
27 #define SPI_TX_RX 7
28 #define SPI_CS_ASSERT 8
29 #define SPI_CS_DEASSERT 9
30 #define SPI_SCK_ONLY 10
31 
32 /* M_CMD params for SPI */
33 /* If fragmentation bit is set then CS will not toggle after each transfer */
34 #define M_CMD_FRAGMENTATION BIT(2)
35 
36 #define BITS_PER_BYTE 8
37 #define BITS_PER_WORD 8
38 #define TX_WATERMARK 1
39 
40 #define IRQ_TRIGGER (M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN | \
41  M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN | \
42  M_CMD_CANCEL_EN | M_CMD_ABORT_EN)
43 
44 static void setup_fifo_params(const struct spi_slave *slave)
45 {
46  unsigned int se_bus = slave->bus;
47  struct qup_regs *regs = qup[se_bus].regs;
48  u32 word_len = 0;
49 
50  /* Disable loopback mode */
51  write32(&regs->proto_loopback_cfg, 0);
52 
53  write32(&regs->spi_demux_sel, slave->cs);
54  word_len = ((BITS_PER_WORD - MIN_WORD_LEN) & WORD_LEN_MSK);
55  write32(&regs->spi_word_len, word_len);
56 
57  /* FIFO PACKING CONFIGURATION */
58  write32(&regs->geni_tx_packing_cfg0, PACK_VECTOR0
59  | (PACK_VECTOR1 << 10));
60  write32(&regs->geni_tx_packing_cfg1, PACK_VECTOR2
61  | (PACK_VECTOR3 << 10));
62  write32(&regs->geni_rx_packing_cfg0, PACK_VECTOR0
63  | (PACK_VECTOR1 << 10));
64  write32(&regs->geni_rx_packing_cfg1, PACK_VECTOR2
65  | (PACK_VECTOR3 << 10));
66  write32(&regs->geni_byte_granularity, (log2(BITS_PER_WORD) - 3));
67 }
68 
69 static void qup_setup_m_cmd(unsigned int se_bus, u32 cmd, u32 params)
70 {
71  struct qup_regs *regs = qup[se_bus].regs;
72  u32 m_cmd = (cmd << M_OPCODE_SHFT);
73 
74  m_cmd |= (params & M_PARAMS_MSK);
75  write32(&regs->geni_m_cmd0, m_cmd);
76 }
77 
78 int qup_spi_xfer(const struct spi_slave *slave, const void *dout,
79  size_t bytes_out, void *din, size_t bytes_in)
80 {
81  u32 m_cmd = 0;
82  u32 m_param = M_CMD_FRAGMENTATION;
83  int size;
84  unsigned int se_bus = slave->bus;
85  struct qup_regs *regs = qup[se_bus].regs;
86  struct stopwatch timeout;
87 
88  if ((bytes_in == 0) && (bytes_out == 0))
89  return 0;
90 
92 
93  if (!bytes_out) {
94  size = bytes_in;
95  m_cmd = SPI_RX_ONLY;
96  dout = NULL;
97  } else if (!bytes_in) {
98  size = bytes_out;
99  m_cmd = SPI_TX_ONLY;
100  din = NULL;
101  } else {
102  size = MIN(bytes_in, bytes_out);
103  m_cmd = SPI_FULL_DUPLEX;
104  }
105 
106  /* Check for maximum permissible transfer length */
107  assert(!(size & ~TRANS_LEN_MSK));
108 
109  if (bytes_out) {
110  write32(&regs->spi_tx_trans_len, size);
111  write32(&regs->geni_tx_watermark_reg, TX_WATERMARK);
112  }
113  if (bytes_in)
114  write32(&regs->spi_rx_trans_len, size);
115 
116  qup_setup_m_cmd(se_bus, m_cmd, m_param);
117 
118  stopwatch_init_msecs_expire(&timeout, 1000);
119  if (qup_handle_transfer(se_bus, dout, din, size, &timeout))
120  return -1;
121 
122  qup_spi_xfer(slave, dout + size, MAX((int)bytes_out - size, 0),
123  din + size, MAX((int)bytes_in - size, 0));
124 
125  return 0;
126 }
127 
128 static int spi_qup_set_cs(const struct spi_slave *slave, bool enable)
129 {
130  u32 m_cmd = 0;
131  u32 m_irq = 0;
132  unsigned int se_bus = slave->bus;
133  struct stopwatch sw;
134 
135  m_cmd = (enable) ? SPI_CS_ASSERT : SPI_CS_DEASSERT;
136  qup_setup_m_cmd(se_bus, m_cmd, 0);
137 
138  stopwatch_init_usecs_expire(&sw, 100);
139  do {
140  m_irq = qup_wait_for_m_irq(se_bus);
141  if (m_irq & M_CMD_DONE_EN) {
142  write32(&qup[se_bus].regs->geni_m_irq_clear, m_irq);
143  break;
144  }
145  write32(&qup[se_bus].regs->geni_m_irq_clear, m_irq);
146  } while (!stopwatch_expired(&sw));
147 
148  if (!(m_irq & M_CMD_DONE_EN)) {
149  printk(BIOS_INFO, "%s:Failed to %s chip\n", __func__,
150  (enable) ? "Assert" : "Deassert");
151  qup_m_cancel_and_abort(se_bus);
152  return -1;
153  }
154  return 0;
155 }
156 
157 void qup_spi_init(unsigned int bus, unsigned int speed_hz)
158 {
159  u32 m_clk_cfg = 0, div = DEFAULT_SE_CLK / speed_hz;
160  struct qup_regs *regs = qup[bus].regs;
161 
162  /* Make sure div can hit target frequency within +/- 1KHz range */
163  assert(((DEFAULT_SE_CLK - speed_hz * div) <= div * KHz) && (div > 0));
166  m_clk_cfg |= ((div << CLK_DIV_SHFT) | SER_CLK_EN);
167  write32(&regs->geni_ser_m_clk_cfg, m_clk_cfg);
168  /* Mode:0, cpha=0, cpol=0 */
169  write32(&regs->spi_cpha, 0);
170  write32(&regs->spi_cpol, 0);
171 
172  /* Serial engine IO initialization */
173  write32(&regs->geni_cgc_ctrl, DEFAULT_CGC_EN);
174  write32(&regs->dma_general_cfg,
177  write32(&regs->geni_output_ctrl,
179  write32(&regs->geni_force_default_reg, FORCE_DEFAULT);
180 
181  /* Serial engine IO set mode */
182  write32(&regs->se_irq_en, (GENI_M_IRQ_EN |
184  write32(&regs->se_gsi_event_en, 0);
185 
186  /* Set RX and RFR watermark */
187  write32(&regs->geni_rx_watermark_reg, 0);
188  write32(&regs->geni_rx_rfr_watermark_reg, FIFO_DEPTH - 2);
189 
190  /* GPIO Configuration */
191  gpio_configure(qup[bus].pin[0], qup[bus].func[0], GPIO_NO_PULL,
192  GPIO_6MA, GPIO_INPUT); /* MISO */
193  gpio_configure(qup[bus].pin[1], qup[bus].func[1], GPIO_NO_PULL,
194  GPIO_6MA, GPIO_OUTPUT); /* MOSI */
195  gpio_configure(qup[bus].pin[2], qup[bus].func[2], GPIO_NO_PULL,
196  GPIO_6MA, GPIO_OUTPUT); /* CLK */
197  gpio_configure(qup[bus].pin[3], qup[bus].func[3], GPIO_NO_PULL,
198  GPIO_6MA, GPIO_OUTPUT); /* CS */
199 
200  /* Select and setup FIFO mode */
201  write32(&regs->geni_m_irq_clear, 0xFFFFFFFF);
202  write32(&regs->geni_s_irq_clear, 0xFFFFFFFF);
203  write32(&regs->dma_tx_irq_clr, 0xFFFFFFFF);
204  write32(&regs->dma_rx_irq_clr, 0xFFFFFFFF);
205  write32(&regs->geni_m_irq_enable, (M_COMMON_GENI_M_IRQ_EN |
208  write32(&regs->geni_s_irq_enable, (S_COMMON_GENI_S_IRQ_EN
209  | S_CMD_DONE_EN));
210  clrbits32(&regs->geni_dma_mode_en, GENI_DMA_MODE_EN);
211 }
212 
214 {
215  return spi_qup_set_cs(slave, 1);
216 }
217 
219 {
220  spi_qup_set_cs(slave, 0);
221 }
#define GPIO_OUTPUT
Definition: gpio_ftns.h:23
#define GPIO_INPUT
Definition: gpio_ftns.h:24
static void write32(void *addr, uint32_t val)
Definition: mmio.h:40
#define assert(statement)
Definition: assert.h:74
static struct sdram_info params
Definition: sdram_configs.c:83
#define MIN(a, b)
Definition: helpers.h:37
#define KHz
Definition: helpers.h:79
#define MAX(a, b)
Definition: helpers.h:40
#define printk(level,...)
Definition: stdlib.h:16
#define clrbits32(addr, clear)
Definition: mmio.h:26
static int stopwatch_expired(struct stopwatch *sw)
Definition: timer.h:152
static void stopwatch_init_msecs_expire(struct stopwatch *sw, long ms)
Definition: timer.h:133
static void stopwatch_init_usecs_expire(struct stopwatch *sw, long us)
Definition: timer.h:127
static int log2(u32 x)
Definition: lib.h:53
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
@ GPIO_6MA
Definition: gpio_common.h:72
@ GPIO_NO_PULL
Definition: gpio_common.h:62
#define M_TX_FIFO_WATERMARK_EN
#define AHB_SEC_SLV_CLK_CGC_ON
#define GENI_DMA_MODE_EN
#define DMA_RX_IRQ_EN
#define PACK_VECTOR2
#define DMA_AHB_SLV_CFG_ON
#define DEFAULT_SE_CLK
#define PACK_VECTOR0
#define GENI_S_IRQ_EN
#define PACK_VECTOR1
#define GENI_M_IRQ_EN
#define DMA_TX_CLK_CGC_ON
#define M_CMD_DONE_EN
#define DEFAULT_CGC_EN
void qup_m_cancel_and_abort(unsigned int bus)
#define M_OPCODE_SHFT
#define S_COMMON_GENI_S_IRQ_EN
#define FIFO_DEPTH
#define SER_CLK_EN
#define DMA_RX_CLK_CGC_ON
#define M_RX_FIFO_WATERMARK_EN
#define M_COMMON_GENI_M_IRQ_EN
#define M_RX_FIFO_LAST_EN
#define DEFAULT_IO_OUTPUT_CTRL_MSK
#define CLK_DIV_SHFT
#define M_PARAMS_MSK
#define PACK_VECTOR3
#define FORCE_DEFAULT
#define S_CMD_DONE_EN
u32 qup_wait_for_m_irq(unsigned int bus)
Definition: qup_se_handler.c:7
#define DMA_TX_IRQ_EN
int qup_handle_transfer(unsigned int bus, const void *dout, void *din, int size, struct stopwatch *timeout)
@ SE_PROTOCOL_SPI
void qupv3_se_fw_load_and_init(unsigned int bus, unsigned int protocol, unsigned int mode)
Definition: qupv3_config.c:13
void qup_spi_release_bus(const struct spi_slave *slave)
Definition: qupv3_spi.c:218
#define TX_WATERMARK
Definition: qupv3_spi.c:38
#define SPI_TX_ONLY
Definition: qupv3_spi.c:24
#define SPI_FULL_DUPLEX
Definition: qupv3_spi.c:26
#define WORD_LEN_MSK
Definition: qupv3_spi.c:17
#define TRANS_LEN_MSK
Definition: qupv3_spi.c:21
#define SPI_CS_ASSERT
Definition: qupv3_spi.c:28
static void setup_fifo_params(const struct spi_slave *slave)
Definition: qupv3_spi.c:44
static void qup_setup_m_cmd(unsigned int se_bus, u32 cmd, u32 params)
Definition: qupv3_spi.c:69
#define SPI_RX_ONLY
Definition: qupv3_spi.c:25
int qup_spi_claim_bus(const struct spi_slave *slave)
Definition: qupv3_spi.c:213
#define MIN_WORD_LEN
Definition: qupv3_spi.c:18
#define SPI_CS_DEASSERT
Definition: qupv3_spi.c:29
int qup_spi_xfer(const struct spi_slave *slave, const void *dout, size_t bytes_out, void *din, size_t bytes_in)
Definition: qupv3_spi.c:78
void qup_spi_init(unsigned int bus, unsigned int speed_hz)
Definition: qupv3_spi.c:157
static int spi_qup_set_cs(const struct spi_slave *slave, bool enable)
Definition: qupv3_spi.c:128
#define BITS_PER_WORD
Definition: qupv3_spi.c:37
#define M_CMD_FRAGMENTATION
Definition: qupv3_spi.c:34
void gpio_configure(gpio_t gpio, uint32_t func, uint32_t pull, uint32_t drive_str, uint32_t enable)
Definition: gpio.c:7
void clock_enable_qup(int qup)
Definition: clock.c:132
static struct spi_slave slave
Definition: spiconsole.c:7
#define NULL
Definition: stddef.h:19
uint32_t u32
Definition: stdint.h:51
Definition: device.h:76
struct qup_regs * regs
Definition: qcom_qup_se.h:29
unsigned int bus
Definition: spi-generic.h:41
unsigned int cs
Definition: spi-generic.h:42