coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
pmif.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <assert.h>
4 #include <console/console.h>
5 #include <device/mmio.h>
6 #include <soc/addressmap.h>
7 #include <soc/pmif.h>
8 #include <soc/pmif_spi.h>
9 #include <soc/pmif_spmi.h>
10 #include <soc/pmif_sw.h>
11 #include <soc/spmi.h>
12 #include <timer.h>
13 
14 static int pmif_check_swinf(struct pmif *arb, long timeout_us, u32 expected_status)
15 {
16  u32 reg_rdata;
17  struct stopwatch sw;
18 
19  stopwatch_init_usecs_expire(&sw, timeout_us);
20  do {
21  reg_rdata = read32(&arb->ch->ch_sta);
22  if (stopwatch_expired(&sw))
23  return E_TIMEOUT;
24  } while (GET_SWINF_0_FSM(reg_rdata) != expected_status);
25 
26  return 0;
27 }
28 
29 static void pmif_send_cmd(struct pmif *arb, int write, u32 opc, u32 slvid,
30  u32 addr, u32 *rdata, u32 wdata, u32 len)
31 {
32  int ret;
33  u32 data, bc = len - 1;
34 
35  /* Wait for Software Interface FSM state to be IDLE. */
37  if (ret) {
38  printk(BIOS_ERR, "[%s] idle timeout\n", __func__);
39  return;
40  }
41 
42  /* Set the write data */
43  if (write)
44  write32(&arb->ch->wdata, wdata);
45 
46  /* Send the command. */
47  write32(&arb->ch->ch_send,
48  (opc << 30) | (write << 29) | (slvid << 24) | (bc << 16) | addr);
49 
50  if (!write) {
51  /*
52  * Wait for Software Interface FSM state to be WFVLDCLR,
53  * read the data and clear the valid flag.
54  */
56  if (ret) {
57  printk(BIOS_ERR, "[%s] read timeout\n", __func__);
58  return;
59  }
60 
61  data = read32(&arb->ch->rdata);
62  *rdata = data;
63  write32(&arb->ch->ch_rdy, 0x1);
64  }
65 }
66 
67 static void pmif_spmi_read(struct pmif *arb, u32 slvid, u32 reg, u32 *data)
68 {
69  *data = 0;
70  pmif_send_cmd(arb, 0, PMIF_CMD_EXT_REG_LONG, slvid, reg, data, 0, 1);
71 }
72 
73 static void pmif_spmi_write(struct pmif *arb, u32 slvid, u32 reg, u32 data)
74 {
75  pmif_send_cmd(arb, 1, PMIF_CMD_EXT_REG_LONG, slvid, reg, NULL, data, 1);
76 }
77 
78 static u32 pmif_spmi_read_field(struct pmif *arb, u32 slvid, u32 reg, u32 mask, u32 shift)
79 {
80  u32 data;
81 
82  pmif_spmi_read(arb, slvid, reg, &data);
83  data &= (mask << shift);
84  data >>= shift;
85 
86  return data;
87 }
88 
89 static void pmif_spmi_write_field(struct pmif *arb, u32 slvid, u32 reg,
90  u32 val, u32 mask, u32 shift)
91 {
92  u32 old, new;
93 
94  pmif_spmi_read(arb, slvid, reg, &old);
95  new = old & ~(mask << shift);
96  new |= (val << shift);
97  pmif_spmi_write(arb, slvid, reg, new);
98 }
99 
100 static void pmif_spi_read(struct pmif *arb, u32 slvid, u32 reg, u32 *data)
101 {
102  *data = 0;
103  pmif_send_cmd(arb, 0, PMIF_CMD_REG_0, slvid, reg, data, 0, 1);
104 }
105 
106 static void pmif_spi_write(struct pmif *arb, u32 slvid, u32 reg, u32 data)
107 {
108  pmif_send_cmd(arb, 1, PMIF_CMD_REG_0, slvid, reg, NULL, data, 1);
109 }
110 
111 static u32 pmif_spi_read_field(struct pmif *arb, u32 slvid, u32 reg, u32 mask, u32 shift)
112 {
113  u32 data;
114 
115  pmif_spi_read(arb, slvid, reg, &data);
116  data &= (mask << shift);
117  data >>= shift;
118 
119  return data;
120 }
121 
122 static void pmif_spi_write_field(struct pmif *arb, u32 slvid, u32 reg,
123  u32 val, u32 mask, u32 shift)
124 {
125  u32 old, new;
126 
127  pmif_spi_read(arb, slvid, reg, &old);
128  new = old & ~(mask << shift);
129  new |= (val << shift);
130  pmif_spi_write(arb, slvid, reg, new);
131 }
132 
133 static int is_pmif_init_done(struct pmif *arb)
134 {
135  if (read32(&arb->mtk_pmif->init_done) & 0x1)
136  return 0;
137 
138  return -E_NODEV;
139 }
140 
141 static const struct pmif pmif_spmi_arb[] = {
142  {
144  .ch = (struct chan_regs *)PMIF_SPMI_AP_CHAN,
145  .mstid = SPMI_MASTER_0,
146  .pmifid = PMIF_SPMI,
147  .write = pmif_spmi_write,
148  .read = pmif_spmi_read,
149  .write_field = pmif_spmi_write_field,
150  .read_field = pmif_spmi_read_field,
151  .is_pmif_init_done = is_pmif_init_done,
152  },
153 };
154 
155 static const struct pmif pmif_spi_arb[] = {
156  {
157  .mtk_pmif = (struct mtk_pmif_regs *)PMIF_SPI_BASE,
158  .ch = (struct chan_regs *)PMIF_SPI_AP_CHAN,
159  .pmifid = PMIF_SPI,
160  .write = pmif_spi_write,
161  .read = pmif_spi_read,
162  .write_field = pmif_spi_write_field,
163  .read_field = pmif_spi_read_field,
164  .is_pmif_init_done = is_pmif_init_done,
165  },
166 };
167 
168 struct pmif *get_pmif_controller(int inf, int mstid)
169 {
170  if (inf == PMIF_SPMI && mstid < ARRAY_SIZE(pmif_spmi_arb))
171  return (struct pmif *)&pmif_spmi_arb[mstid];
172  else if (inf == PMIF_SPI)
173  return (struct pmif *)&pmif_spi_arb[0];
174 
175  die("[%s] Failed to get pmif controller: inf = %d, mstid = %d\n", __func__, inf, mstid);
176  return NULL;
177 }
178 
179 static void pmif_select(enum pmic_interface mode)
180 {
181  unsigned int spi_spm_sleep_req, spi_scp_sleep_req,
182  spmi_spm_sleep_req, spmi_scp_sleep_req,
183  spi_md_ctl_pmif_rdy, spi_md_ctl_srclk_en, spi_md_ctl_srvol_en,
184  spmi_md_ctl_pmif_rdy, spmi_md_ctl_srclk_en, spmi_md_ctl_srvol_en,
185  spi_inf_srclken_rc_en, spi_other_inf_dcxo0_en, spi_other_inf_dcxo1_en,
186  spi_arb_srclken_rc_en, spi_arb_dcxo_conn_en, spi_arb_dcxo_nfc_en;
187 
188  switch (mode) {
189  case PMIF_VLD_RDY:
190  /* spm and scp sleep request disable spi and spmi */
191  spi_spm_sleep_req = 1;
192  spi_scp_sleep_req = 1;
193  spmi_spm_sleep_req = 1;
194  spmi_scp_sleep_req = 1;
195 
196  /*
197  * pmic vld/rdy control spi mode enable
198  * srclken control spi mode disable
199  * vreq control spi mode disable
200  */
201  spi_md_ctl_pmif_rdy = 1;
202  spi_md_ctl_srclk_en = 0;
203  spi_md_ctl_srvol_en = 0;
204  spmi_md_ctl_pmif_rdy = 1;
205  spmi_md_ctl_srclk_en = 0;
206  spmi_md_ctl_srvol_en = 0;
207 
208  /* srclken rc interface enable */
209  spi_inf_srclken_rc_en = 1;
210 
211  /* dcxo interface disable */
212  spi_other_inf_dcxo0_en = 0;
213  spi_other_inf_dcxo1_en = 0;
214 
215  /* srclken enable, dcxo0,1 disable */
216  spi_arb_srclken_rc_en = 1;
217  spi_arb_dcxo_conn_en = 0;
218  spi_arb_dcxo_nfc_en = 0;
219  break;
220 
221  case PMIF_SLP_REQ:
222  /* spm and scp sleep request enable spi and spmi */
223  spi_spm_sleep_req = 0;
224  spi_scp_sleep_req = 0;
225  spmi_spm_sleep_req = 0;
226  spmi_scp_sleep_req = 0;
227 
228  /*
229  * pmic vld/rdy control spi mode disable
230  * srclken control spi mode enable
231  * vreq control spi mode enable
232  */
233  spi_md_ctl_pmif_rdy = 0;
234  spi_md_ctl_srclk_en = 1;
235  spi_md_ctl_srvol_en = 1;
236  spmi_md_ctl_pmif_rdy = 0;
237  spmi_md_ctl_srclk_en = 1;
238  spmi_md_ctl_srvol_en = 1;
239 
240  /* srclken rc interface disable */
241  spi_inf_srclken_rc_en = 0;
242 
243  /* dcxo interface enable */
244  spi_other_inf_dcxo0_en = 1;
245  spi_other_inf_dcxo1_en = 1;
246 
247  /* srclken disable, dcxo0,1 enable */
248  spi_arb_srclken_rc_en = 0;
249  spi_arb_dcxo_conn_en = 1;
250  spi_arb_dcxo_nfc_en = 1;
251  break;
252 
253  default:
254  die("Can't support pmif mode %d\n", mode);
255  }
256 
258  PMIFSPI_SPM_SLEEP_REQ_SEL, spi_spm_sleep_req,
259  PMIFSPI_SCP_SLEEP_REQ_SEL, spi_scp_sleep_req);
261  PMIFSPMI_SPM_SLEEP_REQ_SEL, spmi_spm_sleep_req,
262  PMIFSPMI_SCP_SLEEP_REQ_SEL, spmi_scp_sleep_req);
264  PMIFSPI_MD_CTL_PMIF_RDY, spi_md_ctl_pmif_rdy,
265  PMIFSPI_MD_CTL_SRCLK_EN, spi_md_ctl_srclk_en,
266  PMIFSPI_MD_CTL_SRVOL_EN, spi_md_ctl_srvol_en);
268  PMIFSPMI_MD_CTL_PMIF_RDY, spmi_md_ctl_pmif_rdy,
269  PMIFSPMI_MD_CTL_SRCLK_EN, spmi_md_ctl_srclk_en,
270  PMIFSPMI_MD_CTL_SRVOL_EN, spmi_md_ctl_srvol_en);
272  PMIFSPI_INF_EN_SRCLKEN_RC_HW, spi_inf_srclken_rc_en);
274  PMIFSPI_OTHER_INF_DXCO0_EN, spi_other_inf_dcxo0_en,
275  PMIFSPI_OTHER_INF_DXCO1_EN, spi_other_inf_dcxo1_en);
277  PMIFSPI_ARB_EN_SRCLKEN_RC_HW, spi_arb_srclken_rc_en,
278  PMIFSPI_ARB_EN_DCXO_CONN, spi_arb_dcxo_conn_en,
279  PMIFSPI_ARB_EN_DCXO_NFC, spi_arb_dcxo_nfc_en);
280 }
281 
283 {
284  if (CONFIG(SRCLKEN_RC_SUPPORT)) {
285  printk(BIOS_INFO, "%s: Select PMIF_VLD_RDY\n", __func__);
287  } else {
288  printk(BIOS_INFO, "%s: Select PMIF_SLP_REQ\n", __func__);
290  }
291 }
292 
293 int mtk_pmif_init(void)
294 {
295  int ret;
296 
297  ret = pmif_clk_init();
298  if (!ret)
300  if (!ret)
302 
303  return ret;
304 }
static void write32(void *addr, uint32_t val)
Definition: mmio.h:40
static uint32_t read32(const void *addr)
Definition: mmio.h:22
#define ARRAY_SIZE(a)
Definition: helpers.h:12
static u32 addr
Definition: cirrus.c:14
static int is_pmif_init_done(struct pmif *arb)
Definition: pmif.c:133
static void pmif_select(enum pmic_interface mode)
Definition: pmif.c:179
static const struct pmif pmif_spi_arb[]
Definition: pmif.c:155
static u32 pmif_spi_read_field(struct pmif *arb, u32 slvid, u32 reg, u32 mask, u32 shift)
Definition: pmif.c:111
static const struct pmif pmif_spmi_arb[]
Definition: pmif.c:141
static void pmif_spmi_write(struct pmif *arb, u32 slvid, u32 reg, u32 data)
Definition: pmif.c:73
static int pmif_check_swinf(struct pmif *arb, long timeout_us, u32 expected_status)
Definition: pmif.c:14
static u32 pmif_spmi_read_field(struct pmif *arb, u32 slvid, u32 reg, u32 mask, u32 shift)
Definition: pmif.c:78
void pmwrap_interface_init(void)
Definition: pmif.c:282
static void pmif_spi_write(struct pmif *arb, u32 slvid, u32 reg, u32 data)
Definition: pmif.c:106
static void pmif_spi_write_field(struct pmif *arb, u32 slvid, u32 reg, u32 val, u32 mask, u32 shift)
Definition: pmif.c:122
struct pmif * get_pmif_controller(int inf, int mstid)
Definition: pmif.c:168
static void pmif_send_cmd(struct pmif *arb, int write, u32 opc, u32 slvid, u32 addr, u32 *rdata, u32 wdata, u32 len)
Definition: pmif.c:29
static void pmif_spi_read(struct pmif *arb, u32 slvid, u32 reg, u32 *data)
Definition: pmif.c:100
static void pmif_spmi_read(struct pmif *arb, u32 slvid, u32 reg, u32 *data)
Definition: pmif.c:67
int mtk_pmif_init(void)
Definition: pmif.c:293
static void pmif_spmi_write_field(struct pmif *arb, u32 slvid, u32 reg, u32 val, u32 mask, u32 shift)
Definition: pmif.c:89
#define printk(level,...)
Definition: stdlib.h:16
void __noreturn die(const char *fmt,...)
Definition: die.c:17
@ CONFIG
Definition: dsi_common.h:201
@ E_TIMEOUT
#define SET32_BITFIELDS(addr,...)
Definition: mmio.h:201
static int stopwatch_expired(struct stopwatch *sw)
Definition: timer.h:152
static void stopwatch_init_usecs_expire(struct stopwatch *sw, long us)
Definition: timer.h:127
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
static struct dramc_channel const ch[2]
#define PMIF_SPMI_AP_CHAN
Definition: pmif.h:122
#define PMIF_SPI_AP_CHAN
Definition: pmif.h:123
@ PMIF_SPI
Definition: pmif_common.h:39
@ PMIF_SPMI
Definition: pmif_common.h:40
@ E_NODEV
Definition: pmif_common.h:46
@ PMIF_CMD_REG_0
Definition: pmif_common.h:9
@ PMIF_CMD_EXT_REG_LONG
Definition: pmif_common.h:12
pmic_interface
Definition: pmif_common.h:55
@ PMIF_SLP_REQ
Definition: pmif_common.h:57
@ PMIF_VLD_RDY
Definition: pmif_common.h:56
int pmif_spi_init(struct pmif *arb)
Definition: pmif_spi.c:275
int pmif_spmi_init(struct pmif *arb)
Definition: pmif_spmi.c:186
#define SWINF_FSM_IDLE
Definition: pmif_sw.h:7
#define GET_SWINF_0_FSM(x)
Definition: pmif_sw.h:13
@ PMIF_WAIT_IDLE_US
Definition: pmif_sw.h:17
@ PMIF_READ_US
Definition: pmif_sw.h:16
int pmif_clk_init(void)
Definition: pmif_clk.c:105
#define SWINF_FSM_WFVLDCLR
Definition: pmif_sw.h:10
static const int mask[4]
Definition: gpio.c:308
@ PMIF_SPMI_BASE
Definition: addressmap.h:31
@ PMIF_SPI_BASE
Definition: addressmap.h:30
@ SPMI_MASTER_0
Definition: spmi.h:9
#define NULL
Definition: stddef.h:19
uint32_t u32
Definition: stdint.h:51
u32 ch_sta
Definition: pmif_common.h:22
u32 ch_send
Definition: pmif_common.h:16
u32 ch_rdy
Definition: pmif_common.h:21
u32 spi_mode_ctrl
Definition: pmif.h:59
u32 inf_en
Definition: pmif.h:16
u32 other_inf_en
Definition: pmif.h:17
u32 init_done
Definition: pmif.h:11
u32 arb_en
Definition: pmif.h:32
u32 sleep_protection_ctrl
Definition: pmif.h:57
struct chan_regs * ch
Definition: pmif_common.h:27
struct mtk_pmif_regs * mtk_pmif
Definition: pmif_common.h:26
u32 mstid
Definition: pmif_common.h:29
u8 val
Definition: sys.c:300