vxKernel/src/modules/display/dupdate.c

77 lines
1.8 KiB
C

#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]);
}