| /* |
| * Copyright 2013 Red Hat Inc. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in |
| * all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
| * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| * OTHER DEALINGS IN THE SOFTWARE. |
| * |
| * Authors: Ben Skeggs |
| */ |
| |
| #define T_TIMEOUT 2200000 |
| #define T_RISEFALL 1000 |
| #define T_HOLD 5000 |
| |
| #ifdef INCLUDE_PROC |
| process(PROC_I2C_, #i2c_init, #i2c_recv) |
| #endif |
| |
| /****************************************************************************** |
| * I2C_ data segment |
| *****************************************************************************/ |
| #ifdef INCLUDE_DATA |
| i2c_scl_map: |
| .b32 NV_PPWR_OUTPUT_I2C_0_SCL |
| .b32 NV_PPWR_OUTPUT_I2C_1_SCL |
| .b32 NV_PPWR_OUTPUT_I2C_2_SCL |
| .b32 NV_PPWR_OUTPUT_I2C_3_SCL |
| .b32 NV_PPWR_OUTPUT_I2C_4_SCL |
| .b32 NV_PPWR_OUTPUT_I2C_5_SCL |
| .b32 NV_PPWR_OUTPUT_I2C_6_SCL |
| .b32 NV_PPWR_OUTPUT_I2C_7_SCL |
| .b32 NV_PPWR_OUTPUT_I2C_8_SCL |
| .b32 NV_PPWR_OUTPUT_I2C_9_SCL |
| i2c_sda_map: |
| .b32 NV_PPWR_OUTPUT_I2C_0_SDA |
| .b32 NV_PPWR_OUTPUT_I2C_1_SDA |
| .b32 NV_PPWR_OUTPUT_I2C_2_SDA |
| .b32 NV_PPWR_OUTPUT_I2C_3_SDA |
| .b32 NV_PPWR_OUTPUT_I2C_4_SDA |
| .b32 NV_PPWR_OUTPUT_I2C_5_SDA |
| .b32 NV_PPWR_OUTPUT_I2C_6_SDA |
| .b32 NV_PPWR_OUTPUT_I2C_7_SDA |
| .b32 NV_PPWR_OUTPUT_I2C_8_SDA |
| .b32 NV_PPWR_OUTPUT_I2C_9_SDA |
| #if NVKM_PPWR_CHIPSET < GF119 |
| i2c_ctrl: |
| .b32 0x00e138 |
| .b32 0x00e150 |
| .b32 0x00e168 |
| .b32 0x00e180 |
| .b32 0x00e254 |
| .b32 0x00e274 |
| .b32 0x00e764 |
| .b32 0x00e780 |
| .b32 0x00e79c |
| .b32 0x00e7b8 |
| #endif |
| #endif |
| |
| /****************************************************************************** |
| * I2C_ code segment |
| *****************************************************************************/ |
| #ifdef INCLUDE_CODE |
| |
| // $r3 - value |
| // $r2 - sda line |
| // $r1 - scl line |
| // $r0 - zero |
| i2c_drive_scl: |
| cmp b32 $r3 0 |
| bra e #i2c_drive_scl_lo |
| nv_iowr(NV_PPWR_OUTPUT_SET, $r1) |
| ret |
| i2c_drive_scl_lo: |
| nv_iowr(NV_PPWR_OUTPUT_CLR, $r1) |
| ret |
| |
| i2c_drive_sda: |
| cmp b32 $r3 0 |
| bra e #i2c_drive_sda_lo |
| nv_iowr(NV_PPWR_OUTPUT_SET, $r2) |
| ret |
| i2c_drive_sda_lo: |
| nv_iowr(NV_PPWR_OUTPUT_CLR, $r2) |
| ret |
| |
| i2c_sense_scl: |
| bclr $flags $p1 |
| nv_iord($r3, NV_PPWR_INPUT) |
| and $r3 $r1 |
| bra z #i2c_sense_scl_done |
| bset $flags $p1 |
| i2c_sense_scl_done: |
| ret |
| |
| i2c_sense_sda: |
| bclr $flags $p1 |
| nv_iord($r3, NV_PPWR_INPUT) |
| and $r3 $r2 |
| bra z #i2c_sense_sda_done |
| bset $flags $p1 |
| i2c_sense_sda_done: |
| ret |
| |
| #define i2c_drive_scl(v) /* |
| */ mov $r3 (v) /* |
| */ call(i2c_drive_scl) |
| #define i2c_drive_sda(v) /* |
| */ mov $r3 (v) /* |
| */ call(i2c_drive_sda) |
| #define i2c_sense_scl() /* |
| */ call(i2c_sense_scl) |
| #define i2c_sense_sda() /* |
| */ call(i2c_sense_sda) |
| #define i2c_delay(v) /* |
| */ mov $r14 (v) /* |
| */ call(nsec) |
| |
| #define i2c_trace_init() /* |
| */ imm32($r6, 0x10000000) /* |
| */ sub b32 $r7 $r6 1 /* |
| */ |
| #define i2c_trace_down() /* |
| */ shr b32 $r6 4 /* |
| */ push $r5 /* |
| */ shl b32 $r5 $r6 4 /* |
| */ sub b32 $r5 $r6 /* |
| */ not b32 $r5 /* |
| */ and $r7 $r5 /* |
| */ pop $r5 /* |
| */ |
| #define i2c_trace_exit() /* |
| */ shl b32 $r6 4 /* |
| */ |
| #define i2c_trace_next() /* |
| */ add b32 $r7 $r6 /* |
| */ |
| #define i2c_trace_call(func) /* |
| */ i2c_trace_next() /* |
| */ i2c_trace_down() /* |
| */ call(func) /* |
| */ i2c_trace_exit() /* |
| */ |
| |
| i2c_raise_scl: |
| push $r4 |
| mov $r4 (T_TIMEOUT / T_RISEFALL) |
| i2c_drive_scl(1) |
| i2c_raise_scl_wait: |
| i2c_delay(T_RISEFALL) |
| i2c_sense_scl() |
| bra $p1 #i2c_raise_scl_done |
| sub b32 $r4 1 |
| bra nz #i2c_raise_scl_wait |
| i2c_raise_scl_done: |
| pop $r4 |
| ret |
| |
| i2c_start: |
| i2c_sense_scl() |
| bra not $p1 #i2c_start_rep |
| i2c_sense_sda() |
| bra not $p1 #i2c_start_rep |
| bra #i2c_start_send |
| i2c_start_rep: |
| i2c_drive_scl(0) |
| i2c_drive_sda(1) |
| i2c_trace_call(i2c_raise_scl) |
| bra not $p1 #i2c_start_out |
| i2c_start_send: |
| i2c_drive_sda(0) |
| i2c_delay(T_HOLD) |
| i2c_drive_scl(0) |
| i2c_delay(T_HOLD) |
| i2c_start_out: |
| ret |
| |
| i2c_stop: |
| i2c_drive_scl(0) |
| i2c_drive_sda(0) |
| i2c_delay(T_RISEFALL) |
| i2c_drive_scl(1) |
| i2c_delay(T_HOLD) |
| i2c_drive_sda(1) |
| i2c_delay(T_HOLD) |
| ret |
| |
| // $r3 - value |
| // $r2 - sda line |
| // $r1 - scl line |
| // $r0 - zero |
| i2c_bitw: |
| call(i2c_drive_sda) |
| i2c_delay(T_RISEFALL) |
| i2c_trace_call(i2c_raise_scl) |
| bra not $p1 #i2c_bitw_out |
| i2c_delay(T_HOLD) |
| i2c_drive_scl(0) |
| i2c_delay(T_HOLD) |
| i2c_bitw_out: |
| ret |
| |
| // $r3 - value (out) |
| // $r2 - sda line |
| // $r1 - scl line |
| // $r0 - zero |
| i2c_bitr: |
| i2c_drive_sda(1) |
| i2c_delay(T_RISEFALL) |
| i2c_trace_call(i2c_raise_scl) |
| bra not $p1 #i2c_bitr_done |
| i2c_sense_sda() |
| i2c_drive_scl(0) |
| i2c_delay(T_HOLD) |
| xbit $r3 $flags $p1 |
| bset $flags $p1 |
| i2c_bitr_done: |
| ret |
| |
| i2c_get_byte: |
| mov $r5 0 |
| mov $r4 8 |
| i2c_get_byte_next: |
| shl b32 $r5 1 |
| i2c_trace_call(i2c_bitr) |
| bra not $p1 #i2c_get_byte_done |
| or $r5 $r3 |
| sub b32 $r4 1 |
| bra nz #i2c_get_byte_next |
| mov $r3 1 |
| i2c_trace_call(i2c_bitw) |
| i2c_get_byte_done: |
| ret |
| |
| i2c_put_byte: |
| mov $r4 8 |
| i2c_put_byte_next: |
| sub b32 $r4 1 |
| xbit $r3 $r5 $r4 |
| i2c_trace_call(i2c_bitw) |
| bra not $p1 #i2c_put_byte_done |
| cmp b32 $r4 0 |
| bra ne #i2c_put_byte_next |
| i2c_trace_call(i2c_bitr) |
| bra not $p1 #i2c_put_byte_done |
| i2c_trace_next() |
| cmp b32 $r3 1 |
| bra ne #i2c_put_byte_done |
| bclr $flags $p1 // nack |
| i2c_put_byte_done: |
| ret |
| |
| i2c_addr: |
| i2c_trace_call(i2c_start) |
| bra not $p1 #i2c_addr_done |
| extr $r3 $r12 I2C__MSG_DATA0_ADDR |
| shl b32 $r3 1 |
| or $r5 $r3 |
| i2c_trace_call(i2c_put_byte) |
| i2c_addr_done: |
| ret |
| |
| i2c_acquire_addr: |
| extr $r14 $r12 I2C__MSG_DATA0_PORT |
| #if NVKM_PPWR_CHIPSET < GF119 |
| shl b32 $r14 2 |
| add b32 $r14 #i2c_ctrl |
| ld b32 $r14 D[$r14] |
| #else |
| shl b32 $r14 5 |
| add b32 $r14 0x00d014 |
| #endif |
| ret |
| |
| i2c_acquire: |
| call(i2c_acquire_addr) |
| call(rd32) |
| bset $r13 3 |
| call(wr32) |
| ret |
| |
| i2c_release: |
| call(i2c_acquire_addr) |
| call(rd32) |
| bclr $r13 3 |
| call(wr32) |
| ret |
| |
| // description |
| // |
| // $r15 - current (i2c) |
| // $r14 - sender process name |
| // $r13 - message |
| // $r12 - data0 |
| // $r11 - data1 |
| // $r0 - zero |
| i2c_recv: |
| bclr $flags $p1 |
| extr $r1 $r12 I2C__MSG_DATA0_PORT |
| shl b32 $r1 2 |
| cmp b32 $r1 (#i2c_sda_map - #i2c_scl_map) |
| bra ge #i2c_recv_done |
| add b32 $r3 $r1 #i2c_sda_map |
| ld b32 $r2 D[$r3] |
| add b32 $r3 $r1 #i2c_scl_map |
| ld b32 $r1 D[$r3] |
| |
| bset $flags $p2 |
| push $r13 |
| push $r14 |
| |
| push $r13 |
| i2c_trace_init() |
| i2c_trace_call(i2c_acquire) |
| pop $r13 |
| |
| cmp b32 $r13 I2C__MSG_RD08 |
| bra ne #i2c_recv_not_rd08 |
| mov $r5 0 |
| i2c_trace_call(i2c_addr) |
| bra not $p1 #i2c_recv_done |
| extr $r5 $r12 I2C__MSG_DATA0_RD08_REG |
| i2c_trace_call(i2c_put_byte) |
| bra not $p1 #i2c_recv_done |
| mov $r5 1 |
| i2c_trace_call(i2c_addr) |
| bra not $p1 #i2c_recv_done |
| i2c_trace_call(i2c_get_byte) |
| bra not $p1 #i2c_recv_done |
| ins $r11 $r5 I2C__MSG_DATA1_RD08_VAL |
| i2c_trace_call(i2c_stop) |
| mov b32 $r11 $r5 |
| clear b32 $r7 |
| bra #i2c_recv_done |
| |
| i2c_recv_not_rd08: |
| cmp b32 $r13 I2C__MSG_WR08 |
| bra ne #i2c_recv_not_wr08 |
| mov $r5 0 |
| call(i2c_addr) |
| bra not $p1 #i2c_recv_done |
| extr $r5 $r12 I2C__MSG_DATA0_WR08_REG |
| call(i2c_put_byte) |
| bra not $p1 #i2c_recv_done |
| mov $r5 0 |
| call(i2c_addr) |
| bra not $p1 #i2c_recv_done |
| extr $r5 $r11 I2C__MSG_DATA1_WR08_VAL |
| call(i2c_put_byte) |
| bra not $p1 #i2c_recv_done |
| call(i2c_stop) |
| clear b32 $r7 |
| extr $r5 $r12 I2C__MSG_DATA0_WR08_SYNC |
| bra nz #i2c_recv_done |
| bclr $flags $p2 |
| bra #i2c_recv_done |
| |
| i2c_recv_not_wr08: |
| |
| i2c_recv_done: |
| extr $r14 $r12 I2C__MSG_DATA0_PORT |
| call(i2c_release) |
| |
| pop $r14 |
| pop $r13 |
| bra not $p2 #i2c_recv_exit |
| mov b32 $r12 $r7 |
| call(send) |
| |
| i2c_recv_exit: |
| ret |
| |
| // description |
| // |
| // $r15 - current (i2c) |
| // $r0 - zero |
| i2c_init: |
| ret |
| #endif |