208 строки
4.7 KiB
C
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);
|
||
|
}
|