#include "vhex/display.h" #include "vhex/defs/attributes.h" #include "vhex/defs/types.h" /* Registers and operations */ enum { device_code_read = 0x000, driver_output_control = 0x001, entry_mode = 0x003, display_control_2 = 0x008, low_power_control = 0x00b, ram_address_horizontal = 0x200, ram_address_vertical = 0x201, write_data = 0x202, horizontal_ram_start = 0x210, horizontal_ram_end = 0x211, vertical_ram_start = 0x212, vertical_ram_end = 0x213, }; /* Interface with the controller */ static volatile uint16_t *intf = (void *)0xb4000000; /* Bit 4 of Port R controls the RS bit of the display driver */ static volatile uint8_t *PRDR = (void *)0xa405013c; static void select(uint16_t reg) { /* Clear RS and write the register number */ *PRDR &= ~0x10; __asm__ volatile ("synco"::); *intf = reg; __asm__ volatile ("synco"::); /* Set RS back. We don't do this in read()/write() because the display driver is optimized for consecutive GRAM access. LCD-transfers will be faster when executing select() followed by several calls to write(). (Although most applications should use the DMA instead.) */ *PRDR |= 0x10; __asm__ volatile ("synco"::); } static void write(uint16_t data) { *intf = data; } /* dupdate(): Push the video RAM to the display driver */ VWEAK void dupdate(void) { extern uint16_t vhex_vram[]; /* Set the windows size */ select(horizontal_ram_start); write(0); select(horizontal_ram_end); write(395); select(vertical_ram_start); write(0); select(vertical_ram_end); write(223); /* Set the RAM position */ select(ram_address_horizontal); write(0); select(ram_address_vertical); write(0); /* Bind address 0xb4000000 to the data write command */ select(write_data); /* force-fill manualy the screen */ for (int i = 0; i < 396 * 224; ++i) write(vhex_vram[i]); }