0001 /*
0002 * Copyright 2013 Red Hat Inc.
0003 *
0004 * Permission is hereby granted, free of charge, to any person obtaining a
0005 * copy of this software and associated documentation files (the "Software"),
0006 * to deal in the Software without restriction, including without limitation
0007 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008 * and/or sell copies of the Software, and to permit persons to whom the
0009 * Software is furnished to do so, subject to the following conditions:
0010 *
0011 * The above copyright notice and this permission notice shall be included in
0012 * all copies or substantial portions of the Software.
0013 *
0014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
0017 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020 * OTHER DEALINGS IN THE SOFTWARE.
0021 *
0022 * Authors: Ben Skeggs
0023 */
0024
0025 #define T_TIMEOUT 2200000
0026 #define T_RISEFALL 1000
0027 #define T_HOLD 5000
0028
0029 #ifdef INCLUDE_PROC
0030 process(PROC_I2C_, #i2c_init, #i2c_recv)
0031 #endif
0032
0033 /******************************************************************************
0034 * I2C_ data segment
0035 *****************************************************************************/
0036 #ifdef INCLUDE_DATA
0037 i2c_scl_map:
0038 .b32 NV_PPWR_OUTPUT_I2C_0_SCL
0039 .b32 NV_PPWR_OUTPUT_I2C_1_SCL
0040 .b32 NV_PPWR_OUTPUT_I2C_2_SCL
0041 .b32 NV_PPWR_OUTPUT_I2C_3_SCL
0042 .b32 NV_PPWR_OUTPUT_I2C_4_SCL
0043 .b32 NV_PPWR_OUTPUT_I2C_5_SCL
0044 .b32 NV_PPWR_OUTPUT_I2C_6_SCL
0045 .b32 NV_PPWR_OUTPUT_I2C_7_SCL
0046 .b32 NV_PPWR_OUTPUT_I2C_8_SCL
0047 .b32 NV_PPWR_OUTPUT_I2C_9_SCL
0048 i2c_sda_map:
0049 .b32 NV_PPWR_OUTPUT_I2C_0_SDA
0050 .b32 NV_PPWR_OUTPUT_I2C_1_SDA
0051 .b32 NV_PPWR_OUTPUT_I2C_2_SDA
0052 .b32 NV_PPWR_OUTPUT_I2C_3_SDA
0053 .b32 NV_PPWR_OUTPUT_I2C_4_SDA
0054 .b32 NV_PPWR_OUTPUT_I2C_5_SDA
0055 .b32 NV_PPWR_OUTPUT_I2C_6_SDA
0056 .b32 NV_PPWR_OUTPUT_I2C_7_SDA
0057 .b32 NV_PPWR_OUTPUT_I2C_8_SDA
0058 .b32 NV_PPWR_OUTPUT_I2C_9_SDA
0059 #if NVKM_PPWR_CHIPSET < GF119
0060 i2c_ctrl:
0061 .b32 0x00e138
0062 .b32 0x00e150
0063 .b32 0x00e168
0064 .b32 0x00e180
0065 .b32 0x00e254
0066 .b32 0x00e274
0067 .b32 0x00e764
0068 .b32 0x00e780
0069 .b32 0x00e79c
0070 .b32 0x00e7b8
0071 #endif
0072 #endif
0073
0074 /******************************************************************************
0075 * I2C_ code segment
0076 *****************************************************************************/
0077 #ifdef INCLUDE_CODE
0078
0079 // $r3 - value
0080 // $r2 - sda line
0081 // $r1 - scl line
0082 // $r0 - zero
0083 i2c_drive_scl:
0084 cmp b32 $r3 0
0085 bra e #i2c_drive_scl_lo
0086 nv_iowr(NV_PPWR_OUTPUT_SET, $r1)
0087 ret
0088 i2c_drive_scl_lo:
0089 nv_iowr(NV_PPWR_OUTPUT_CLR, $r1)
0090 ret
0091
0092 i2c_drive_sda:
0093 cmp b32 $r3 0
0094 bra e #i2c_drive_sda_lo
0095 nv_iowr(NV_PPWR_OUTPUT_SET, $r2)
0096 ret
0097 i2c_drive_sda_lo:
0098 nv_iowr(NV_PPWR_OUTPUT_CLR, $r2)
0099 ret
0100
0101 i2c_sense_scl:
0102 bclr $flags $p1
0103 nv_iord($r3, NV_PPWR_INPUT)
0104 and $r3 $r1
0105 bra z #i2c_sense_scl_done
0106 bset $flags $p1
0107 i2c_sense_scl_done:
0108 ret
0109
0110 i2c_sense_sda:
0111 bclr $flags $p1
0112 nv_iord($r3, NV_PPWR_INPUT)
0113 and $r3 $r2
0114 bra z #i2c_sense_sda_done
0115 bset $flags $p1
0116 i2c_sense_sda_done:
0117 ret
0118
0119 #define i2c_drive_scl(v) /*
0120 */ mov $r3 (v) /*
0121 */ call(i2c_drive_scl)
0122 #define i2c_drive_sda(v) /*
0123 */ mov $r3 (v) /*
0124 */ call(i2c_drive_sda)
0125 #define i2c_sense_scl() /*
0126 */ call(i2c_sense_scl)
0127 #define i2c_sense_sda() /*
0128 */ call(i2c_sense_sda)
0129 #define i2c_delay(v) /*
0130 */ mov $r14 (v) /*
0131 */ call(nsec)
0132
0133 #define i2c_trace_init() /*
0134 */ imm32($r6, 0x10000000) /*
0135 */ sub b32 $r7 $r6 1 /*
0136 */
0137 #define i2c_trace_down() /*
0138 */ shr b32 $r6 4 /*
0139 */ push $r5 /*
0140 */ shl b32 $r5 $r6 4 /*
0141 */ sub b32 $r5 $r6 /*
0142 */ not b32 $r5 /*
0143 */ and $r7 $r5 /*
0144 */ pop $r5 /*
0145 */
0146 #define i2c_trace_exit() /*
0147 */ shl b32 $r6 4 /*
0148 */
0149 #define i2c_trace_next() /*
0150 */ add b32 $r7 $r6 /*
0151 */
0152 #define i2c_trace_call(func) /*
0153 */ i2c_trace_next() /*
0154 */ i2c_trace_down() /*
0155 */ call(func) /*
0156 */ i2c_trace_exit() /*
0157 */
0158
0159 i2c_raise_scl:
0160 push $r4
0161 mov $r4 (T_TIMEOUT / T_RISEFALL)
0162 i2c_drive_scl(1)
0163 i2c_raise_scl_wait:
0164 i2c_delay(T_RISEFALL)
0165 i2c_sense_scl()
0166 bra $p1 #i2c_raise_scl_done
0167 sub b32 $r4 1
0168 bra nz #i2c_raise_scl_wait
0169 i2c_raise_scl_done:
0170 pop $r4
0171 ret
0172
0173 i2c_start:
0174 i2c_sense_scl()
0175 bra not $p1 #i2c_start_rep
0176 i2c_sense_sda()
0177 bra not $p1 #i2c_start_rep
0178 bra #i2c_start_send
0179 i2c_start_rep:
0180 i2c_drive_scl(0)
0181 i2c_drive_sda(1)
0182 i2c_trace_call(i2c_raise_scl)
0183 bra not $p1 #i2c_start_out
0184 i2c_start_send:
0185 i2c_drive_sda(0)
0186 i2c_delay(T_HOLD)
0187 i2c_drive_scl(0)
0188 i2c_delay(T_HOLD)
0189 i2c_start_out:
0190 ret
0191
0192 i2c_stop:
0193 i2c_drive_scl(0)
0194 i2c_drive_sda(0)
0195 i2c_delay(T_RISEFALL)
0196 i2c_drive_scl(1)
0197 i2c_delay(T_HOLD)
0198 i2c_drive_sda(1)
0199 i2c_delay(T_HOLD)
0200 ret
0201
0202 // $r3 - value
0203 // $r2 - sda line
0204 // $r1 - scl line
0205 // $r0 - zero
0206 i2c_bitw:
0207 call(i2c_drive_sda)
0208 i2c_delay(T_RISEFALL)
0209 i2c_trace_call(i2c_raise_scl)
0210 bra not $p1 #i2c_bitw_out
0211 i2c_delay(T_HOLD)
0212 i2c_drive_scl(0)
0213 i2c_delay(T_HOLD)
0214 i2c_bitw_out:
0215 ret
0216
0217 // $r3 - value (out)
0218 // $r2 - sda line
0219 // $r1 - scl line
0220 // $r0 - zero
0221 i2c_bitr:
0222 i2c_drive_sda(1)
0223 i2c_delay(T_RISEFALL)
0224 i2c_trace_call(i2c_raise_scl)
0225 bra not $p1 #i2c_bitr_done
0226 i2c_sense_sda()
0227 i2c_drive_scl(0)
0228 i2c_delay(T_HOLD)
0229 xbit $r3 $flags $p1
0230 bset $flags $p1
0231 i2c_bitr_done:
0232 ret
0233
0234 i2c_get_byte:
0235 mov $r5 0
0236 mov $r4 8
0237 i2c_get_byte_next:
0238 shl b32 $r5 1
0239 i2c_trace_call(i2c_bitr)
0240 bra not $p1 #i2c_get_byte_done
0241 or $r5 $r3
0242 sub b32 $r4 1
0243 bra nz #i2c_get_byte_next
0244 mov $r3 1
0245 i2c_trace_call(i2c_bitw)
0246 i2c_get_byte_done:
0247 ret
0248
0249 i2c_put_byte:
0250 mov $r4 8
0251 i2c_put_byte_next:
0252 sub b32 $r4 1
0253 xbit $r3 $r5 $r4
0254 i2c_trace_call(i2c_bitw)
0255 bra not $p1 #i2c_put_byte_done
0256 cmp b32 $r4 0
0257 bra ne #i2c_put_byte_next
0258 i2c_trace_call(i2c_bitr)
0259 bra not $p1 #i2c_put_byte_done
0260 i2c_trace_next()
0261 cmp b32 $r3 1
0262 bra ne #i2c_put_byte_done
0263 bclr $flags $p1 // nack
0264 i2c_put_byte_done:
0265 ret
0266
0267 i2c_addr:
0268 i2c_trace_call(i2c_start)
0269 bra not $p1 #i2c_addr_done
0270 extr $r3 $r12 I2C__MSG_DATA0_ADDR
0271 shl b32 $r3 1
0272 or $r5 $r3
0273 i2c_trace_call(i2c_put_byte)
0274 i2c_addr_done:
0275 ret
0276
0277 i2c_acquire_addr:
0278 extr $r14 $r12 I2C__MSG_DATA0_PORT
0279 #if NVKM_PPWR_CHIPSET < GF119
0280 shl b32 $r14 2
0281 add b32 $r14 #i2c_ctrl
0282 ld b32 $r14 D[$r14]
0283 #else
0284 shl b32 $r14 5
0285 add b32 $r14 0x00d014
0286 #endif
0287 ret
0288
0289 i2c_acquire:
0290 call(i2c_acquire_addr)
0291 call(rd32)
0292 bset $r13 3
0293 call(wr32)
0294 ret
0295
0296 i2c_release:
0297 call(i2c_acquire_addr)
0298 call(rd32)
0299 bclr $r13 3
0300 call(wr32)
0301 ret
0302
0303 // description
0304 //
0305 // $r15 - current (i2c)
0306 // $r14 - sender process name
0307 // $r13 - message
0308 // $r12 - data0
0309 // $r11 - data1
0310 // $r0 - zero
0311 i2c_recv:
0312 bclr $flags $p1
0313 extr $r1 $r12 I2C__MSG_DATA0_PORT
0314 shl b32 $r1 2
0315 cmp b32 $r1 (#i2c_sda_map - #i2c_scl_map)
0316 bra ge #i2c_recv_done
0317 add b32 $r3 $r1 #i2c_sda_map
0318 ld b32 $r2 D[$r3]
0319 add b32 $r3 $r1 #i2c_scl_map
0320 ld b32 $r1 D[$r3]
0321
0322 bset $flags $p2
0323 push $r13
0324 push $r14
0325
0326 push $r13
0327 i2c_trace_init()
0328 i2c_trace_call(i2c_acquire)
0329 pop $r13
0330
0331 cmp b32 $r13 I2C__MSG_RD08
0332 bra ne #i2c_recv_not_rd08
0333 mov $r5 0
0334 i2c_trace_call(i2c_addr)
0335 bra not $p1 #i2c_recv_done
0336 extr $r5 $r12 I2C__MSG_DATA0_RD08_REG
0337 i2c_trace_call(i2c_put_byte)
0338 bra not $p1 #i2c_recv_done
0339 mov $r5 1
0340 i2c_trace_call(i2c_addr)
0341 bra not $p1 #i2c_recv_done
0342 i2c_trace_call(i2c_get_byte)
0343 bra not $p1 #i2c_recv_done
0344 ins $r11 $r5 I2C__MSG_DATA1_RD08_VAL
0345 i2c_trace_call(i2c_stop)
0346 mov b32 $r11 $r5
0347 clear b32 $r7
0348 bra #i2c_recv_done
0349
0350 i2c_recv_not_rd08:
0351 cmp b32 $r13 I2C__MSG_WR08
0352 bra ne #i2c_recv_not_wr08
0353 mov $r5 0
0354 call(i2c_addr)
0355 bra not $p1 #i2c_recv_done
0356 extr $r5 $r12 I2C__MSG_DATA0_WR08_REG
0357 call(i2c_put_byte)
0358 bra not $p1 #i2c_recv_done
0359 mov $r5 0
0360 call(i2c_addr)
0361 bra not $p1 #i2c_recv_done
0362 extr $r5 $r11 I2C__MSG_DATA1_WR08_VAL
0363 call(i2c_put_byte)
0364 bra not $p1 #i2c_recv_done
0365 call(i2c_stop)
0366 clear b32 $r7
0367 extr $r5 $r12 I2C__MSG_DATA0_WR08_SYNC
0368 bra nz #i2c_recv_done
0369 bclr $flags $p2
0370 bra #i2c_recv_done
0371
0372 i2c_recv_not_wr08:
0373
0374 i2c_recv_done:
0375 extr $r14 $r12 I2C__MSG_DATA0_PORT
0376 call(i2c_release)
0377
0378 pop $r14
0379 pop $r13
0380 bra not $p2 #i2c_recv_exit
0381 mov b32 $r12 $r7
0382 call(send)
0383
0384 i2c_recv_exit:
0385 ret
0386
0387 // description
0388 //
0389 // $r15 - current (i2c)
0390 // $r0 - zero
0391 i2c_init:
0392 ret
0393 #endif