1/*
2 * Copyright 2013 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 */
24
25#define T_TIMEOUT  2200000
26#define T_RISEFALL 1000
27#define T_HOLD     5000
28
29#ifdef INCLUDE_PROC
30process(PROC_I2C_, #i2c_init, #i2c_recv)
31#endif
32
33/******************************************************************************
34 * I2C_ data segment
35 *****************************************************************************/
36#ifdef INCLUDE_DATA
37i2c_scl_map:
38.b32 NV_PPWR_OUTPUT_I2C_0_SCL
39.b32 NV_PPWR_OUTPUT_I2C_1_SCL
40.b32 NV_PPWR_OUTPUT_I2C_2_SCL
41.b32 NV_PPWR_OUTPUT_I2C_3_SCL
42.b32 NV_PPWR_OUTPUT_I2C_4_SCL
43.b32 NV_PPWR_OUTPUT_I2C_5_SCL
44.b32 NV_PPWR_OUTPUT_I2C_6_SCL
45.b32 NV_PPWR_OUTPUT_I2C_7_SCL
46.b32 NV_PPWR_OUTPUT_I2C_8_SCL
47.b32 NV_PPWR_OUTPUT_I2C_9_SCL
48i2c_sda_map:
49.b32 NV_PPWR_OUTPUT_I2C_0_SDA
50.b32 NV_PPWR_OUTPUT_I2C_1_SDA
51.b32 NV_PPWR_OUTPUT_I2C_2_SDA
52.b32 NV_PPWR_OUTPUT_I2C_3_SDA
53.b32 NV_PPWR_OUTPUT_I2C_4_SDA
54.b32 NV_PPWR_OUTPUT_I2C_5_SDA
55.b32 NV_PPWR_OUTPUT_I2C_6_SDA
56.b32 NV_PPWR_OUTPUT_I2C_7_SDA
57.b32 NV_PPWR_OUTPUT_I2C_8_SDA
58.b32 NV_PPWR_OUTPUT_I2C_9_SDA
59#if NVKM_PPWR_CHIPSET < GF119
60i2c_ctrl:
61.b32 0x00e138
62.b32 0x00e150
63.b32 0x00e168
64.b32 0x00e180
65.b32 0x00e254
66.b32 0x00e274
67.b32 0x00e764
68.b32 0x00e780
69.b32 0x00e79c
70.b32 0x00e7b8
71#endif
72#endif
73
74/******************************************************************************
75 * I2C_ code segment
76 *****************************************************************************/
77#ifdef INCLUDE_CODE
78
79// $r3  - value
80// $r2  - sda line
81// $r1  - scl line
82// $r0  - zero
83i2c_drive_scl:
84	cmp b32 $r3 0
85	bra e #i2c_drive_scl_lo
86	nv_iowr(NV_PPWR_OUTPUT_SET, $r1)
87	ret
88	i2c_drive_scl_lo:
89	nv_iowr(NV_PPWR_OUTPUT_CLR, $r1)
90	ret
91
92i2c_drive_sda:
93	cmp b32 $r3 0
94	bra e #i2c_drive_sda_lo
95	nv_iowr(NV_PPWR_OUTPUT_SET, $r2)
96	ret
97	i2c_drive_sda_lo:
98	nv_iowr(NV_PPWR_OUTPUT_CLR, $r2)
99	ret
100
101i2c_sense_scl:
102	bclr $flags $p1
103	nv_iord($r3, NV_PPWR_INPUT)
104	and $r3 $r1
105	bra z #i2c_sense_scl_done
106		bset $flags $p1
107	i2c_sense_scl_done:
108	ret
109
110i2c_sense_sda:
111	bclr $flags $p1
112	nv_iord($r3, NV_PPWR_INPUT)
113	and $r3 $r2
114	bra z #i2c_sense_sda_done
115		bset $flags $p1
116	i2c_sense_sda_done:
117	ret
118
119#define i2c_drive_scl(v) /*
120*/	mov $r3 (v) /*
121*/	call(i2c_drive_scl)
122#define i2c_drive_sda(v) /*
123*/	mov $r3 (v) /*
124*/	call(i2c_drive_sda)
125#define i2c_sense_scl() /*
126*/	call(i2c_sense_scl)
127#define i2c_sense_sda() /*
128*/	call(i2c_sense_sda)
129#define i2c_delay(v) /*
130*/	mov $r14 (v) /*
131*/	call(nsec)
132
133#define i2c_trace_init() /*
134*/	imm32($r6, 0x10000000) /*
135*/	sub b32 $r7 $r6 1 /*
136*/
137#define i2c_trace_down() /*
138*/	shr b32 $r6 4 /*
139*/	push $r5 /*
140*/	shl b32 $r5 $r6 4 /*
141*/	sub b32 $r5 $r6 /*
142*/	not b32 $r5 /*
143*/	and $r7 $r5 /*
144*/	pop $r5 /*
145*/
146#define i2c_trace_exit() /*
147*/	shl b32 $r6 4 /*
148*/
149#define i2c_trace_next() /*
150*/	add b32 $r7 $r6 /*
151*/
152#define i2c_trace_call(func) /*
153*/	i2c_trace_next() /*
154*/	i2c_trace_down() /*
155*/	call(func) /*
156*/	i2c_trace_exit() /*
157*/
158
159i2c_raise_scl:
160	push $r4
161	mov $r4 (T_TIMEOUT / T_RISEFALL)
162	i2c_drive_scl(1)
163	i2c_raise_scl_wait:
164		i2c_delay(T_RISEFALL)
165		i2c_sense_scl()
166		bra $p1 #i2c_raise_scl_done
167		sub b32 $r4 1
168		bra nz #i2c_raise_scl_wait
169	i2c_raise_scl_done:
170	pop $r4
171	ret
172
173i2c_start:
174	i2c_sense_scl()
175	bra not $p1 #i2c_start_rep
176	i2c_sense_sda()
177	bra not $p1 #i2c_start_rep
178	bra #i2c_start_send
179	i2c_start_rep:
180		i2c_drive_scl(0)
181		i2c_drive_sda(1)
182		i2c_trace_call(i2c_raise_scl)
183		bra not $p1 #i2c_start_out
184	i2c_start_send:
185	i2c_drive_sda(0)
186	i2c_delay(T_HOLD)
187	i2c_drive_scl(0)
188	i2c_delay(T_HOLD)
189	i2c_start_out:
190	ret
191
192i2c_stop:
193	i2c_drive_scl(0)
194	i2c_drive_sda(0)
195	i2c_delay(T_RISEFALL)
196	i2c_drive_scl(1)
197	i2c_delay(T_HOLD)
198	i2c_drive_sda(1)
199	i2c_delay(T_HOLD)
200	ret
201
202// $r3  - value
203// $r2  - sda line
204// $r1  - scl line
205// $r0  - zero
206i2c_bitw:
207	call(i2c_drive_sda)
208	i2c_delay(T_RISEFALL)
209	i2c_trace_call(i2c_raise_scl)
210	bra not $p1 #i2c_bitw_out
211	i2c_delay(T_HOLD)
212	i2c_drive_scl(0)
213	i2c_delay(T_HOLD)
214	i2c_bitw_out:
215	ret
216
217// $r3  - value (out)
218// $r2  - sda line
219// $r1  - scl line
220// $r0  - zero
221i2c_bitr:
222	i2c_drive_sda(1)
223	i2c_delay(T_RISEFALL)
224	i2c_trace_call(i2c_raise_scl)
225	bra not $p1 #i2c_bitr_done
226	i2c_sense_sda()
227	i2c_drive_scl(0)
228	i2c_delay(T_HOLD)
229	xbit $r3 $flags $p1
230	bset $flags $p1
231	i2c_bitr_done:
232	ret
233
234i2c_get_byte:
235	mov $r5 0
236	mov $r4 8
237	i2c_get_byte_next:
238		shl b32 $r5 1
239		i2c_trace_call(i2c_bitr)
240		bra not $p1 #i2c_get_byte_done
241		or $r5 $r3
242		sub b32 $r4 1
243		bra nz #i2c_get_byte_next
244	mov $r3 1
245	i2c_trace_call(i2c_bitw)
246	i2c_get_byte_done:
247	ret
248
249i2c_put_byte:
250	mov $r4 8
251	i2c_put_byte_next:
252		sub b32 $r4 1
253		xbit $r3 $r5 $r4
254		i2c_trace_call(i2c_bitw)
255		bra not $p1 #i2c_put_byte_done
256		cmp b32 $r4 0
257		bra ne #i2c_put_byte_next
258	i2c_trace_call(i2c_bitr)
259	bra not $p1 #i2c_put_byte_done
260	i2c_trace_next()
261	cmp b32 $r3 1
262	bra ne #i2c_put_byte_done
263	bclr $flags $p1	// nack
264	i2c_put_byte_done:
265	ret
266
267i2c_addr:
268	i2c_trace_call(i2c_start)
269	bra not $p1 #i2c_addr_done
270	extr $r3 $r12 I2C__MSG_DATA0_ADDR
271	shl b32 $r3 1
272	or $r5 $r3
273	i2c_trace_call(i2c_put_byte)
274	i2c_addr_done:
275	ret
276
277i2c_acquire_addr:
278	extr $r14 $r12 I2C__MSG_DATA0_PORT
279#if NVKM_PPWR_CHIPSET < GF119
280	shl b32 $r14 2
281	add b32 $r14 #i2c_ctrl
282	ld b32 $r14 D[$r14]
283#else
284	shl b32 $r14 5
285	add b32 $r14 0x00d014
286#endif
287	ret
288
289i2c_acquire:
290	call(i2c_acquire_addr)
291	call(rd32)
292	bset $r13 3
293	call(wr32)
294	ret
295
296i2c_release:
297	call(i2c_acquire_addr)
298	call(rd32)
299	bclr $r13 3
300	call(wr32)
301	ret
302
303// description
304//
305// $r15 - current (i2c)
306// $r14 - sender process name
307// $r13 - message
308// $r12 - data0
309// $r11 - data1
310// $r0  - zero
311i2c_recv:
312	bclr $flags $p1
313	extr $r1 $r12 I2C__MSG_DATA0_PORT
314	shl b32 $r1 2
315	cmp b32 $r1 (#i2c_sda_map - #i2c_scl_map)
316	bra ge #i2c_recv_done
317	add b32 $r3 $r1 #i2c_sda_map
318	ld b32 $r2 D[$r3]
319	add b32 $r3 $r1 #i2c_scl_map
320	ld b32 $r1 D[$r3]
321
322	bset $flags $p2
323	push $r13
324	push $r14
325
326	push $r13
327	i2c_trace_init()
328	i2c_trace_call(i2c_acquire)
329	pop $r13
330
331	cmp b32 $r13 I2C__MSG_RD08
332	bra ne #i2c_recv_not_rd08
333		mov $r5 0
334		i2c_trace_call(i2c_addr)
335		bra not $p1 #i2c_recv_done
336		extr $r5 $r12 I2C__MSG_DATA0_RD08_REG
337		i2c_trace_call(i2c_put_byte)
338		bra not $p1 #i2c_recv_done
339		mov $r5 1
340		i2c_trace_call(i2c_addr)
341		bra not $p1 #i2c_recv_done
342		i2c_trace_call(i2c_get_byte)
343		bra not $p1 #i2c_recv_done
344		ins $r11 $r5 I2C__MSG_DATA1_RD08_VAL
345		i2c_trace_call(i2c_stop)
346		mov b32 $r11 $r5
347		clear b32 $r7
348		bra #i2c_recv_done
349
350	i2c_recv_not_rd08:
351	cmp b32 $r13 I2C__MSG_WR08
352	bra ne #i2c_recv_not_wr08
353		mov $r5 0
354		call(i2c_addr)
355		bra not $p1 #i2c_recv_done
356		extr $r5 $r12 I2C__MSG_DATA0_WR08_REG
357		call(i2c_put_byte)
358		bra not $p1 #i2c_recv_done
359		mov $r5 0
360		call(i2c_addr)
361		bra not $p1 #i2c_recv_done
362		extr $r5 $r11 I2C__MSG_DATA1_WR08_VAL
363		call(i2c_put_byte)
364		bra not $p1 #i2c_recv_done
365		call(i2c_stop)
366		clear b32 $r7
367		extr $r5 $r12 I2C__MSG_DATA0_WR08_SYNC
368		bra nz #i2c_recv_done
369		bclr $flags $p2
370		bra #i2c_recv_done
371
372	i2c_recv_not_wr08:
373
374	i2c_recv_done:
375	extr $r14 $r12 I2C__MSG_DATA0_PORT
376	call(i2c_release)
377
378	pop $r14
379	pop $r13
380	bra not $p2 #i2c_recv_exit
381	mov b32 $r12 $r7
382	call(send)
383
384	i2c_recv_exit:
385	ret
386
387// description
388//
389// $r15 - current (i2c)
390// $r0  - zero
391i2c_init:
392	ret
393#endif
394