Jens Arnold | 9737fc7 | 2008-04-06 23:57:37 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * $Id$ |
| 9 | * |
| 10 | * Copyright (C) 2008 by Jens Arnold |
| 11 | * |
Daniel Stenberg | 2acc0ac | 2008-06-28 18:10:04 +0000 | [diff] [blame^] | 12 | * This program is free software; you can redistribute it and/or |
| 13 | * modify it under the terms of the GNU General Public License |
| 14 | * as published by the Free Software Foundation; either version 2 |
| 15 | * of the License, or (at your option) any later version. |
Jens Arnold | 9737fc7 | 2008-04-06 23:57:37 +0000 | [diff] [blame] | 16 | * |
| 17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 18 | * KIND, either express or implied. |
| 19 | * |
| 20 | ****************************************************************************/ |
| 21 | |
| 22 | #include "config.h" |
| 23 | |
| 24 | #define RS_MASK 0x00010000 |
| 25 | #define CLOCK_MASK 0x10000000 |
| 26 | #define GPIO_OUT_ADDR 0x80000004 |
| 27 | |
| 28 | #define CS_MASK 0x00000004 /* used in moveq.l */ |
| 29 | #define DATA_MASK 0x00040000 |
| 30 | #define GPIO1_OUT_ADDR 0x800000b4 |
| 31 | |
| 32 | #define CS_TIMEOUT 10 /* HZ/10 */ |
| 33 | |
| 34 | .extern cpu_frequency /* Global variable from system.c */ |
| 35 | .extern remote_byte_delay /* Global variable from lcd-remote-iriver.c */ |
| 36 | .extern remote_cs_countdown /* Global variable from lcd-remote-iriver.c */ |
| 37 | |
| 38 | .section .icode,"ax",@progbits |
| 39 | |
| 40 | /* Output 8 bits to the LCD. Instruction order is devised to maximize the |
| 41 | * delay between changing the data line and the CLK L->H transition, which |
| 42 | * makes the LCD controller sample DATA. |
| 43 | * Requires CLK = 0 on entry. |
| 44 | * |
| 45 | * Custom calling convention: |
| 46 | * %a0 - GPIO_OUT_ADDR |
| 47 | * %a1 - GPIO1_OUT_ADDR |
| 48 | * %d4 - data byte |
| 49 | * %d6 - DATA_MASK |
| 50 | * Clobbers: |
| 51 | * %d0..%d4 |
| 52 | */ |
| 53 | #ifdef HAVE_REMOTE_LCD_TICKING |
| 54 | .write_byte_delayed: |
| 55 | move.l remote_byte_delay, %d0 |
| 56 | 1: |
| 57 | subq.l #1, %d0 |
| 58 | bne.s 1b |
| 59 | #endif |
| 60 | |
| 61 | .write_byte: |
| 62 | move.w %sr, %d3 /* Get current interrupt level */ |
| 63 | move.w #0x2700, %sr /* Disable interrupts */ |
| 64 | |
| 65 | move.l (%a1), %d0 /* Get current state of data port */ |
| 66 | move.l %d0, %d1 |
| 67 | and.l %d6, %d1 /* Check current state of data line */ |
| 68 | beq.s 1f /* and set it as previous-state bit */ |
| 69 | bset #8, %d4 |
| 70 | 1: |
| 71 | move.l %d4, %d1 /* Compute the 'bit derivative', i.e. a value */ |
| 72 | lsr.l #1, %d1 /* with 1's where the data changes from the */ |
| 73 | eor.l %d1, %d4 /* previous state, and 0's where it doesn't */ |
| 74 | swap %d4 /* Shift data to upper byte */ |
| 75 | lsl.l #8, %d4 |
| 76 | |
| 77 | move.l (%a0),%d1 /* Get current state of clock port */ |
| 78 | move.l %d1, %d2 /* Precalculate opposite state of clock line */ |
| 79 | eor.l #CLOCK_MASK, %d2 |
| 80 | |
| 81 | lsl.l #1, %d4 /* Invert data line for bit7 ? */ |
| 82 | bcc.s 1f /* no: skip */ |
| 83 | eor.l %d6, %d0 /* invert data bit */ |
| 84 | move.l %d0, (%a1) /* output data bit7 */ |
| 85 | nop |
Jens Arnold | d52bea8 | 2008-05-29 21:41:47 +0000 | [diff] [blame] | 86 | nop |
Jens Arnold | 9737fc7 | 2008-04-06 23:57:37 +0000 | [diff] [blame] | 87 | 1: |
| 88 | |
| 89 | .macro bit_out |
Jens Arnold | d52bea8 | 2008-05-29 21:41:47 +0000 | [diff] [blame] | 90 | move.l %d2, (%a0) /* Bit7: set CLK = 1 */ |
| 91 | nop |
Jens Arnold | 9737fc7 | 2008-04-06 23:57:37 +0000 | [diff] [blame] | 92 | lsl.l #1, %d4 /* Invert data line for bit6 ? */ |
| 93 | bcc.s 1f /* no: skip */ |
| 94 | eor.l %d6, %d0 /* Invert data bit */ |
Jens Arnold | 9737fc7 | 2008-04-06 23:57:37 +0000 | [diff] [blame] | 95 | move.l %d1, (%a0) /* set CLK = 0 */ |
| 96 | move.l %d0, (%a1) /* Output data bit6 */ |
Jens Arnold | d52bea8 | 2008-05-29 21:41:47 +0000 | [diff] [blame] | 97 | .word 0x51fa /* trapf.w - shadow next insn */ |
| 98 | 1: |
Jens Arnold | 9737fc7 | 2008-04-06 23:57:37 +0000 | [diff] [blame] | 99 | move.l %d1, (%a0) /* set CLK = 0 */ |
Jens Arnold | 9737fc7 | 2008-04-06 23:57:37 +0000 | [diff] [blame] | 100 | .endm |
Jens Arnold | 9737fc7 | 2008-04-06 23:57:37 +0000 | [diff] [blame] | 101 | |
Jens Arnold | d52bea8 | 2008-05-29 21:41:47 +0000 | [diff] [blame] | 102 | bit_out |
| 103 | nop |
| 104 | nop |
| 105 | bit_out |
| 106 | nop |
| 107 | nop |
| 108 | bit_out |
| 109 | nop |
| 110 | nop |
| 111 | bit_out |
| 112 | nop |
| 113 | nop |
| 114 | bit_out |
| 115 | nop |
| 116 | nop |
| 117 | bit_out |
| 118 | nop |
| 119 | nop |
| 120 | bit_out |
| 121 | nop |
| 122 | nop |
| 123 | |
Jens Arnold | 9737fc7 | 2008-04-06 23:57:37 +0000 | [diff] [blame] | 124 | move.l %d2, (%a0) /* Bit0: Set CLK = 1 */ |
Jens Arnold | d52bea8 | 2008-05-29 21:41:47 +0000 | [diff] [blame] | 125 | nop |
| 126 | nop |
Jens Arnold | 9737fc7 | 2008-04-06 23:57:37 +0000 | [diff] [blame] | 127 | move.l %d1, (%a0) /* Set CLK = 0 */ |
| 128 | |
| 129 | move.w %d3, %sr /* Restore interrupt level */ |
| 130 | rts |
| 131 | |
| 132 | /* Output 8 bits to the LCD as fast as possible. Use only at < 60MHz. |
| 133 | * |
| 134 | * Custom calling convention: |
| 135 | * %a0 - GPIO_OUT_ADDR |
| 136 | * %a1 - GPIO1_OUT_ADDR |
| 137 | * %d4 - data word |
| 138 | * %d6 - DATA_MASK |
| 139 | * Clobbers: |
| 140 | * %d0..%d4 |
| 141 | */ |
| 142 | #ifdef HAVE_REMOTE_LCD_TICKING |
| 143 | .write_byte_fast_delayed: |
| 144 | move.l remote_byte_delay, %d0 |
| 145 | 1: |
| 146 | subq.l #1, %d0 |
| 147 | bne.s 1b |
| 148 | #endif |
| 149 | |
| 150 | .write_byte_fast: |
| 151 | move.w %sr, %d3 /* Get current interrupt level */ |
| 152 | move.w #0x2700,%sr /* Disable interrupts */ |
| 153 | |
| 154 | move.l (%a1), %d0 /* Get current state of data port */ |
| 155 | move.l %d0, %d1 |
| 156 | and.l %d6, %d1 /* Check current state of data line */ |
| 157 | beq.s 1f /* and set it as previous-state bit */ |
| 158 | bset #8, %d4 |
| 159 | 1: |
| 160 | move.l %d4, %d1 /* Compute the 'bit derivative', i.e. a value */ |
| 161 | lsr.l #1, %d1 /* with 1's where the data changes from the */ |
| 162 | eor.l %d1, %d4 /* previous state, and 0's where it doesn't */ |
| 163 | swap %d4 /* Shift data to upper byte */ |
| 164 | lsl.l #8, %d4 |
| 165 | |
| 166 | move.l (%a0), %d1 /* Get current state of clock port */ |
| 167 | move.l %d1, %d2 /* Precalculate opposite state of clock line */ |
| 168 | eor.l #CLOCK_MASK, %d2 |
| 169 | |
| 170 | .macro bit_out_fast |
| 171 | lsl.l #1,%d4 /* Shift out MSB */ |
| 172 | bcc.s 1f |
| 173 | eor.l %d6, %d0 /* 1: flip data bit */ |
| 174 | move.l %d0, (%a1) /* and output new DATA state */ |
| 175 | 1: |
| 176 | move.l %d2, (%a0) /* Set CLK */ |
| 177 | move.l %d1, (%a0) /* Reset CLK */ |
| 178 | .endm |
| 179 | bit_out_fast |
| 180 | bit_out_fast |
| 181 | bit_out_fast |
| 182 | bit_out_fast |
| 183 | bit_out_fast |
| 184 | bit_out_fast |
| 185 | bit_out_fast |
| 186 | bit_out_fast |
| 187 | |
| 188 | move.w %d3, %sr /* Restore interrupt level */ |
| 189 | rts |
| 190 | |
| 191 | |
| 192 | .global lcd_remote_write_command |
| 193 | .type lcd_remote_write_command, @function |
| 194 | |
| 195 | lcd_remote_write_command: |
| 196 | lea.l (-4*4, %sp), %sp |
| 197 | movem.l %d2-%d4/%d6, (%sp) |
| 198 | |
| 199 | move.l (4*4+4, %sp), %d4 /* cmd */ |
| 200 | |
| 201 | lea.l GPIO_OUT_ADDR, %a0 |
| 202 | lea.l GPIO1_OUT_ADDR, %a1 |
| 203 | move.l #DATA_MASK, %d6 |
| 204 | |
| 205 | clr.l remote_cs_countdown |
| 206 | |
| 207 | move.l #~RS_MASK, %d0 |
| 208 | and.l %d0, (%a0) |
| 209 | moveq.l #~CS_MASK, %d0 |
| 210 | and.l %d0, (%a1) |
| 211 | |
| 212 | #ifdef HAVE_REMOTE_LCD_TICKING |
| 213 | tst.l remote_byte_delay |
| 214 | ble.s 1f |
| 215 | bsr.w .write_byte_delayed |
| 216 | bra.s 2f |
| 217 | 1: |
| 218 | #endif |
| 219 | bsr.w .write_byte |
| 220 | 2: |
| 221 | |
| 222 | moveq.l #CS_TIMEOUT, %d0 |
| 223 | move.l %d0, remote_cs_countdown |
| 224 | |
| 225 | movem.l (%sp), %d2-%d4/%d6 |
| 226 | lea.l (4*4, %sp), %sp |
| 227 | rts |
| 228 | |
| 229 | |
| 230 | .global lcd_remote_write_command_ex |
| 231 | .type lcd_remote_write_command_ex, @function |
| 232 | |
| 233 | lcd_remote_write_command_ex: |
| 234 | lea.l (-4*4, %sp), %sp |
| 235 | movem.l %d2-%d4/%d6, (%sp) |
| 236 | |
| 237 | lea.l GPIO_OUT_ADDR, %a0 |
| 238 | lea.l GPIO1_OUT_ADDR, %a1 |
| 239 | move.l #DATA_MASK, %d6 |
| 240 | |
| 241 | clr.l remote_cs_countdown |
| 242 | |
| 243 | move.l #~RS_MASK, %d0 |
| 244 | and.l %d0, (%a0) |
| 245 | moveq.l #~CS_MASK, %d0 |
| 246 | and.l %d0, (%a1) |
| 247 | |
| 248 | move.l (4*4+4, %sp), %d4 |
| 249 | |
| 250 | #ifdef HAVE_REMOTE_LCD_TICKING |
| 251 | tst.l remote_byte_delay |
| 252 | ble.s 1f |
| 253 | bsr.w .write_byte_delayed |
| 254 | move.l (4*4+8, %sp), %d4 |
| 255 | bsr.w .write_byte_delayed |
| 256 | bra.s 2f |
| 257 | 1: |
| 258 | #endif |
| 259 | bsr.w .write_byte |
| 260 | move.l (4*4+8, %sp), %d4 |
| 261 | bsr.w .write_byte |
| 262 | 2: |
| 263 | |
| 264 | moveq.l #CS_TIMEOUT, %d0 |
| 265 | move.l %d0, remote_cs_countdown |
| 266 | |
| 267 | movem.l (%sp), %d2-%d4/%d6 |
| 268 | lea.l (4*4, %sp), %sp |
| 269 | rts |
| 270 | |
| 271 | |
| 272 | .global lcd_remote_write_data |
| 273 | .type lcd_remote_write_data, @function |
| 274 | |
| 275 | lcd_remote_write_data: |
| 276 | lea.l (-7*4, %sp), %sp |
| 277 | movem.l %d2-%d6/%a2-%a3, (%sp) |
| 278 | |
| 279 | move.l (7*4+4, %sp), %a2 /* p_bytes */ |
| 280 | move.l (7*4+8, %sp), %d5 /* count */ |
| 281 | |
| 282 | lea.l GPIO_OUT_ADDR, %a0 |
| 283 | lea.l GPIO1_OUT_ADDR, %a1 |
| 284 | move.l #DATA_MASK, %d6 |
| 285 | |
| 286 | lea.l .write_byte, %a3 |
| 287 | move.l cpu_frequency, %d0 |
| 288 | cmp.l #60000000, %d0 |
| 289 | bhi.b 1f |
| 290 | lea.l .write_byte_fast, %a3 |
| 291 | 1: |
| 292 | |
| 293 | #ifdef HAVE_REMOTE_LCD_TICKING |
| 294 | tst.l remote_byte_delay |
| 295 | ble.s 1f |
| 296 | moveq.l #(.write_byte_delayed - .write_byte), %d0 |
| 297 | add.l %d0, %a3 |
| 298 | 1: |
| 299 | #endif |
| 300 | |
| 301 | clr.l remote_cs_countdown |
| 302 | |
| 303 | move.l #RS_MASK, %d0 |
| 304 | or.l %d0, (%a0) |
| 305 | moveq.l #~CS_MASK, %d0 |
| 306 | and.l %d0, (%a1) |
| 307 | |
| 308 | .wd_loop: |
| 309 | clr.l %d4 |
| 310 | move.b (%a2)+, %d4 |
| 311 | jsr (%a3) |
| 312 | subq.l #1, %d5 |
| 313 | bne.s .wd_loop |
| 314 | |
| 315 | moveq.l #CS_TIMEOUT, %d0 |
| 316 | move.l %d0, remote_cs_countdown |
| 317 | |
| 318 | movem.l (%sp), %d2-%d6/%a2-%a3 |
| 319 | lea.l (7*4, %sp), %sp |
| 320 | rts |