blob: faeb59e3763232f74e6fba6dd1a5eb9a98e4f02f [file] [log] [blame]
h# 004c constant pmua_display1_clk_res_ctrl_offset \ DISPLAY1 Clock/Reset Control Register
h# 0110 constant pmua_display2_clk_res_ctrl_offset \ DISPLAY2 Clock/Reset Control Register
h# 0050 constant pmua_ccic_clk_res_ctrl_offset \ CCIC Clock/Reset Control Register
: pmua@ ( offset -- n ) pmua-pa + io@ ;
: pmua! ( n offset -- ) pmua-pa + io! ;
: dsi-twsi! ( l reg# -- )
>r lbsplit swap 2swap swap r> wbsplit 6 twsi-out
;
: dsi-twsi-w! ( w reg# -- )
>r wbsplit swap r> wbsplit 4 twsi-out
;
: dsi-twsi@ ( reg# -- l ) wbsplit 2 4 twsi-get bljoin ;
: dsi-twsi-w@ ( reg# -- w ) wbsplit 2 2 twsi-get bwjoin ;
: dsi1! ( n offset -- ) dsi1-pa + io! ;
: dsi1@ ( n offset -- ) dsi1-pa + io@ ;
: dsi2! ( n offset -- ) dsi2-pa + io! ;
: dsi2@ ( n offset -- ) dsi2-pa + io@ ;
0 value dsi-base
: dsi! ( n offset -- ) dsi-base + io! ;
: dsi@ ( n offset -- ) dsi-base + io@ ;
: bitset ( mask reg-adr -- ) tuck io@ or swap io! ;
: bitclr ( mask reg-adr -- ) tuck io@ swap invert and swap io! ;
: init-dsi1 ( -- )
\ Ensure that the pins are set up properly
h# c0 d# 83 gpio>mfpr io! \ Configure GPIO83 for function 0 - GPIO
d# 83 gpio-dir-out \ Set the direction control to output
h# d123f h# 4c pmua! \ Send clock to TC358762 MIPI DSI bridge
\ Enable the M/N clock output
main-pmu-pa h# 1024 + io@ h# 200 or main-pmu-pa h# 1024 + io! \ Set (GPC) G_CLK_OUT ena in clock gating register
\ Set the M/N value and re-enable the clock gate register
h# 20001 main-pmu-pa h# 30 + io! \ Set M/N divider values in PMUM_GPCR register
h# 4000 mfpr-base h# 160 + bitset \ pull-up
\ Disable DSI
0 h# 00 dsi1! \ Stop the interface
h# c000.0000 dsi1-pa h# 00 + bitset
2 ms
h# c000.0000 dsi1-pa h# 00 + bitclr
2 ms
d# 83 gpio-clr 1 ms d# 83 gpio-set 1 ms \ LCD_RST_N line resets DSI bridge
h# 0b 5 set-twsi-target \ TWSI address of TC358762 MIPI DSI bridge
\ Data Reg#.......
0 h# 047c dsi-twsi! \ Turn off sleep mode
2 ms
7 h# 0210 dsi-twsi! \ Enable 2 lanes + clock lane
h# b8230000 h# 0470 dsi-twsi! \ Set PCLK to 33.2 MHz
5 ms
h# 0400 h# 0464 dsi-twsi! \ Set PCLK divider
5 ms
1 h# 204 dsi-twsi! \ Start RX
0 h# 144 dsi-twsi! \ Analog timer setup for lane 0
0 h# 148 dsi-twsi! \ Analog timer setup for lane 1
\ Set asserting period for the duration between LP-00 detect and
\ High Speed data reception for each lane. (This is for LANE 0)
\ Set between 85ns + 6*UI and 145 ns + 10*UI based on HSBCLK
h# a h# 164 dsi-twsi! \ D0S_CLRSIPOCOUNT register
\ Set asserting period for the duration between LP-00 detect and
\ High Speed data reception for each lane. (This is for LANE 1)
\ Set between 85ns + 6*UI and 145 ns + 10*UI based on HSBCLK
h# a h# 168 dsi-twsi! \ D1S_CLRSIPOCOUNT register
h# 150 h# 420 dsi-twsi! \ LCDCTR0 - RGB888 24-bit color
h# 3FF0000 h# 0450 dsi-twsi! \ SPIRCMR/SPICTRL
1 h# 0104 dsi-twsi! \ STARTPPI
\ High speed mode setup
h# 2102 h# 0020 dsi-twsi! \ CLW_DLYCNTRL = 20pS -> CLW_DPHYCONTRX
h# 2002 h# 0024 dsi-twsi! \ D0W_DLYCNTRL = 10pS -> D0W_DPHYCONTRX
h# 2002 h# 0028 dsi-twsi! \ D1W_DLYCNTRL = 10pS -> D1W_DPHYCONTRX
1 h# 204 dsi-twsi! \ Start RX -> STARTDSI (repeat)
h# 152 h# 420 dsi-twsi! \ LCDCTR0 - RGB888 24-bit color
hsync h# 424 dsi-twsi-w! \ HSYNC width
hbp h# 426 dsi-twsi-w! \ Horizontal back porch
hdisp h# 428 dsi-twsi-w! \ Horizontal display
hfp h# 42a dsi-twsi-w! \ Horizontal front porch
vsync h# 42c dsi-twsi-w! \ VSYNC
vbp h# 42e dsi-twsi-w! \ Vertical back porch
vdisp h# 430 dsi-twsi-w! \ Vertical display
vfp h# 432 dsi-twsi-w! \ Vertical front porch
\ Magic numbers, tuned with scope
h# 07320302 h# c0 dsi1! \ PHY time 0
h# 370afff0 h# c4 dsi1! \ PHY time 1
h# 070a1504 h# c8 dsi1! \ PHY time 2
h# 00000400 h# cc dsi1! \ PHY time 3
h# 30 h# 88 dsi1! \ PHY control 2 - enable 2 lanes
h# 30.0000 h# 24 dsi1! \ Packet command 1 - enable low power tx on 2 lanes
htotal bytes/pixel * #lanes / ( total-chunks )
hdisp bytes/pixel * #lanes / ( total-chunks disp-chunks )
wljoin h# 110 dsi1! \ DSI_LCD1_TIMING_0
hbp hsync wljoin h# 114 dsi1! \ DSI_LCD1_TIMING_1
\ For now the active size is set really low (we'll use 10) to allow
\ the hardware to attain V Sync. Once the DSI bus is up and running,
\ the final value will be put in place for the active size (this is
\ done below). In a later stepping of the processor this workaround
\ will not be required.
vtotal ( vdisp ) d# 10 wljoin h# 118 dsi1! \ DSI_LCD1_TIMING_2
\ The 1- below is for debugging, to get first line positioned properly
vbp 1- vsync wljoin h# 11c dsi1! \ DSI_LCD1_TIMING_3
hsync >bytes d# 11 - 0 max 4 - 6 - ( low )
hbp hsync + >bytes 4 - 6 - ( low high )
wljoin h# 120 dsi1! \ DSI_LCD1_WC_0
hdisp >bytes hfp >bytes 6 - 6 - wljoin h# 124 dsi1! \ DSI_LCD1_WC_1
h# 0040.0010 h# 100 dsi1! \ DSI_LCD1_CTRL_0
h# 0014.0007 h# 104 dsi1! \ DSI_LCD1_CTRL_1 - non-burst w/ sync, 24bpp
h# e4 h# 4 dsi1! \ DSI_CTRL_1 - virtual channel setup
h# 1 h# 0 dsi1! \ DSI_CTRL_0 - active panel 1 enable
d# 100 ms
\ Reset timing register 2 to its final value (workaround)
h# 118 dsi1@ \ DSI_LCD1_TIMING_2
lwsplit drop
vdisp 2- wljoin
h# 118 dsi1! \ DSI_LCD1_TIMING_2
;
[ifdef] debug-dsi
: .dsi ( index -- ) dup 3 u.r space dsi-twsi@ 8 u.r cr ;
: .dsiw ( index -- ) dup 3 u.r space dsi-twsi-w@ 8 u.r cr ;
: dump-dsi ( -- )
0b 5 set-twsi-target
47c .dsi
210 .dsi
470 .dsi
464 .dsi
204 .dsi
144 .dsi
148 .dsi
164 .dsi
168 .dsi
420 .dsi
450 .dsi
104 .dsi
20 .dsi
24 .dsi
28 .dsi
204 .dsi
420 .dsi
424 .dsiw
426 .dsiw
428 .dsiw
42a .dsiw
42c .dsiw
42e .dsiw
430 .dsiw
432 .dsiw
;
[then]
[ifdef] support-low-speed-dsi
: parity ( n -- 0|1 )
dup d# 16 rshift xor
dup 8 rshift xor
dup 4 rshift xor
dup 2 rshift xor
dup u2/ xor
1 and
;
\ ECC bits
\ 10 11 12 13 14 15 16 17 18 19 21 22 23 ->ecc[5] h# effc00
\ 4 5 6 7 8 9 16 17 18 19 20 22 23 ->ecc[4] h# df03f0
\ 1 2 3 7 8 9 13 14 15 19 20 21 23 ->ecc[3] h# b8e38e
\ 0 2 3 5 6 9 11 12 15 18 20 21 22 ->ecc[2] h# 749a6d
\ 0 1 3 4 6 8 10 12 14 17 20 21 22 23 ->ecc[1] h# f2555b
\ 0 1 2 4 5 7 10 11 13 16 20 21 22 23 ->ecc[0] h# f12cb7
: calc-ecc ( l -- )
>r
\ The following masks are all 00 in the low byte, because the calculation
\ skips the first byte in the array
r@ 00ef.fc00 and parity d# 29 lshift
r@ 00df.03f0 and parity d# 28 lshift or
r@ 00b8.e38e and parity d# 27 lshift or
r@ 009a.746d and parity d# 26 lshift or
r@ 00f2.555b and parity d# 25 lshift or
r@ 00f1.2cb7 and parity d# 24 lshift or ( ecc )
r> or
;
: updcrc ( byte crc -- crc' )
8 0 do ( byte crc )
2dup xor 1 and if ( byte crc )
u2/ h# 8408 xor ( byte crc' )
else
u2/ ( byte crc' )
then ( byte crc )
swap u2/ swap ( byte' crc )
loop ( byte crc )
nip ( crc )
;
: calc-crc16 ( adr len -- ) \ Len includes the CRC
swap 4 + swap 6 - ( payload-adr payload-len )
h# ffff >r ( adr len r: crc )
begin dup while ( adr len r: crc )
over c@ ( adr len byte r: crc )
r> updcrc >r ( adr len r: crc' )
repeat ( adr len r: crc' )
drop r> ( adr crc )
swap le-w! ( )
;
: calc-checksums ( adr len low-speed? -- )
\ Calculate ECC and maybe CRC if low speed - hardware does it in high speed mode
third if ( adr len )
over le-l@ calc-ecc ( adr len ecc )
third le-l! ( adr len )
\ Calculate CRC if long packet
dup 4 <> if ( adr len )
2dup calc-crc16 ( adr len )
then ( adr len )
then ( adr len )
;
[then]
[ifdef] use-dsi2
: set-dsi-data ( l index -- )
swap h# 30 dsi! ( index ) \ Data register
d# 16 lshift h# c000.0000 or h# 2c dsi! \ Packet data address to CPU_CMD_3 register
h# 400 0 do h# 2c dsi@ 0>= abort" DSI timeout" loop
;
: stuff-dsi-fifo ( adr len -- )
0 ?do ( adr' )
dup le-l@ i la1+ set-dsi-data ( adr )
la1+ ( adr' )
4 +loop ( adr )
drop ( )
;
: run-dsi-cmd ( cmd -- )
h# 20 dsi! ( )
h# 400 0 do ( )
h# 20 dsi@ 0>= ?leave ( )
loop ( )
;
: dsi-write-short ( l -- ) \ high speed short packet
\ calc-ecc ( l' )
0 set-dsi-data ( )
h# c000.0000 run-dsi-cmd ( )
;
: dsi-write ( adr len -- )
\ Send the long payload code and the length as the first word
dup 8 lshift h# 29 or 0 set-dsi-data ( adr len )
tuck stuff-dsi-fifo ( len )
h# 8000.0000 or run-dsi-cmd
;
: setup-lcd ( -- )
" "(F1 5A 5A)" dsi-write
" "(FC 5A 5A)" dsi-write
" "(B7 00 11 11)" dsi-write
" "(B8 2d 21)" dsi-write
" "(B8 00 06)" dsi-write
" "(2a 00 00 01 df)" dsi-write
" "(2b 00 00 02 7f)" dsi-write
h# 00001105 dsi-write-short
5 ms
" "(F4 00 23 00 64 5C 00 64 5C 00 00)" dsi-write
" "(F5 00 00 0E 00 04 02 03 03 03 03)" dsi-write
" "(EE 32 29 00)" dsi-write
" "(F2 00 30 88 88 57 57 10 00 04)" dsi-write
" "(F3 00 10 25 01 2D 2D 24 2D 10 12 12 73)" dsi-write
" "(F6 21 AE BF 62 22 62)" dsi-write
" "(F7 00 01 00 F2 0A 0A 0A 30 0A 00 0F 00 0F 00 4B 00 8C)" dsi-write
" "(F8 00 01 00 F2 0A 0A 0A 30 0A 00 0F 00 0F 00 4B 00 8C)" dsi-write
" "(F9 11 10 0F 00 01 02 04 05 08 00 0A 00 00 00 0F 10 11 00 00 C3 FF 7F)" dsi-write
d# 120 ms
h# 00002905 dsi-write-short
;
\ This is for the TV path
: init-dsi2 ( -- )
\ Send clock to TC358762 MIPI DSI bridge
h# d123f h# 4c pmua! \ Display 1 clock
h# d123f h# 110 pmua! \ Display 2 clock
\ Disable DSI
0 h# 00 dsi2! \ Stop the interface
h# c000.0000 dsi2-pa h# 00 + bitset
1 ms
h# c000.0000 dsi2-pa h# 00 + bitclr
1 ms
\ Magic numbers, tuned with scope
h# 07320302 h# c0 dsi2! \ PHY time 0
h# 370afff0 h# c4 dsi2! \ PHY time 1
h# 070a1504 h# c8 dsi2! \ PHY time 2
h# 00000400 h# cc dsi2! \ PHY time 3
h# 30 h# 88 dsi2! \ PHY control 2 - enable 2 lanes
h# 30.0000 h# 24 dsi2! \ Packet command 1 - enable low power tx on 2 lanes
setup-lcd
htotal >chunks hdisp >chunks wljoin h# 190 dsi2! \ DSI_LCD2_TIMING_0
hbp hsync wljoin h# 194 dsi2! \ DSI_LCD2_TIMING_1
\ For now the active size is set really low (we'll use 10) to allow
\ the hardware to attain V Sync. Once the DSI bus is up and running,
\ the final value will be put in place for the active size (this is
\ done below). In a later stepping of the processor this workaround
\ will not be required.
vtotal vdisp wljoin h# 198 dsi2! \ DSI_LCD2_TIMING_2
\ The 1- below is for debugging, to get first line positioned properly
vbp 1- vsync wljoin h# 19c dsi2! \ DSI_LCD2_TIMING_3
hsync bytes/pixel * d# 11 - 0 max 4 - 6 - ( low )
hbp hsync + bytes/pixel * 4 - 6 - ( low high )
wljoin h# 1a0 dsi2! \ DSI_LCD2_WC_0
hdisp hfp bytes/pixel * wljoin h# 124 dsi1! \ DSI_LCD1_WC_1
h# 0050.0010 h# 180 dsi2! \ DSI_LCD2_CTRL_0
h# 0014.0007 h# 184 dsi2! \ DSI_LCD2_CTRL_1 - non-burst w/ sync, 24bpp
h# e4 h# 4 dsi2! \ DSI_CTRL_1 - virtual channel setup
h# 1 h# 0 dsi2! \ DSI_CTRL_0 - active panel 1 enable
d# 100 ms
\ Reset timing register 2 to its final value (workaround)
h# 198 dsi2@ \ DSI_LCD2_TIMING_2
lwsplit drop
vdisp 2- wljoin
h# 198 dsi2! \ DSI_LCD2_TIMING_2
;
: dsi-read ( -- n ) h# 64 dsi2@ ;
: dsi-lcd ( enable? -- )
0 dsi1@ 7 invert and 0 dsi1! \ Disable all panels
h# 4c pmua@ 2 invert and h# 4c pmua! \ stop clock?
( enable? ) if
d# 100 ms
h# 4c pmua@ 2 or h# 4c pmua! \ start clock
d# 100 ms
0 dsi1@ 1 or 0 dsi1! \ Enable panel 0
then
;
h# 106 buffer: dsi-cmd-buf
: lcd-send-some ( code adr len -- code' adr' len' )
rot dup dsi-cmd-buf c! ( adr len code )
h# 10 or -rot ( code' adr len ) \ Change code to 3c after first time
dup d# 240 min ( code adr len thislen )
third dsi-cmd-buf 1+ third ( code adr len thislen adr dst thislen )
move ( code adr len thislen )
dsi-cmd-buf over dsi-write ( code adr len thislen )
/string ( code adr' len' )
;
: lcd-send ( adr len -- )
h# 2c -rot ( code adr len )
begin dup while ( code adr len )
lcd-send-some ( code' adr' len' )
repeat ( code' adr' len' )
3drop
;
[then]