coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
ww_ring.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 /*
4  * This is a driver for the Whirlwind LED ring, which is equipped with two LED
5  * microcontrollers TI LP55231 (http://www.ti.com/product/lp55231), each of
6  * them driving three multicolor LEDs.
7  *
8  * The only connection between the ring and the main board is an i2c bus.
9  *
10  * This driver imitates a depthcharge display device. On initialization the
11  * driver sets up the controllers to prepare them to accept programs to run.
12  *
13  * When a certain vboot state needs to be indicated, the program for that
14  * state is loaded into the controllers, resulting in the state appropriate
15  * LED behavior.
16  */
17 
18 #include <console/console.h>
19 #include <delay.h>
20 #include <device/i2c_simple.h>
21 #include <string.h>
22 
24 
25 /* I2c address of the first of the controllers, the rest are contiguous. */
26 #define WW_RING_BASE_ADDR 0x32
27 
28 /* Key lp55231 registers. */
29 #define LP55231_ENGCTRL1_REG 0x00
30 #define LP55231_ENGCTRL2_REG 0x01
31 #define LP55231_D1_CRT_CTRL_REG 0x26
32 #define LP55231_MISC_REG 0x36
33 #define LP55231_VARIABLE_REG 0x3c
34 #define LP55231_RESET_REG 0x3d
35 #define LP55231_ENG1_PROG_START 0x4c
36 #define LP55231_PROG_PAGE_REG 0x4f
37 #define LP55231_PROG_BASE_REG 0x50
38 
39 /* LP55231_D1_CRT_CTRL_REG, default value, applies to all nine of them */
40 #define LP55231_CRT_CTRL_DEFAULT 0xaf
41 
42 /* LP55231_ENGCTRL1_REG fields */
43 #define LP55231_ENGCTRL1_CHIP_EN 0x40
44 #define LP55231_ENGCTRL1_ALL_ENG_GO 0x2a
45 
46 /* LP55231_ENGCTRL2_REG fields. */
47 #define LP55231_ENGCTRL2_ALL_DISABLE 0
48 #define LP55231_ENGCTRL2_ALL_LOAD 0x15
49 #define LP55231_ENGCTRL2_ALL_RUN 0x2a
50 
51 /* LP55231_MISC_REG fields. */
52 #define LP55231_MISC_AUTOINCR (1 << 6)
53 #define LP55231_MISC_PUMP_1X (1 << 3)
54 #define LP55231_MISC_INT_CLK (3 << 0)
55 
56 /*
57  * LP55231_VARIABLE_REG cookie value. It indicates to depthcharge that the
58  * ring has been initialized by coreboot.
59  */
60 #define LP55231_VARIABLE_COOKIE 0xb4
61 
62 /* Goes into LP55231_RESET_REG to reset the chip. */
63 #define LP55231_RESET_VALUE 0xff
64 
65 /*
66  * The controller has 192 bytes of SRAM for code/data, available as six 32 byte
67  * pages.
68  */
69 #define LP55231_PROG_PAGE_SIZE 32
70 #define LP55231_PROG_PAGES 6
71 #define LP55231_MAX_PROG_SIZE (LP55231_PROG_PAGE_SIZE * LP55231_PROG_PAGES)
72 
73 /*
74  * Structure to cache data relevant to accessing one controller. I2c interface
75  * to use, device address on the i2c bus and a data buffer for write
76  * transactions. The most bytes sent at a time is the register address plus
77  * the program page size.
78  */
79 typedef struct {
80  unsigned int i2c_bus;
82  uint8_t data_buffer[LP55231_PROG_PAGE_SIZE + 1];
83 } TiLp55231;
84 
85 static void ww_ring_init(unsigned int i2c_bus);
86 
87 /* Controller descriptors. */
89 
90 /*
91  * i2c transfer function for the driver. To keep things simple, the function
92  * repeats the transfer, if the first attempt fails. This is OK with the
93  * controller and makes it easier to handle errors.
94  *
95  * Note that the reset register accesses are expected to fail on writes, but
96  * due to a bug in the ipq806x i2c controller, the error is reported on the
97  * following read attempt.
98  *
99  * To work around this the driver writes and then reads the reset register,
100  * the transfer function ignores errors when accessing the reset register.
101  */
102 
103 static int ledc_transfer(TiLp55231 *ledc, struct i2c_msg *segs,
104  int seg_count, int reset)
105 {
106  int rv, max_attempts = 2;
107 
108  while (max_attempts--) {
109  rv = i2c_transfer(ledc->i2c_bus, segs, seg_count);
110 
111  /* Accessing reset register is expected to fail. */
112  if (!rv || reset)
113  break;
114  }
115 
116  if (rv) {
117  if (!reset)
119  "%s: dev %#x, reg %#x, %s transaction error.\n",
120  __func__, segs->slave, segs->buf[0],
121  seg_count == 1 ? "write" : "read");
122  else
123  rv = 0;
124  }
125 
126  return rv;
127 }
128 
129 /*
130  * The controller is programmed to autoincrement on writes, so up to page size
131  * bytes can be transmitted in one write transaction.
132  */
133 static int ledc_write(TiLp55231 *ledc, uint8_t start_addr,
134  const uint8_t *data, unsigned int count)
135 {
136  struct i2c_msg seg;
137 
138  if (count > (sizeof(ledc->data_buffer) - 1)) {
139  printk(BIOS_WARNING, "%s: transfer size too large (%d bytes)\n",
140  __func__, count);
141  return -1;
142  }
143 
144  memcpy(ledc->data_buffer + 1, data, count);
145  ledc->data_buffer[0] = start_addr;
146 
147  seg.flags = 0;
148  seg.slave = ledc->dev_addr;
149  seg.buf = ledc->data_buffer;
150  seg.len = count + 1;
151 
152  return ledc_transfer(ledc, &seg, 1, start_addr == LP55231_RESET_REG);
153 }
154 
155 /* To keep things simple, read is limited to one byte at a time. */
156 static int ledc_read(TiLp55231 *ledc, uint8_t addr, uint8_t *data)
157 {
158  struct i2c_msg seg[2];
159 
160  seg[0].flags = 0;
161  seg[0].slave = ledc->dev_addr;
162  seg[0].buf = &addr;
163  seg[0].len = 1;
164 
165  seg[1].flags = I2C_M_RD;
166  seg[1].slave = ledc->dev_addr;
167  seg[1].buf = data;
168  seg[1].len = 1;
169 
170  return ledc_transfer(ledc, seg, ARRAY_SIZE(seg),
172 }
173 
174 /*
175  * Reset transaction is expected to result in a failing i2c command. But even
176  * before trying it, read the reset register, which is supposed to always
177  * return 0. If this fails - there is no lp55231 at this address.
178  *
179  * Return 0 on success, -1 on failure to detect controller.
180  */
181 static int ledc_reset(TiLp55231 *ledc)
182 {
183  uint8_t data;
184 
185  data = ~0;
186  ledc_read(ledc, LP55231_RESET_REG, &data);
187  if (data) {
189  "WW_RING: no controller found at address %#2.2x\n",
190  ledc->dev_addr);
191  return -1;
192  }
193 
194  data = LP55231_RESET_VALUE;
195  ledc_write(ledc, LP55231_RESET_REG, &data, 1);
196 
197  /*
198  * This read is not necessary for the chip reset, but is required to
199  * work around the i2c driver bug where the missing ACK on the last
200  * byte of the write transaction is ignored, but the next transaction
201  * fails.
202  */
203  ledc_read(ledc, LP55231_RESET_REG, &data);
204  return 0;
205 }
206 
207 /*
208  * Write a program into the internal lp55231 memory. Split write transactions
209  * into sections fitting into memory pages.
210  */
211 static void ledc_write_program(TiLp55231 *ledc, uint8_t load_addr,
212  const uint8_t *program, unsigned int count)
213 {
214  uint8_t page_num = load_addr / LP55231_PROG_PAGE_SIZE;
215  unsigned int page_offs = load_addr % LP55231_PROG_PAGE_SIZE;
216 
217  if ((load_addr + count) > LP55231_MAX_PROG_SIZE) {
219  "%s: program of size %#x does not fit at addr %#x\n",
220  __func__, count, load_addr);
221  return;
222  }
223 
224  while (count) {
225  unsigned int segment_size = LP55231_PROG_PAGE_SIZE - page_offs;
226 
227  if (segment_size > count)
228  segment_size = count;
229 
230  ledc_write(ledc, LP55231_PROG_PAGE_REG, &page_num, 1);
231  ledc_write(ledc, LP55231_PROG_BASE_REG + page_offs,
232  program, segment_size);
233 
234  count -= segment_size;
235  program += segment_size;
236  page_offs = 0;
237  page_num++;
238  }
239 }
240 
242 {
244  udelay(1500);
245 }
246 
247 /* Run an lp55231 program on a controller. */
248 static void ledc_run_program(TiLp55231 *ledc,
249  const TiLp55231Program *program_desc)
250 {
251  int i;
252  uint8_t data;
253 
254  /* All engines on hold. */
256  ledc_write(ledc, LP55231_ENGCTRL1_REG, &data, 1);
257 
260 
261  ledc_write_program(ledc, program_desc->load_addr,
262  program_desc->program_text,
263  program_desc->program_size);
264 
265  for (i = 0; i < sizeof(program_desc->engine_start_addr); i++)
267  program_desc->engine_start_addr + i, 1);
268 
270  ledc_write(ledc, LP55231_ENGCTRL1_REG, &data, 1);
272 }
273 
274 /*
275  * Initialize a controller to a state were it is ready to accept programs, and
276  * try to confirm that we are in fact talking to a lp55231
277  */
278 static int ledc_init_validate(TiLp55231 *ledc)
279 {
280  uint8_t data;
281  int i;
282 
283  if (ledc_reset(ledc))
284  return -1;
285 
286  /* Enable the chip, keep engines in hold state. */
288  ledc_write(ledc, LP55231_ENGCTRL1_REG, &data, 1);
289 
290  /*
291  * Internal clock, 3.3V output (pump 1x), autoincrement on multibyte
292  * writes.
293  */
294  data = LP55231_MISC_AUTOINCR |
296  ledc_write(ledc, LP55231_MISC_REG, &data, 1);
297 
298  /*
299  * All nine current control registers are supposed to return the same
300  * value at reset.
301  */
302  for (i = 0; i < 9; i++) {
303  ledc_read(ledc, LP55231_D1_CRT_CTRL_REG + i, &data);
304  if (data != LP55231_CRT_CTRL_DEFAULT) {
306  "%s: read %#2.2x from register %#x\n", __func__,
307  data, LP55231_D1_CRT_CTRL_REG + i);
308  return -1;
309  }
310  }
311 
312  /*
313  * Signal Depthcharge that the controller has been initiazed by
314  * coreboot.
315  */
317  ledc_write(ledc, LP55231_VARIABLE_REG, &data, 1);
318 
319  return 0;
320 }
321 
322 /*
323  * Find a program matching screen type, and run it on both controllers, if
324  * found.
325  */
327 {
328  static int initted;
329  const WwRingStateProg *wwr_prog;
330 
331  if (!initted) {
333  initted = 1;
334  }
335 
336  /* Last entry does not have any actual programs defined. */
337  for (wwr_prog = wwr_state_programs; wwr_prog->programs[0]; wwr_prog++)
338  if (wwr_prog->led_pattern == pattern) {
339  int j;
340 
341  /*
342  * First stop all running programs to avoid
343  * inerference between the controllers.
344  */
345  for (j = 0; j < WW_RING_NUM_LED_CONTROLLERS; j++) {
346  if (!lp55231s[j].dev_addr)
347  continue;
349  (lp55231s + j,
351  }
352 
353  for (j = 0; j < WW_RING_NUM_LED_CONTROLLERS; j++) {
354  if (!lp55231s[j].dev_addr)
355  continue;
357  wwr_prog->programs[j]);
358  }
359  return 0;
360  }
361 
362  printk(BIOS_WARNING, "%s: did not find program for pattern %d\n",
363  __func__, pattern);
364 
365  return -1;
366 }
367 
368 #define LP55231_I2C_BASE_ADDR 0x32
369 
370 static void ww_ring_init(unsigned int i2c_bus)
371 {
372  TiLp55231 *ledc;
373  int i, count = 0;
374 
375  for (i = 0, ledc = lp55231s;
377  i++, ledc++) {
378 
379  ledc->i2c_bus = i2c_bus;
380  ledc->dev_addr = LP55231_I2C_BASE_ADDR + i;
381 
382  if (!ledc_init_validate(ledc))
383  count++;
384  else
385  ledc->dev_addr = 0; /* Mark disabled. */
386  }
387 
388  printk(BIOS_INFO, "WW_RING: initialized %d out of %d\n", count, i);
389  if (count != i) {
390  if (count)
392  "WW_RING: will keep going anyway\n");
393  else
395  "WW_RING: LED ring not present\n");
396  }
397 }
pte_t value
Definition: mmu.c:91
void * memcpy(void *dest, const void *src, size_t n)
Definition: memcpy.c:7
static const u32 pattern[8]
Definition: ast_post.c:428
#define ARRAY_SIZE(a)
Definition: helpers.h:12
static u32 addr
Definition: cirrus.c:14
#define printk(level,...)
Definition: stdlib.h:16
static int i2c_transfer(unsigned int bus, struct i2c_msg *segments, int count)
Definition: i2c_simple.h:42
#define I2C_M_RD
Definition: i2c.h:34
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_WARNING
BIOS_WARNING - Bad configuration.
Definition: loglevel.h:86
static const uintptr_t i2c_bus[]
Definition: i2c.c:41
unsigned char uint8_t
Definition: stdint.h:8
const uint8_t * program_text
uint8_t engine_start_addr[LP55231_NUM_OF_ENGINES]
uint8_t dev_addr
Definition: ww_ring.c:81
uint8_t data_buffer[LP55231_PROG_PAGE_SIZE+1]
Definition: ww_ring.c:82
unsigned int i2c_bus
Definition: ww_ring.c:80
enum display_pattern led_pattern
const TiLp55231Program * programs[WW_RING_NUM_LED_CONTROLLERS]
Definition: i2c.c:65
struct i2c_msg - an I2C transaction segment beginning with START @addr: Slave address,...
Definition: i2c.h:32
uint16_t len
Definition: i2c.h:39
uint16_t slave
Definition: i2c.h:38
uint16_t flags
Definition: i2c.h:33
uint8_t * buf
Definition: i2c.h:40
static void __noreturn reset(void)
void udelay(uint32_t us)
Definition: udelay.c:15
#define count
#define LP55231_D1_CRT_CTRL_REG
Definition: ww_ring.c:31
#define LP55231_ENG1_PROG_START
Definition: ww_ring.c:35
static void ledc_write_program(TiLp55231 *ledc, uint8_t load_addr, const uint8_t *program, unsigned int count)
Definition: ww_ring.c:211
#define LP55231_PROG_PAGE_REG
Definition: ww_ring.c:36
static int ledc_write(TiLp55231 *ledc, uint8_t start_addr, const uint8_t *data, unsigned int count)
Definition: ww_ring.c:133
#define LP55231_RESET_VALUE
Definition: ww_ring.c:63
#define LP55231_RESET_REG
Definition: ww_ring.c:34
#define LP55231_ENGCTRL2_ALL_RUN
Definition: ww_ring.c:49
int ww_ring_display_pattern(unsigned int i2c_bus, enum display_pattern pattern)
Definition: ww_ring.c:326
static void ledc_write_engctrl2(TiLp55231 *ledc, uint8_t value)
Definition: ww_ring.c:241
static int ledc_init_validate(TiLp55231 *ledc)
Definition: ww_ring.c:278
static void ledc_run_program(TiLp55231 *ledc, const TiLp55231Program *program_desc)
Definition: ww_ring.c:248
#define LP55231_CRT_CTRL_DEFAULT
Definition: ww_ring.c:40
#define LP55231_VARIABLE_COOKIE
Definition: ww_ring.c:60
#define LP55231_ENGCTRL2_ALL_DISABLE
Definition: ww_ring.c:47
static TiLp55231 lp55231s[WW_RING_NUM_LED_CONTROLLERS]
Definition: ww_ring.c:88
#define LP55231_I2C_BASE_ADDR
Definition: ww_ring.c:368
#define LP55231_ENGCTRL2_ALL_LOAD
Definition: ww_ring.c:48
#define LP55231_ENGCTRL1_CHIP_EN
Definition: ww_ring.c:43
#define LP55231_MISC_PUMP_1X
Definition: ww_ring.c:53
#define LP55231_VARIABLE_REG
Definition: ww_ring.c:33
#define LP55231_PROG_BASE_REG
Definition: ww_ring.c:37
#define LP55231_ENGCTRL1_REG
Definition: ww_ring.c:29
#define LP55231_MISC_REG
Definition: ww_ring.c:32
static int ledc_read(TiLp55231 *ledc, uint8_t addr, uint8_t *data)
Definition: ww_ring.c:156
#define LP55231_MAX_PROG_SIZE
Definition: ww_ring.c:71
#define LP55231_ENGCTRL1_ALL_ENG_GO
Definition: ww_ring.c:44
static int ledc_reset(TiLp55231 *ledc)
Definition: ww_ring.c:181
#define LP55231_MISC_INT_CLK
Definition: ww_ring.c:54
static void ww_ring_init(unsigned int i2c_bus)
Definition: ww_ring.c:370
#define LP55231_MISC_AUTOINCR
Definition: ww_ring.c:52
#define LP55231_ENGCTRL2_REG
Definition: ww_ring.c:30
#define LP55231_PROG_PAGE_SIZE
Definition: ww_ring.c:69
static int ledc_transfer(TiLp55231 *ledc, struct i2c_msg *segs, int seg_count, int reset)
Definition: ww_ring.c:103
display_pattern
Definition: ww_ring.h:10
const WwRingStateProg wwr_state_programs[]
#define WW_RING_NUM_LED_CONTROLLERS