/* * (c) 2024, SWD Embedded Systems Limited, http://www.kpda.ru */ #include #include #include #include /*************************************************/ /* 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); }