; Copyright 2009 Castle Technology Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;

        GET     Hdr:ListOpts
        GET     Hdr:Macros
        GET     Hdr:System
        GET     Hdr:Machine.<Machine>
        GET     Hdr:ImageSize.<ImageSize>
        $GetIO
        GET     Hdr:Proc

        GET     Hdr:OSEntries
        GET     Hdr:HALEntries

        GET     hdr.omap3530
        GET     hdr.StaticWS
        GET     hdr.PRCM
        GET     hdr.GPIO
        GET     hdr.Timers
        GET     hdr.SPI

        AREA    |Asm$$Code|, CODE, READONLY, PIC

        EXPORT  Video_Init
        EXPORT  VideoDevice_Init
        EXPORT  Video_Power_VBC_DVI
        EXPORT  Video_Power_VBC_Pandora
        EXPORT  Video_Power_VBC_TouchBook
        EXPORT  Video_SetPandoraGamma

        IMPORT  memcpy
        IMPORT  GPIOx_SetAsOutput
        IMPORT  GPIOx_SetOutput
        IMPORT  HAL_CounterDelay
        IMPORT  TPSWrite

Video_Init
        ; Configure GPIO pins so we can turn the DVI framer on/off
        LDRB    a1, [sb, #BoardConfig_VideoGPIO]
        CMP     a1, #255
        MOV     a2, #0
        BNE     GPIOx_SetAsOutput ; Turn DVI framer off
        MOV     pc, lr

VideoDevice_Init
        ; Not much to do here - just register our HAL device
        Push    "v1,lr"
        ADRL    v1, VideoDevice
        MOV     a1, v1
        ADR     a2, VideoDeviceTemplate
        MOV     a3, #Video_DeviceSize
        BL      memcpy
        LDR     a1, L4_Display_Log
        STR     a1, [v1, #HALDevice_Address]
        ADRL    a3, VideoBoardConfig
        STR     a3, [v1, #HALDevice_VDUDeviceSpecificField]
        STR     sb, [v1, #:INDEX:VideoWorkspace]
        ; Fill in the board config
        LDR     a2, sys_clk
        STR     a2, [a3, #VideoBoardConfig_sys_clk]
        BL      Determine_PorchSync_Limits
        STRH    a1, [a3, #VideoBoardConfig_Max_Porch]
        STRH    a2, [a3, #VideoBoardConfig_Max_Sync]
        LDR     a2, L4_sDMA_Log
        STR     a2, [a3, #VideoBoardConfig_DMA_Ptr]
        MOV     a2, #SDMA_IRQ_1
        STR     a2, [a3, #VideoBoardConfig_DMA_Device]
        ASSERT  SDMA_NumDevices = 31
        MOV     a2, #&80000000
        STR     a2, [a3, #VideoBoardConfig_DMA_Chans]
        LDRB    a2, [sb, #BoardConfig_VBC_Flags]
        STRB    a2, [a3, #VideoBoardConfig_Flags]
        LDRB    a2, [sb, #BoardConfig_VBC_LCDNum]
        STRB    a2, [a3, #VideoBoardConfig_Num_LCDs]
        MOV     a2, #VideoBoardConfig_Size
        STRH    a2, [a3, #VideoBoardConfig_MySize]
        LDR     a2, [sb, #BoardConfig_VBC_LCDPtr]
        STR     a2, [a3, #VideoBoardConfig_LCD_Configs]
        ADR     a2, Video_TVDet_Func
        STR     a2, [a3, #VideoBoardConfig_TVDet_Func]
        ADR     a2, Video_TVPower_Func
        STR     a2, [a3, #VideoBoardConfig_TVPower_Func]
        MOV     a1, #0
        MOV     a2, v1
        CallOS  OS_AddDevice
      [ {FALSE}
        ; Pandora hack - point GFX overlay at the start of physical memory so we can catch any early error messages
        ; This will treat the 8bpp display as 16bpp, so it'll be a bit squashed, but better than nothing
        LDR     a1, L4_Display_Log
        MOV     a2, #&80000000
        STR     a2, [a1, #&480]
        STR     a2, [a1, #&484]
        LDR     a2, =319+(479<<16)
        STR     a2, [a1, #&48c]
        LDR     a2, =&18329
        STR     a2, [a1, #&440]
      ]
        Pull    "v1,pc"

VideoDeviceTemplate
        DCW     HALDeviceType_Video + HALDeviceVideo_VDU
        DCW     HALDeviceID_VDU_OMAP3
        DCD     HALDeviceBus_Interconnect + HALDeviceInterconnectBus_L3
        DCD     0               ; API version 0
        DCD     VideoDevice_Desc
        DCD     0               ; Address - filled in later
        %       12              ; Reserved
        DCD     VideoDevice_Activate
        DCD     VideoDevice_Deactivate
        DCD     VideoDevice_Reset
        DCD     VideoDevice_Sleep
        DCD     VIDEO_IRQ ; Device.
        DCD     0               ; TestIRQ cannot be called
        %       8
        DCD     0          ; Pointer to board config stuff - filled in later
        ASSERT (.-VideoDeviceTemplate) = HALDevice_VDU_Size
        DCD     0          ; HAL workspace pointer - filled in later
        ASSERT (.-VideoDeviceTemplate) = Video_DeviceSize

VideoDevice_Desc
        =       "OMAP3 video controller", 0
        ALIGN

VideoDevice_Activate
        Entry   "sb"
        LDR     sb, VideoWorkspace
        ; Enable DSS power
        ; TODO - should disable interrupts for this bit!
        LDR     a1, L4_ClockMan_Log
        LDR     a2, [a1, #CM_ICLKEN_DSS]
        ORR     a2, a2, #1 ; EN_DSS (correct to enable iclk before fclk?)
        STR     a2, [a1, #CM_ICLKEN_DSS]
        LDR     a2, [a1, #CM_FCLKEN_DSS]
        ORR     a2, a2, #7 ; EN_DSS1, EN_DSS2, EN_TV (required for reset)
        STR     a2, [a1, #CM_FCLKEN_DSS]
        MOV     a1, #1
        EXIT

VideoDevice_Deactivate ; TODO!
VideoDevice_Reset
        MOV     pc, lr

VideoDevice_Sleep
        MOV     a1, #0
        MOV     pc, lr

Video_Power_VBC_DVI
        ; a1 = HAL device
        ; a2 = brightness 0-65536, which we treat as a simple on/off flag
        Entry   "sb"
        LDR     sb, VideoWorkspace
      [ DebugTiming
        CMP     a2, #0
        BEQ     %FT10
        DebugTime a1, "Video on @ "
10
      ]
        ; Just set the GPIO to the right value
        LDRB    a1, [sb, #BoardConfig_VideoGPIO]
        CMP     a1, #255
        BLNE    GPIOx_SetOutput
        EXIT

Video_Power_VBC_TouchBook
        ; a1 = HAL device
        ; a2 = brightness 0-65536
        Entry   "sb"
        LDR     sb, VideoWorkspace
        ; TODO - Proper brightness controls
        ; For now, just toggle on/off, via the SCPWM bit of GPTIMER9.TCLR
        LDR     a3, Timers_Log
        ADD     a3, a3, #L4_GPTIMER9-TIMER_BASE
        CMP     a2, #0
        LDR     a4, [a3, #TCLR]
        BICEQ   a4, a4, #&80
        ORRNE   a4, a4, #&80
        STR     a4, [a3, #TCLR]
        ; Also toggle the GPIO that controls the DVI framer
        LDRB    a1, [sb, #BoardConfig_VideoGPIO]
        CMP     a1, #255
        BLNE    GPIOx_SetOutput
        EXIT

Video_Power_VBC_Pandora ROUT
        ; a1 = HAL device
        ; a2 = brightness 0-65536
        Entry   "a2,v4,sb"
        LDR     sb, VideoWorkspace
        ; TODO - Proper brightness controls, and proper LCD power control.
        ; To turn the power on/off properly it looks like it needs to be done over several frames, which would ideally require some changes to OMAPVideo to ensure we're called from the foreground and aren't re-entered.
        ; For now we'll just put the LCD in/out of standby, via the SPI interface
        TEQ     a2, #0
        MOVEQ   a4, #&d8
        MOVNE   a4, #&df
        LDR     a2, L4_Core_Log
        ADD     a2, a2, #L4_McSPI1-L4_Core
        ADD     a2, a2, #MCSPI_STRIDE
        LDR     v4, =(7<<2)+(1<<6)+(15<<7)+(2<<12)+(1<<16)
        MOV     a3, #3
        BL      td043_write
        ; The datasheet says we should wait 9 frames before cutting the sync
        ; signals, but OMAPVideo will cut them right away. Luckily it looks like
        ; we can get by with waiting just one frame.
        LDR     a2, [sp]
        TEQ     a2, #0
        LDREQ   a1, =17000
        BLEQ    HAL_CounterDelay
        EXIT

Determine_PorchSync_Limits
        ; Returns:
        ; a1 = max porch value
        ; a2 = max sync value
        ; Get the OMAP revision so we can find out how large the timing registers are. OMAP35x errata shows that in ES 3.1+ the registers were increased from 8/6 bits to 12/8 bits.
        LDR     a2, L4_Wakeup_Log
        ADD     a2, a2, #(L4_CONTROL_IDCODE-L4_Wakeup) :AND: &FF00
        LDR     a2, [a2, #(L4_CONTROL_IDCODE-L4_Wakeup) :AND: &00FF]
        ; Check revision first
        CMP     a2, #REVISION_ES31 :SHL: 28
        MOVHS   a1, #1:SHL:12
        MOVHS   a2, #1:SHL:8
        MOVHS   pc, lr
        ; Revision check failed - check if this is OMAP35x
        ; If not, assume it's something newer which supports the larger timings
        LDR     a1, =HAWKEYE_OMAP35x_ES10
        MOV     a2, a2, LSL #4
        CMP     a1, a2, LSR #16
        LDRNE   a1, =HAWKEYE_OMAP35x
        CMPNE   a1, a2, LSR #16
        MOVNE   a1, #1:SHL:12
        MOVNE   a2, #1:SHL:8
        MOVEQ   a1, #1:SHL:8
        MOVEQ   a2, #1:SHL:6
        MOV     pc, lr

Video_TVDet_Func
        Entry   "sb"
        LDR     sb, VideoWorkspace
        ; The TV detect signal is internally hardwired to GPIO 33
        GPIO_PrepareC a1, a2, 33
        GPIO_GetInput a1, a1, a2
        EXIT

Video_TVPower_Func
        Entry   "v1-v2,sb", 4
        LDR     sb, VideoWorkspace
        LDR     v1, OSentries+4*OS_IICOpV
        MOVS    ip, a2
        MOV     a3, #1
        MOV     a2, sp
        BEQ     %FT50
        ; Configure VDAC for 1.8V output
        MOV     a1, #&4b*2
        MOV     ip, #3
        MOV     a4, #&99 ; VDAC_DEDICATED
        STR     ip, [a2]
        BL      TPSWrite
        ; Enable it
        MOV     ip, #&20
50      ; Arrive here with ip=0 when disabling
        MOV     a1, #&4b*2
        MOV     a4, #&96 ; VDAC_DEV_GRP
        STR     ip, [a2]
        BL      TPSWrite
        EXIT

Video_SetPandoraGamma ROUT
        Entry   "v1-v4"
        ADR     a1, PandoraGamma
        ; Reset McSPI1 and configure channel 1
        LDR     a2, L4_Core_Log
        ADD     a2, a2, #L4_McSPI1-L4_Core
        MOV     a3, #2
        STR     a3, [a2, #MCSPI_SYSCONFIG]
10
        LDR     a3, [a2, #MCSPI_SYSSTATUS]
        TST     a3, #1
        BEQ     %BT10
        MOV     a3, #1
        STR     a3, [a2, #MCSPI_MODULCTRL]
        LDR     v4, =(7<<2)+(1<<6)+(15<<7)+(2<<12)+(1<<16)
        ADD     a2, a2, #MCSPI_STRIDE
        STR     v4, [a2, #MCSPI_CHxCONF]
        ; Configure display
        MOV     a3, #2
        MOV     a4, #&f
        BL      td043_write
        MOV     a3, #3
        MOV     a4, #&df
        BL      td043_write
        MOV     a3, #&20
        MOV     a4, #&f0
        BL      td043_write
        MOV     a3, #&21
        MOV     a4, #&f0
        BL      td043_write
        ; Process gamma table
        ; Bits 9-8 of table entries
        MOV     v1, #2
20
        MOV     a4, #0
        MOV     v2, #3
30
        ADD     v3, v2, v1, LSL #2
        ADD     v3, a1, v3, LSL #1
        ADD     ip, v2, #1
        LDRH    v3, [v3]
        MOV     ip, ip, LSL #1
        AND     v3, v3, #&300
        ORR     a4, a4, v3, LSR ip
        SUBS    v2, v2, #1
        BGE     %BT30
        ADD     a3, v1, #&11
        BL      td043_write
        SUBS    v1, v1, #1
        BGE     %BT20
        ; bits 7-0
        MOV     v1, #0
40
        LDRH    a4, [a1], #2
        ADD     a3, v1, #&14
        AND     a4, a4, #255
        BL      td043_write
        ADD     v1, v1, #1
        CMP     v1, #12
        BLT     %BT40
        ; Done
        EXIT

td043_write     ROUT
        Entry   "a1-a2"
        ; In:
        ;  a2 = SPI register block
        ;  a3 = register
        ;  a4 = data
        ;  v4 = channel config
        ; Out:
        ;  a3-a4 corrupt
        ; Construct 16 bit SPI data word
        ORR     a3, a4, a3, LSL #10
        ORR     a3, a3, #1<<8
        ; Set force flag
        ORR     a4, v4, #1<<20
        STR     a4, [a2, #MCSPI_CHxCONF]
        ; Enable channel
        MOV     a4, #1
        STR     a4, [a2, #MCSPI_CHxCTRL]
        ; Write data
        STR     a3, [a2, #MCSPI_TXx]
        ; Wait for transmission
10
        LDR     a4, [a2, #MCSPI_CHxSTAT]
        AND     a4, a4, #6
        TEQ     a4, #6
        BNE     %BT10
        ; Disable channel
        MOV     a4, #0
        STR     a4, [a2, #MCSPI_CHxCTRL]
        ; Clear force flag
        STR     v4, [a2, #MCSPI_CHxCONF]
        ; TD043 datasheet says a minimum 1ns period is needed between transfers
        ; Chances are that amount of time has already passed, but play it safe
        ; and wait for 1us
        MOV     a1, #1
        BL      HAL_CounterDelay
        EXIT

        ; Default gamma table used by Linux
PandoraGamma
        DCW 105
        DCW 315
        DCW 381
        DCW 431
        DCW 490
        DCW 537
        DCW 579
        DCW 686
        DCW 780
        DCW 837
        DCW 880
        DCW 1023

        END