xref: /aosp_15_r20/external/coreboot/src/drivers/i2c/ww_ring/ww_ring_programs.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
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 "drivers/i2c/ww_ring/ww_ring_programs.h"
19 
20 /****************************************************************
21  *   LED ring program definitions for different patterns.
22  *
23  * Comments below are real lp55231 source code, they are compiled using
24  * lasm.exe, the TI tool available from their Web site (search for lp55231)
25  * and running only on Windows :P.
26  *
27  * Different hex dumps are results of tweaking the source code parameters to
28  * achieve desirable LED ring behavior. It is possible to use just one code
29  * dump and replace certain values in the body to achieve different behaviour
30  * with the same basic dump, but keeping track of location to tweak with every
31  * code change would be quite tedious.
32  */
33 
34 /*
35  * Solid LED display, the arguments of the set_pwm commands set intensity and
36  * color of the display:
37 
38 row_red:   dw 0000000000000001b
39 row_green: dw 0000000000000010b
40 row_blue:  dw 0000000000000100b
41 
42 .segment program1
43 	mux_map_addr row_red
44 	set_pwm 0
45 	end
46 
47 .segment program2
48 	mux_map_addr row_green
49 	set_pwm 0
50 	end
51 
52 .segment program3
53 	mux_map_addr row_blue
54 	set_pwm 0
55 	end
56 */
57 
58 /* RGB set to 000000, resulting in all LEDs off. */
59 static const uint8_t solid_000000_text[] = {
60 	0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x9F, 0x80,
61 	0x40,    0, 0xC0, 0x00, 0x9F, 0x81, 0x40,    0,
62 	0xC0, 0x00, 0x9F, 0x82, 0x40,    0, 0xC0, 0x00
63 };
64 
65 /* Rgb set to 128, resulting in a brightish white color. */
66 static const uint8_t solid_808080_text[] = {
67 	0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x9F, 0x80,
68 	0x40,  128, 0xC0, 0x00, 0x9F, 0x81, 0x40,  128,
69 	0xC0, 0x00, 0x9F, 0x82, 0x40,  128, 0xC0, 0x00
70 };
71 
72 static const TiLp55231Program solid_808080_program = {
73 	solid_808080_text,
74 	sizeof(solid_808080_text),
75 	0,
76 	{ 3, 6, 9 }
77 };
78 
79 static const TiLp55231Program solid_000000_program = {
80 	solid_000000_text,
81 	sizeof(solid_000000_text),
82 	0,
83 	{ 3, 6, 9 }
84 };
85 
86 /*
87  * Blinking patterns are trickier then solid ones.
88  *
89  * The three internal engines seem to be competing for resources and get out
90  * of sync in seconds if left running asynchronously.
91  *
92  * When solid patterns are deployed with instantaneous color intensity
93  * changes, all three LEDs can be controlled by one engine in sequential
94  * accesses. But the controllers still need to be synchronized.
95  *
96  * The maximum timer duration of lp55231 is .48 seconds. To achieve longer
97  * blinking intervals the loops delays are deployed. Only the first controller
98  * intervals need to be changed, as the second one is in lockstep with the
99  * first.
100  *
101  * The time granularity is set at .1 second (see commands 'wait 0.1' in the
102  * code), and then the loop counters can be set up to 63 (registers rb and rc),
103  * which allows to generate intervals up to 6.3 seconds in .1 second
104  * increments.
105  */
106 /*
107  * blink_solid1.src
108 row_red:   dw 0000000000000001b
109 row_green: dw 0000000000000010b
110 row_blue:  dw 0000000000000100b
111 
112 .segment program1
113 	ld ra, 2   # LED on duration
114 	ld rb, 2   # LED off duration
115 	mux_map_addr row_red
116 loop:
117 	ld rc, 1        ; red intensity
118 	set_pwm rc
119 	mux_map_addr row_green
120 	ld rc, 50       ; green intensity
121 	set_pwm rc
122 	mux_map_addr row_blue
123 	ld rc, 155      ; blue intensity
124 	set_pwm rc
125 wait1:
126 	wait 0.1
127 	branch ra, wait1
128 	set_pwm 0
129 	mux_map_addr row_green
130 	set_pwm 0
131 	mux_map_addr row_red
132 	set_pwm 0
133 wait2:
134 	wait 0.1
135 	branch rb, wait2
136 	branch 0, loop
137 .segment program2
138 	 end
139 .segment program3
140 	 end
141 */
142 static const uint8_t blink_wipeout1_text[] = {
143 	0x00,  0x01,  0x00,  0x02,  0x00,  0x04,  0x90,  0x02,
144 	0x94,  0x02,  0x9f,  0x80,  0x98,     1,  0x84,  0x62,
145 	0x9f,  0x81,  0x98,    50,  0x84,  0x62,  0x9f,  0x82,
146 	0x98,   155,  0x84,  0x62,  0x4c,  0x00,  0x86,  0x2c,
147 	0x40,  0x00,  0x9f,  0x81,  0x40,  0x00,  0x9f,  0x80,
148 	0x40,  0x00,  0x4c,  0x00,  0x86,  0x49,  0xa0,  0x03,
149 	0xc0,  0x00,  0xc0,  0x00,  0x00,
150 };
151 
152 static const TiLp55231Program blink_wipeout1_program = {
153 	blink_wipeout1_text,
154 	sizeof(blink_wipeout1_text),
155 	0,
156 	{ 3,  24,  25,  }
157 };
158 
159 static const uint8_t blink_recovery1_text[] = {
160 	0x00,  0x01,  0x00,  0x02,  0x00,  0x04,  0x90,  0x02,
161 	0x94,  0x02,  0x9f,  0x80,  0x98,   255,  0x84,  0x62,
162 	0x9f,  0x81,  0x98,   100,  0x84,  0x62,  0x9f,  0x82,
163 	0x98,    10,  0x84,  0x62,  0x4c,  0x00,  0x86,  0x2c,
164 	0x40,  0x00,  0x9f,  0x81,  0x40,  0x00,  0x9f,  0x80,
165 	0x40,  0x00,  0x4c,  0x00,  0x86,  0x49,  0xa0,  0x03,
166 	0xc0,  0x00,  0xc0,  0x00,  0x00,
167 };
168 static const TiLp55231Program blink_recovery1_program = {
169 	blink_recovery1_text,
170 	sizeof(blink_recovery1_text),
171 	0,
172 	{ 3,  24,  25,  }
173 };
174 
175 /*
176  * fade_in1.src
177  *
178  row_red:   dw 0000000000000001b
179  row_green: dw 0000000000000010b
180  row_blue:  dw 0000000000000100b
181 
182  .segment program1
183 	mux_map_addr row_red
184 	set_pwm 1h
185 	trigger s{2|3}
186 	end
187  .segment program2
188 	mux_map_addr row_green
189 	set_pwm 0h
190 	trigger w{1}
191 	ramp 2, 50
192 	end
193 .segment program3
194 	mux_map_addr row_blue
195 	set_pwm 0h
196  loop3: trigger w{1}
197 	ramp 2, 155
198 	end
199 */
200 
201 static const uint8_t fade_in1_text[] = {
202 	0x00,  0x01,  0x00,  0x02,  0x00,  0x04,  0x9f,  0x80,
203 	0x40,  0x01,  0xe0,  0x0c,  0xc0,  0x00,  0x9f,  0x81,
204 	0x40,  0x00,  0xe0,  0x80,  0x46,  0x32,  0xc0,  0x00,
205 	0x9f,  0x82,  0x40,  0x00,  0xe0,  0x80,  0x34,  0x9B,
206 	0xc0,  0x00,  0x00,
207 };
208 static const TiLp55231Program fade_in1_program = {
209 	fade_in1_text,
210 	sizeof(fade_in1_text),
211 	0,
212 	{ 3,  7,  12,  }
213 };
214 
215 const WwRingStateProg wwr_state_programs[] = {
216 	/*
217 	 * for test purposes the blank screen program is set to blinking, will
218 	 * be changed soon.
219 	 */
220 	{WWR_ALL_OFF, {&solid_000000_program} },
221 	{WWR_RECOVERY_PUSHED, {&solid_808080_program} },
222 	{WWR_WIPEOUT_REQUEST, {&blink_wipeout1_program} },
223 	{WWR_RECOVERY_REQUEST, {&blink_recovery1_program} },
224 	{WWR_NORMAL_BOOT, {&fade_in1_program} },
225 	{}, /* Empty record to mark the end of the table. */
226 };
227