1
1
graphics/devg/vpoutfb/init.c

255 строки
7.9 KiB
C

/*
* (c) 2020, SWD Embedded Systems Limited, http://www.kpda.ru
*/
/*************************************************/
/* HEADERS */
/*************************************************/
#include "vpoutfb.h"
/*************************************************/
/* FUNCTIONS */
/*************************************************/
const struct sigevent * vpout_isr_handler( void *ptr, int id )
{
vpout_draw_context_t *vpout_draw = (vpout_draw_context_t *)ptr;
vpout_context_t *vpout = vpout_draw->vpout;
return vpout_hw_isr( vpout, vpout_draw );
}
int vpout_isr_setup( disp_adapter_t *adapter, vpout_context_t *vpout, vpout_draw_context_t *vpout_draw )
{
int err = EOK;
#ifdef ENABLE_IRQ
vpout->irq_polling = 0;
#else
vpout->irq_polling = 1;
return (0);
#endif
if ( vpout->irq == 0 )
/* Switch to polling */
return (-1);
if ( (vpout->irq_chid = ChannelCreate( _NTO_CHF_DISCONNECT | _NTO_CHF_UNBLOCK )) == -1 )
{
disp_printf( adapter, "[vpoutfb] Error: can't setup interrupt handler [channel creation failed]" );
return (-1);
}
if ( (vpout->irq_coid = ConnectAttach( 0, 0, vpout->irq_chid, _NTO_SIDE_CHANNEL, 0 )) == -1 )
{
err = errno;
goto vpout_isr_fail;
}
SIGEV_PULSE_INIT( &vpout->irq_event, vpout->irq_coid, vpout->adapter->pulseprio + 20, VBLANK_PULSE, 0 );
vpout->irq_iid = InterruptAttach( _NTO_INTR_CLASS_EXTERNAL | vpout->irq, vpout_isr_handler, vpout_draw, sizeof( *vpout_draw ),
_NTO_INTR_FLAGS_END | _NTO_INTR_FLAGS_TRK_MSK | _NTO_INTR_FLAGS_PROCESS );
if ( vpout->irq_iid == -1 )
{
err = errno;
goto vpout_isr_fail2;
}
/* Enable IRQs: see register LCDINTMASK in the vpout_hw_configure_display() */
return (0);
vpout_isr_fail2:
disp_printf( adapter, "[vpoutfb] Error: can't setup interrupt handler [interrupt attaching failed]" );
ConnectDetach( vpout->irq_coid );
vpout->irq_coid = -1;
vpout_isr_fail:
disp_printf( adapter, "[vpoutfb] Error: can't setup interrupt handler [channel connection failed]" );
ChannelDestroy( vpout->irq_chid );
vpout->irq_chid = -1;
errno = err;
return (-1);
}
void vpout_isr_cleanup( vpout_context_t *vpout, vpout_draw_context_t *vpout_draw )
{
if ( (vpout->irq_coid != -1) && (vpout->irq_coid != 0) )
ConnectDetach( vpout->irq_coid );
if ( (vpout->irq_chid != -1) && (vpout->irq_chid != 0) )
ChannelDestroy( vpout->irq_chid );
if ( (vpout->irq_iid != -1) && (vpout->irq_iid != 0) )
InterruptDetach( vpout->irq_iid );
}
int devg_shmem_size = sizeof( vpout_context_t );
int vpout_init( disp_adapter_t *adapter, char *optstring )
{
vpout_context_t *vpout = NULL;
vpout_draw_context_t *vpout_draw = NULL;
int i = 0;
uint8_t *gpio_registers = NULL;
if ( disp_register_adapter( adapter ) == -1 )
{
disp_printf( adapter, "[vpoutfb] Fatal: can't register driver" );
return (-1);
}
/* Allocate GPU context */
vpout = adapter->shmem;
if ( vpout )
memset( vpout, 0, sizeof( vpout_context_t ) );
else {
vpout = calloc( 1, sizeof( vpout_context_t ) );
if ( vpout == NULL )
{
disp_printf( adapter, "[vpoutfb] Fatal: can't allocate GPU context" );
goto fail;
}
vpout->context_allocated = 1;
}
/* Parse configuration options */
if ( parse_options( adapter, vpout, optstring ) )
goto fail;
/* Allocate draw-context */
vpout_draw = calloc( 1, sizeof( vpout_draw_context_t ) );
if ( vpout_draw == NULL )
{
disp_printf( adapter, "[vpoutfb] Fatal: can't allocate GPU draw-context" );
goto fail;
}
vpout->adapter = adapter;
vpout_draw->vpout = vpout;
adapter->ms_ctx = vpout;
adapter->vsync_counter = &vpout->vsync_counter[0];
adapter->gd_ctx = vpout_draw;
/* Mmap registers */
vpout->registers = (uint8_t *)mmap64( NULL, vpout->registers_size, PROT_READ | PROT_WRITE | PROT_NOCACHE, MAP_PHYS, NOFD, vpout->registers_base );
if ( vpout->registers == MAP_FAILED || vpout->registers == NULL )
{
disp_printf( adapter, "[vpoutfb] Fatal: can't mmap registers" );
goto fail1;
}
vpout_draw->registers = vpout->registers;
/* Get aperture metrics */
vpout->cmctr_registers = (uint8_t *)mmap64( NULL, CMCTR_REGISTERS_SIZE, PROT_READ | PROT_WRITE | PROT_NOCACHE, MAP_PHYS, NOFD, CMCTR_REGISTERS_BASE );
if ( vpout->cmctr_registers == MAP_FAILED || vpout->cmctr_registers == NULL )
{
disp_printf( adapter, "[vpoutfb] Fatal: can't mmap CMCTR registers" );
goto fail2;
}
/* Check PLLs */
if ( (*CMCTR_MMIO32( SEL_CPLL ) & SEL_CPLL_LOCK) || ((*CMCTR_MMIO32( SEL_CPLL ) & SEL_CPLL_SEL) == 0) )
disp_printf( adapter, "[vpoutfb] CPLL frequency: %d MHz", ((*CMCTR_MMIO32( SEL_CPLL ) & SEL_CPLL_SEL) + 1) * VPOUT_XTI_FREQUENCY );
else {
disp_printf( adapter, "[vpoutfb] Fatal: CPLL disabled" );
goto fail4;
}
if ( (*CMCTR_MMIO32( SEL_SPLL ) & SEL_SPLL_LOCK) || ((*CMCTR_MMIO32( SEL_SPLL ) & SEL_SPLL_SEL) == 0) )
disp_printf( adapter, "[vpoutfb] SPLL frequency: %d MHz (288 MHz expected)", ((*CMCTR_MMIO32( SEL_SPLL ) & SEL_SPLL_SEL) + 1) * VPOUT_XTI_FREQUENCY );
else {
disp_printf( adapter, "[vpoutfb] Fatal: SPLL disabled" );
goto fail4;
}
for ( i = 0; i < vpout->hdmi_count; i++ )
{
if ( (strcmp( vpout->hdmi[i].transmitter, VPOUT_OPT_HDMI_IT66121 ) == 0) && gpio_registers == NULL )
{
gpio_registers = (uint8_t *)mmap64( NULL, GPIO_REGISTERS_SIZE, PROT_READ | PROT_WRITE | PROT_NOCACHE, MAP_PHYS, NOFD,
vpout->hdmi[i].device.it66121.base );
if ( gpio_registers == MAP_FAILED || gpio_registers == NULL )
{
disp_printf( adapter, "[vpoutfb] Fatal: can't mmap GPIO registers" );
goto fail4;
}
vpout->hdmi[i].device.it66121.registers = gpio_registers;
}
}
adapter->adapter_ram = 0;
adapter->caps = DISP_CAP_NO_IO_PRIVITY;
/* Setup ISR */
if ( vpout_isr_setup( adapter, vpout, vpout_draw ) == -1 )
{
disp_printf( adapter, "[vpoutfb] Error: can't attach interrupt handler [switching to vsync polling]" );
vpout->irq_polling = 1;
}
return VPOUT_GPU_PIPES;
fail4:
munmap( vpout->cmctr_registers, CMCTR_REGISTERS_SIZE );
fail2:
munmap( vpout_draw->registers, vpout->registers_size );
fail1:
free( vpout_draw );
fail:
if ( vpout->context_allocated )
free( vpout );
disp_unregister_adapter( adapter );
return (-1);
}
void vpout_fini( disp_adapter_t *adapter )
{
vpout_context_t *vpout = adapter->ms_ctx;
vpout_draw_context_t *vpout_draw = adapter->gd_ctx;
int i = 0;
/* Done if vpout_init failed */
if ( adapter->gd_ctx == NULL )
return;
/* Disable hardware */
vpout_hw_disable( vpout, vpout_draw );
/* Cleanup ISR */
vpout_isr_cleanup( vpout, vpout_draw );
/* Free mmapings */
for ( i = 0; i < vpout->hdmi_count; i++ )
if ( vpout->hdmi[i].device.it66121.registers )
{
munmap( vpout->hdmi[i].device.it66121.registers, GPIO_REGISTERS_SIZE );
break;
}
munmap( vpout->cmctr_registers, CMCTR_REGISTERS_SIZE );
munmap( vpout->registers, vpout->registers_size );
/* Free draw-context */
free( vpout_draw );
adapter->gd_ctx = NULL;
/* Free GPU context */
if ( vpout->context_allocated )
free( vpout );
adapter->ms_ctx = NULL;
disp_unregister_adapter( adapter );
}