208 строки
4.7 KiB
C
Исполняемый файл

/*
* (c) 2024, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#include <stdbool.h>
#include <stddef.h>
#include <sunxi.h>
#include <hw/sun8iw7-platform.h>
/*************************************************/
/* MISC FUNCTIONS */
/*************************************************/
static uint16_t sunxi_get_sram_id(uintptr_t addr)
{
uint16_t id;
/* Unlock sram info reg, read it, relock */
regmap_update_bits(addr, 0, (1 << 15), (1 << 15));
id = in32(addr) >> 16;
regmap_update_bits(addr, 0, (1 << 15), (0 << 15));
return id;
}
static int sunxi_identification(sunxi_plat_t *dev)
{
uint16_t get_id = sunxi_get_sram_id(dev->sys_base);
int support = (EOK);
switch (get_id)
{
case sun8iw7: dev->func = sun8iw7_get_plat_func(); strcpy(dev->soc_version, "8IW7"); break;
case sun8iw1:
case sun8iw2:
case sun8iw3:
case sun8iw5:
case sun8iw6:
case sun8iw8:
case sun8iw10:
case sun8iw11:
case sun8iw12:
case sun8iw15:
case sun8iw16:
case sun8iw17:
default:
support = (ENOTSUP);
break;
}
return support;
}
void regmap_update_bits(uintptr_t addr, uint32_t offset, uint32_t mask, uint32_t value)
{
uint32_t orig;
orig = in32(addr + offset);
orig &= ~mask;
out32(addr + offset, orig | (value & mask));
}
int check_valid_id_clk(plat_func_t func, enum sunxi_clk_index cfg_id, int *shift)
{
int res = (EOK);
if (cfg_id >= CCU_CLK_MAX)
{
errno = res = EINVAL;
perror("Invalid CCU index");
}
res = func.convert_clk_index(cfg_id, shift);
if (res != EOK)
{
errno = res;
perror("Not supported CLK on this version SoC");
}
return (res);
}
int check_valid_id_rst(plat_func_t func, enum sunxi_clk_index cfg_id)
{
int shift = 0;
return (check_valid_id_clk(func, cfg_id, &shift));
}
int check_valid_id_pll(plat_func_t func, enum sunxi_pll_clocks cfg_id, int *shift)
{
int res = (EOK);
if (cfg_id >= CCU_PLL_MAX)
{
errno = res = EINVAL;
perror("Invalid PLL index");
}
res = func.convert_pll_index(cfg_id, shift);
if (res != EOK)
{
errno = res;
perror("Not supported PLL on this version SoC");
}
return (res);
}
int check_valid_id_clock_parent(plat_func_t func, enum sunxi_clk_parent cfg_id)
{
int res = (EOK);
if (cfg_id >= CLK_PARENT_MAX)
{
errno = res = EINVAL;
perror("Invalid CLK Parent index");
}
res = func.check_clk_parent_index(cfg_id);
if (res != EOK)
{
errno = res;
perror("Not supported CLK Parent on this version SoC");
}
return (res);
}
/*************************************************/
/* MAIN FUNCTIONS */
/*************************************************/
plat_ctrl_funcs_t plat_ctrl_drv_entry = {
sizeof(plat_ctrl_funcs_t),
sunxi_init, /* init() */
sunxi_fini, /* fini() */
sunxi_drvinfo, /* drvinfo() */
NULL, /* set_pd() */
sunxi_set_reset, /* set_reset() */
sunxi_set_clk, /* set_clk() */
sunxi_get_clk, /* get_clk() */
};
void* sunxi_init(void *hdl, char *options)
{
sunxi_plat_t *dev;
ThreadCtl(_NTO_TCTL_IO_PRIV, NULL);
dev = calloc(1, sizeof(sunxi_plat_t));
if (dev == NULL)
{
return NULL;
}
dev->ccu_base = mmap_device_io(SUNXI_CCU_SIZE, SUNXI_CCU_BASE);
if (dev->ccu_base == (uintptr_t)MAP_FAILED)
{
perror("Unable to mmap CCU area: ");
goto fail;
}
dev->sys_base = mmap_device_io(SUNXI_SYS_CTL_VER_SIZE, (SUNXI_SYS_CTL_BASE + SUNXI_SYS_CTL_VER_REG));
if (dev->sys_base == (uintptr_t)MAP_FAILED)
{
perror("Unable to mmap SYS area: ");
goto fail1;
}
if (sunxi_identification(dev) == ENOTSUP)
{
perror("Not supported SoC version: ");
goto fail2;
}
dev->plat.hdl = hdl;
return (dev);
fail2:
munmap_device_io(dev->sys_base, SUNXI_SYS_CTL_VER_SIZE);
fail1:
munmap_device_io(dev->ccu_base, SUNXI_CCU_SIZE);
fail:
free(dev);
return (NULL);
}
void sunxi_fini(void *hdl)
{
sunxi_plat_t *dev = hdl;
munmap_device_io(dev->ccu_base, SUNXI_CCU_SIZE);
free(hdl);
}
int sunxi_drvinfo(void *hdl, plat_ctrl_drvinfo_t *info)
{
sunxi_plat_t *dev = hdl;
info->version = (PLAT_CTRL_VERSION_MAJOR << PLAT_CTRL_VERMAJOR_SHIFT) |
(PLAT_CTRL_VERSION_MINOR << PLAT_CTRL_VERMINOR_SHIFT) |
(PLAT_CTRL_REVISION << PLAT_CTRL_VERREV_SHIFT);
sprintf(info->name, "%s%s", "SUN", dev->soc_version);
return (EOK);
}