Драйвер devp-sunxi.so для ЗОСРВ Нейтрино редакции 2024

Этот коммит содержится в:
Коммит 30073b5705
17 изменённых файлов: 2273 добавлений и 0 удалений

2
Makefile Исполняемый файл
Просмотреть файл

@ -0,0 +1,2 @@
LIST=hardware
include recurse.mk

66
README.md Обычный файл
Просмотреть файл

@ -0,0 +1,66 @@
## Общая структура
```
┌───────────────────────────┐
│ │
│ Clock / Reset / Power │
│ Контроллеры │
│ │
└─────────────▴─────────────┘
┌─────────────┴─────────────┐
│ │
│ Драйвер (devp-*) │
│ │
└─────────────▴─────────────┘
┌─────────────┴─────────────┐
│ │
│ Менеджер platform-control │
│ │
└─────────────▴─────────────┘
┌─────────────┴─────────────┐
│ │
│ Клиентское приложение │
│ │
└───────────────────────────┘
```
Подробнее см. в статье [Подсистема управления общими блоками SoC для ЗОСРВ «Нейтрино»](https://habr.com/ru/companies/swd_es/articles/837776/).
## Дерево исходных кодов
```
|- devp/
| |- sunxi/ - Исходный код драйвера управления общими элементами для платформ на базе процессоров Allwinner
| | |- Makefile - Правила сборки дерева исходников
| | `- common.mk - Параметры сборки драйверов
| |
| `- Makefile - Правила сборки дерева исходников
|
`- Makefile - Правила сборки дерева исходников
```
## Сборка драйвера
- Установить и настроить [комплект разработчика](https://help.kpda.ru/neutrino/2024/help/topic/ru.kpda.doc.dev_tools_ru/html/devkit/devkit.html) для [ЗОСРВ "Нейтрино" редакции 2024](https://help.kpda.ru/neutrino/2024/help/index.jsp).
- Выполнить команду:
```
make
```
**Обратите внимание, что заявлена поддержка, начиная с ЗОСРВ «Нейтрино» редакции 2024.**
## Запуск драйвера
```
platform-control -dsunxi &
```

2
devp/Makefile Исполняемый файл
Просмотреть файл

@ -0,0 +1,2 @@
LIST=hardware
include recurse.mk

9
devp/sunxi/Makefile Исполняемый файл
Просмотреть файл

@ -0,0 +1,9 @@
LIST=CPU
ifndef QRECURSE
QRECURSE=recurse.mk
ifdef QCONFIG
QRDIR=$(dir $(QCONFIG))
endif
endif
include $(QRDIR)$(QRECURSE)

8
devp/sunxi/arm/Makefile Исполняемый файл
Просмотреть файл

@ -0,0 +1,8 @@
LIST=VARIANT
ifndef QRECURSE
QRECURSE=recurse.mk
ifdef QCONFIG
QRDIR=$(dir $(QCONFIG))
endif
endif
include $(QRDIR)$(QRECURSE)

1
devp/sunxi/arm/dll.le.v7/Makefile Исполняемый файл
Просмотреть файл

@ -0,0 +1 @@
include ../../common.mk

603
devp/sunxi/clock.c Обычный файл
Просмотреть файл

@ -0,0 +1,603 @@
/*
* (c) 2024, SWD Embedded Systems Limited, http://www.kpda.ru
*/
/*
* SUNXI Clock Controller
*/
#include <sunxi.h>
#include <clock.h>
/*************************************************/
/* MISC FUNCTIONS */
/*************************************************/
static uint32_t ipow2_to_exp(uint32_t exp)
{
uint32_t base = 2;
uint32_t result = 1;
for (;;)
{
if (exp & 1)
{
result *= base;
}
exp >>= 1;
if (!exp)
{
break;
}
base *= base;
}
return result;
}
static uint32_t calculate_pll_output(uint8_t n, uint8_t k, uint8_t m, uint8_t p)
{
/* optimizing the equation so that there is no overflow */
return ((n * k) * (OSC24M / (m * p))); // Hz
}
/* CLK gate operation */
static int clock_enable(sunxi_plat_t *dev, plat_ctrl_clk_cfg_t *cfg, int shift)
{
uint8_t bus_rst_id = 0xFF, bus_gat_id = 0xFF;
uint8_t shift_bus_rst = ENOTSUP,
shift_bus_gat = ENOTSUP;
uint32_t value,
rst_value = 0,
gat_value = 0;
/* get struct bus_gating/sft_rst/clk_parent_map */
shift_bus_rst = dev->func.get_struct_bus_rst(cfg->id, &bus_rst_id);
shift_bus_gat = dev->func.get_struct_bus_gat(cfg->id, &bus_gat_id);
if ((shift_bus_rst == ENOTSUP) ||
(shift_bus_gat == ENOTSUP))
{
return (-ENOTSUP);
}
if (cfg->state == PLAT_CTRL_CLK_STATE_ENABLED)
{
rst_value = (1 << shift_bus_rst);
gat_value = (1 << shift_bus_gat);
value = CLK_ON_MASK;
}
else
{
value = ~CLK_ON_MASK;
}
/* Reset De-assert/Assert */
if (shift_bus_rst != (-ENOTSUP))
{
regmap_update_bits(dev->ccu_base, SUNXI_BUS_SFT_RST_OFFSET(bus_rst_id), (1 << shift_bus_rst), rst_value);
delay(10);
}
/* Gating Pass/Mask */
if (shift_bus_gat != (-ENOTSUP))
{
regmap_update_bits(dev->ccu_base, SUNXI_BUS_CLK_GATING_OFFSET(bus_gat_id), (1 << shift_bus_gat), gat_value);
delay(10);
}
/* CLK on/off */
if (shift != (-ENOTSUP))
{
regmap_update_bits(dev->ccu_base, SUNXI_CCU_CLK_OFFSET(shift), CLK_ON_MASK, value);
delay(10);
}
return (EOK);
}
static int16_t get_coef(uint32_t value, int8_t shift, uint32_t mask)
{
return ((shift != CLK_NO_DIV_RATIO ) ? (((value & mask) >> shift)): 0);
}
static int32_t set_coef(uint32_t value, int8_t shift, uint32_t mask)
{
return ((shift != CLK_NO_DIV_RATIO ) ? (((value << shift) & mask)): 0);
}
/* max can return 4.2GHz */
static int read_rate_pll(uintptr_t ccu_base, uint32_t *rate, enum sunxi_pll_clocks id, int shift)
{
int16_t n = 1, m = 1, k = 1, p = 1;
struct pll_map *pll_map = NULL;
pll_map = get_pll_map(id);
if (pll_map == NULL)
{
/* No such device or address */
*rate = 0;
return (ENXIO);
}
uint32_t value = in32(ccu_base + SUNXI_PLL_CTRL_OFFSET(shift));
p = get_coef(value, pll_map->div_p_shift, pll_map->div_p_mask);
if (id == PLL_CPU0_CTRL || id == PLL_CPU1_CTRL)
{
p = ipow2_to_exp(p);
}
else
{
p += 1;
}
n = get_coef(value, pll_map->div_n_shift, pll_map->div_n_mask) + 1;
k = get_coef(value, pll_map->div_k_shift, pll_map->div_k_mask) + 1;
m = get_coef(value, pll_map->div_m_shift, pll_map->div_m_mask) + 1;
*rate = calculate_pll_output(n, k, m, p); // Hz
return (EOK);
}
static uint32_t read_rate_clk(sunxi_plat_t *dev, uint32_t *rate, enum sunxi_clk_index id, int shift)
{
uint32_t value = 0;
uint32_t reg_val_clk_parent;
int x, i;
uint32_t freq_pll;
uint8_t n, m;
int pll_shift;
enum sunxi_pll_clocks pll_id;
struct clk_parent_map *clk_parent_map = NULL;
clk_parent_map = get_clk_parent_map(id);
if (clk_parent_map == NULL)
{
return (ENOTSUP);
}
/* read clk_ctrl */
value = in32(dev->ccu_base + SUNXI_CCU_CLK_OFFSET(shift));
/* getting bits installed clk_parent */
reg_val_clk_parent = ((value & CLK_PARENT_MASK) >> clk_parent_map->parent_shift_bits);
/* search enum sunxi_clk_parent */
for(i = 0; i < ARRAY_SIZE(clk_parent_map->clk_parents); i++)
{
if (reg_val_clk_parent == i)
{
break;
}
}
if (i == ARRAY_SIZE(clk_parent_map->clk_parents))
{
return (ENOTSUP);
}
/* converting to a sunxi_pll_clocks */
x = dev->func.covert_clk_parent_to_pll_ctrl(clk_parent_map->clk_parents[i], &pll_id);
if(pll_id != OSC24M)
{
dev->func.convert_pll_index(pll_id, &pll_shift);
read_rate_pll(dev->ccu_base, &freq_pll, pll_id, pll_shift);
}
else
{
freq_pll = pll_id;
}
if (x > 0)
{
freq_pll *= x;
}
else if (x < 0)
{
freq_pll /= abs(x);
}
n = ipow2_to_exp(get_coef(value, clk_parent_map->div_n_shift, clk_parent_map->div_n_mask));
m = get_coef(value, clk_parent_map->div_m_shift, clk_parent_map->div_m_mask) + 1;
*rate = (freq_pll / (n * m));
return (EOK);
}
static int set_clock_rate(sunxi_plat_t *dev, plat_ctrl_clk_cfg_t *cfg, int shift)
{
uint32_t value = 0, mask = 0;
uint32_t reg_val_clk_parent;
int x, i;
int pll_shift;
uint32_t freq_pll;
uint8_t n, m;
uint8_t max_n = 1,
max_m = 1;
uint8_t best_n = 0,
best_m = 0;
enum sunxi_pll_clocks pll_id;
struct clk_parent_map *clk_parent_map = NULL;
clk_parent_map = get_clk_parent_map(cfg->id);
if (clk_parent_map == NULL)
{
return (-ENOTSUP);
}
/* read clk_ctrl */
value = in32(dev->ccu_base + SUNXI_CCU_CLK_OFFSET(shift));
/* getting bits installed clk_parent */
reg_val_clk_parent = ((value & CLK_PARENT_MASK) >> clk_parent_map->parent_shift_bits);
/* search enum sunxi_clk_parent */
for(i = 0; i < ARRAY_SIZE(clk_parent_map->clk_parents); i++)
{
if (reg_val_clk_parent == i)
{
break;
}
}
if (i == ARRAY_SIZE(clk_parent_map->clk_parents))
{
return (-ENOTSUP);
}
/* converting to a sunxi_pll_clocks */
x = dev->func.covert_clk_parent_to_pll_ctrl(clk_parent_map->clk_parents[i], &pll_id);
if (pll_id != OSC24M)
{
dev->func.convert_pll_index(pll_id, &pll_shift);
read_rate_pll(dev->ccu_base, &freq_pll, pll_id, pll_shift);
}
else
{
freq_pll = pll_id;
}
if (x > 0)
{
freq_pll *= x;
}
else if (x < 0)
{
freq_pll /= abs(x);
}
/* Calcilate freq */
uint64_t best_diff = cfg->rate;
if (clk_parent_map->div_n_shift != CLK_NO_DIV_RATIO)
{
max_n = (clk_parent_map->div_n_mask >> clk_parent_map->div_n_shift);
}
if (clk_parent_map->div_m_shift != CLK_NO_DIV_RATIO)
{
max_m = (clk_parent_map->div_m_mask >> clk_parent_map->div_m_shift) + 1;
}
for (n = 0; n <= max_n; n++)
{
for (m = 1; m <= max_m; m++)
{
/* body */
uint64_t clk_output = freq_pll / (ipow2_to_exp(n) * m);
uint64_t diff = abs(cfg->rate - clk_output);
if (diff < best_diff)
{
best_diff = diff;
best_n = n;
best_m = m;
}
}
}
value = set_coef(best_n, clk_parent_map->div_n_shift, clk_parent_map->div_n_mask);
value |= set_coef(SUNXI_MASK_DIV(best_m), clk_parent_map->div_m_shift, clk_parent_map->div_m_mask);
mask = (clk_parent_map->div_m_mask | clk_parent_map->div_n_mask);
/* Set DIV_N and DIV_M */
regmap_update_bits(dev->ccu_base, SUNXI_CCU_CLK_OFFSET(shift), mask, value);
return (EOK);
}
/*
* PLL Applications: use the available clock sources to generate clock roots to various parts of the chip. In practical
* application, other PLLs doesnt support dynamic frequency scaling except for PLL_CPUX and PLL_DDRX.
*/
static int set_pll_rate(uintptr_t ccu_base, uint32_t rate, enum sunxi_pll_clocks id, int shift)
{
uint32_t value, mask;
uint8_t best_n = 0,
best_m = 0,
best_k = 0,
best_p = 0;
uint8_t n, m, k, p;
uint8_t max_n = 1,
max_m = 1,
max_k = 1,
max_p = 1;
uint8_t timeout = 10;
uint8_t pow_p = 0;
struct pll_map *pll_map = NULL;
pll_map = get_pll_map(id);
if (pll_map == NULL)
{
/* No such device or address */
return (ENXIO);
}
/*
* The P factor only use in the condition that PLL output less than 288 MHz.
*/
if (rate <= 288000000 && pll_map->div_p_shift != CLK_NO_DIV_RATIO)
{
max_p = (pll_map->div_p_mask >> pll_map->div_p_shift) + 1;
if (id == PLL_CPU0_CTRL || id == PLL_CPU1_CTRL)
{
pow_p = 1;
}
}
if (pll_map->div_n_shift != CLK_NO_DIV_RATIO)
{
max_n = (pll_map->div_n_mask >> pll_map->div_n_shift) + 1;
}
if (pll_map->div_k_shift != CLK_NO_DIV_RATIO)
{
max_k = (pll_map->div_k_mask >> pll_map->div_k_shift) + 1;
}
if (pll_map->div_m_shift != CLK_NO_DIV_RATIO)
{
max_m = (pll_map->div_m_mask >> pll_map->div_m_shift) + 1;
}
/* Calcilate freq */
uint32_t best_diff = rate;
for (p = 1; p <= max_p; ++p)
{
for (n = 1; n <= max_n; ++n)
{
for (k = 1; k <= max_k; ++k)
{
for (m = 1; m <= max_m; ++m)
{
/* body */
uint32_t pll_output = calculate_pll_output(n, k, m, (pow_p ? ipow2_to_exp(SUNXI_MASK_DIV(p)): p));
uint32_t diff = rate - pll_output;
if (diff < best_diff)
{
best_diff = diff;
best_p = p;
best_n = n;
best_k = k;
best_m = m;
}
}
}
}
}
if (id == PLL_CPU0_CTRL || id == PLL_CPU1_CTRL)
{
// TODO for A83t
/* Switch to 24MHz clock while changing PLL1 */
regmap_update_bits(ccu_base, SUNXI_PLL_CTRL_OFFSET(0x14), (0x3 << 16), (0x1 << 16));
delay(8);
}
else
{
/* PLL off */
regmap_update_bits(ccu_base, SUNXI_PLL_CTRL_OFFSET(shift), CLK_ON_MASK | PLL_LOCK_ON, ~CLK_ON_MASK | ~PLL_LOCK_ON);
}
/* Set new coef */
value = 0;
mask = 0;
if (pll_map->div_p_shift != CLK_NO_DIV_RATIO)
{
value |= SUNXI_MASK_DIV(best_p) << pll_map->div_p_shift;
mask |= pll_map->div_p_mask;
}
value |= SUNXI_MASK_DIV(best_n) << pll_map->div_n_shift;
mask |= pll_map->div_n_mask;
if (pll_map->div_k_shift != CLK_NO_DIV_RATIO)
{
value |= SUNXI_MASK_DIV(best_k) << pll_map->div_k_shift;
mask |= pll_map->div_k_mask;
}
value |= SUNXI_MASK_DIV(best_m) << pll_map->div_m_shift;
mask |= pll_map->div_m_mask;
regmap_update_bits(ccu_base, SUNXI_PLL_CTRL_OFFSET(shift), mask, value);
if (id != PLL_CPU0_CTRL || id != PLL_CPU1_CTRL)
{
/* PLL on */
regmap_update_bits(ccu_base, SUNXI_PLL_CTRL_OFFSET(shift), (CLK_ON_MASK | PLL_MODE_SEL_INTEGER), (CLK_ON_MASK | PLL_MODE_SEL_INTEGER));
}
/* Check LOCK */
while (!(in32(ccu_base + SUNXI_PLL_CTRL_OFFSET(shift)) & PLL_LOCK_ON))
{
timeout--;
if (!timeout)
{
return (ETIMEDOUT);
}
delay(10);
}
if (id == PLL_CPU0_CTRL || id == PLL_CPU1_CTRL)
{
// TODO for A83t
regmap_update_bits(ccu_base, SUNXI_PLL_CTRL_OFFSET(0x14), (0x3 << 16), (0x3 << 16));
delay(8);
}
return (EOK);
}
static int set_clock_parent(sunxi_plat_t *dev, plat_ctrl_clk_cfg_t *cfg, int shift)
{
struct clk_parent_map *clk_parent_map;
int i;
clk_parent_map = get_clk_parent_map(cfg->id);
if (clk_parent_map == NULL)
{
return (ENOTSUP);
}
for(i = 0; i < ARRAY_SIZE(clk_parent_map->clk_parents); i++)
{
if (cfg->parent == clk_parent_map->clk_parents[i])
{
break;
}
}
if (i == ARRAY_SIZE(clk_parent_map->clk_parents))
{
return (ENOTSUP);
}
regmap_update_bits(dev->ccu_base, SUNXI_CCU_CLK_OFFSET(shift),
clk_parent_map->parent_mask_bits, i << clk_parent_map->parent_shift_bits);
return (EOK);
}
/*************************************************/
/* MAIN FUNCTIONS */
/*************************************************/
int sunxi_set_clk(void *hdl, plat_ctrl_clk_cfg_t *cfg)
{
sunxi_plat_t *dev = hdl;
int shift;
int res = (EOK);
switch (cfg->state)
{
case PLAT_CTRL_CLK_STATE_ENABLED:
case PLAT_CTRL_CLK_STATE_DISABLED:
{
res = check_valid_id_clk(dev->func, cfg->id, &shift);
if (res == EOK)
{
clock_enable(dev, cfg, shift);
}
break;
}
case PLAT_CTRL_CLK_STATE_SET_RATE:
{
res = check_valid_id_clk(dev->func, cfg->id, &shift);
if (res == EOK)
{
res = set_clock_rate(dev, cfg, shift);
}
break;
}
case PLAT_CTRL_PLL_STATE_SET_RATE:
{
res = check_valid_id_pll(dev->func, cfg->id, &shift);
if (res == EOK)
{
res = set_pll_rate(dev->ccu_base, cfg->rate, cfg->id, shift);
}
break;
}
case PLAT_CTRL_CLK_STATE_SET_PARENT:
{
res = check_valid_id_clk(dev->func, cfg->id, &shift);
if (res == EOK)
{
res = check_valid_id_clock_parent(dev->func, cfg->parent);
if (res == EOK)
{
res = set_clock_parent(dev, cfg, shift);
}
}
break;
}
default:
{
perror("Not supported CLK config state");
return (ENOTSUP);
}
}
return (res);
}
int sunxi_get_clk(void *hdl, plat_ctrl_clk_cfg_t *cfg)
{
sunxi_plat_t *dev = hdl;
int shift;
int res = (EOK);
switch (cfg->state)
{
case PLAT_CTRL_CLK_STATE_GET_RATE:
{
res = check_valid_id_clk(dev->func, cfg->id, &shift);
if (res == EOK)
{
res = read_rate_clk(dev, &cfg->rate, cfg->id, shift);
}
break;
}
case PLAT_CTRL_PLL_STATE_GET_RATE:
{
res = check_valid_id_pll(dev->func, cfg->id, &shift);
if (res == EOK)
{
res = read_rate_pll(dev->ccu_base, &cfg->rate, cfg->id, shift);
}
break;
}
default:
{
perror("Not supported CLK config state");
return (ENOTSUP);
}
}
return (res);
}

70
devp/sunxi/clock.h Обычный файл
Просмотреть файл

@ -0,0 +1,70 @@
/*
* (c) 2024, SWD Embedded Systems Limited, http://www.kpda.ru
*/
/*
* SUNXI Clock Controller
*/
#ifndef _CLOCK_H_INCLUDED_
#define _CLOCK_H_INCLUDED_
#include <hw/sunxi-platform.h>
#define OSC24M 24000000 // Hz
#define CLK_ON_MASK (1 << 31)
#define PLL_LOCK_ON (1 << 28)
#define PLL_MODE_SEL_INTEGER (1 << 24)
#define PLL_FACTOR_P_SHIFT 16
#define PLL_FACTOR_P_MASK (0x0F << PLL_FACTOR_P_SHIFT)
#define PLL_FACTOR_N_SHIFT 8
#define PLL_FACTOR_N_MASK (0x7F << PLL_FACTOR_N_SHIFT)
#define PLL_FACTOR_K_SHIFT 4
#define PLL_FACTOR_K_MASK (0x03 << PLL_FACTOR_K_SHIFT)
#define PLL_FACTOR_M_SHIFT 0
#define PLL_FACTOR_M_MASK (0x1F << PLL_FACTOR_M_SHIFT)
#define CLK_NO_DIV_RATIO -1
#define CLK_DIV_RATIO_N_MASK(x) (0x03 << x)
#define CLK_DIV_RATIO_M_MASK(x) (0x07 << x)
#define CLK_PARENT_SHIFT 24
#define CLK_PARENT_MASK (0x07 << CLK_PARENT_SHIFT)
#define UNKNOWN_BIT -1
#define SIZE_REG 32
#define CNT_BUS_CLK_GATING 5
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
struct clk_parent_map {
enum sunxi_clk_index entry;
uint8_t parent_shift_bits;
uint32_t parent_mask_bits;
int8_t div_n_shift;
uint32_t div_n_mask;
int8_t div_m_shift;
uint32_t div_m_mask;
uint8_t clk_parents[8];
};
struct pll_map {
enum sunxi_pll_clocks entry;
int8_t div_p_shift; uint32_t div_p_mask;
int8_t div_n_shift; uint32_t div_n_mask;
int8_t div_k_shift; uint32_t div_k_mask;
int8_t div_m_shift; uint32_t div_m_mask;
};
struct clk_parent_map* get_clk_parent_map(enum sunxi_clk_index clk_id);
struct pll_map* get_pll_map(enum sunxi_pll_clocks pll_id);
#endif /* _CLOCK_H_INCLUDED_ */

678
devp/sunxi/clock_map.c Обычный файл
Просмотреть файл

@ -0,0 +1,678 @@
/*
* (c) 2024, SWD Embedded Systems Limited, http://www.kpda.ru
*/
/*
* SUNXI Clock Controller common
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <hw/inout.h>
#include <clock.h>
/*
* Add in the format:
* X_CLK, shift_bits, mask_parent,
* {PLL1_*, PLL2_*, PLL3_*, PLL4_*, etc},
* shift_div_n, shift_div_m
*
* PLL1_* = 00
* PLL2_* = 01
* PLL3_* = 10
*
* etc...
*/
static struct clk_parent_map parent_array[] = {
{
.entry = THS_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = 0,
.div_n_mask = 0x3,
.div_m_shift = CLK_NO_DIV_RATIO,
.div_m_mask = 0x01,
.clk_parents = {OSC_24M},
},
{
.entry = NAND0_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = 16,
.div_n_mask = 0x3 << 16,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {OSC_24M, PLL_PERIPH0, PLL_PERIPH1},
},
{
.entry = NAND1_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = 16,
.div_n_mask = 0x3 << 16,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {OSC_24M, PLL_PERIPH0, PLL_PERIPH1},
},
{
.entry = SDMMC0_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = 16,
.div_n_mask = 0x3 << 16,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {OSC_24M, PLL_PERIPH0_2X, PLL_PERIPH1_2X},
},
{
.entry = SDMMC1_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = 16,
.div_n_mask = 0x3 << 16,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {OSC_24M, PLL_PERIPH0_2X, PLL_PERIPH1_2X},
},
{
.entry = SDMMC2_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = 16,
.div_n_mask = 0x3 << 16,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {OSC_24M, PLL_PERIPH0_2X, PLL_PERIPH1_2X},
},
{
.entry = SDMMC3_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = 16,
.div_n_mask = 0x3 << 16,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {OSC_24M, PLL_PERIPH0_2X, PLL_PERIPH1_2X},
},
{
.entry = TS_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = 16,
.div_n_mask = 0x3 << 16,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {OSC_24M, PLL_PERIPH0}
},
{
.entry = SS_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = 16,
.div_n_mask = 0x3 << 16,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {OSC_24M, PLL_PERIPH0_2X, PLL_PERIPH1_2X},
},
{
.entry = SPI0_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = 16,
.div_n_mask = 0x3 << 16,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {OSC_24M, PLL_PERIPH0, PLL_PERIPH1},
},
{
.entry = SPI1_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = 16,
.div_n_mask = 0x3 << 16,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {OSC_24M, PLL_PERIPH0, PLL_PERIPH1},
},
{
.entry = SPI2_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = 16,
.div_n_mask = 0x3 << 16,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {OSC_24M, PLL_PERIPH0, PLL_PERIPH1},
},
{
.entry = SPI3_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = 16,
.div_n_mask = 0x3 << 16,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {OSC_24M, PLL_PERIPH0, PLL_PERIPH1},
},
{
.entry = I2S0_CLK,
.parent_shift_bits = 16,
.parent_mask_bits = 3 << 16,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_AUDIO_8X, PLL_AUDIO_4X, PLL_AUDIO_2X, PLL_AUDIO},
},
{
.entry = I2S1_CLK,
.parent_shift_bits = 16,
.parent_mask_bits = 3 << 16,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_AUDIO_8X, PLL_AUDIO_4X, PLL_AUDIO_2X, PLL_AUDIO},
},
{
.entry = I2S2_CLK,
.parent_shift_bits = 16,
.parent_mask_bits = 3 << 16,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_AUDIO_8X, PLL_AUDIO_4X, PLL_AUDIO_2X, PLL_AUDIO},
},
{
.entry = TDM_CLK,
.parent_shift_bits = 16,
.parent_mask_bits = 3 << 16,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = CLK_NO_DIV_RATIO,
.div_m_mask = 0x01,
.clk_parents = {PLL_AUDIO_8X, PLL_AUDIO_4X, PLL_AUDIO_2X, PLL_AUDIO},
},
{
.entry = OWA_CLK,
.parent_shift_bits = 16,
.parent_mask_bits = 3 << 16,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_AUDIO_8X, PLL_AUDIO_4X, PLL_AUDIO_2X, PLL_AUDIO},
},
{
.entry = KEYPAD_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = 16,
.div_n_mask = 0x3 << 16,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {OSC_24M, UNKNOWN_BIT/*, LOSC*/},
},
{
.entry = SATA_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = CLK_NO_DIV_RATIO,
.div_m_mask = 0x01,
.clk_parents = {PLL_SATA, UNKNOWN_BIT},
},
{
.entry = CIR0_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = 16,
.div_n_mask = 0x3 << 16,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {OSC_24M, PLL_PERIPH0, PLL_PERIPH1/*, LOSC*/},
},
{
.entry = CIR1_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = 16,
.div_n_mask = 0x3 << 16,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {OSC_24M, PLL_PERIPH0, PLL_PERIPH1/*, LOSC*/},
},
{
.entry = DRAM_CLK,
.parent_shift_bits = 20,
.parent_mask_bits = 3 << 20,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x3,
.clk_parents = {PLL_DDR0, PLL_DDR1},
},
{
.entry = DE_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_PERIPH0_2X, PLL_DE},
},
{
.entry = DE_MP_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_PERIPH0_2X, PLL_DE},
},
{
.entry = LCD0_TCON_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_VIDEO0, PLL_VIDEO1, PLL_VIDEO0_2X, PLL_VIDEO1_2X, PLL_MIPI},
},
{
.entry = LCD1_TCON_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_VIDEO0, PLL_VIDEO1, PLL_VIDEO0_2X, PLL_VIDEO1_2X, PLL_MIPI},
},
{
.entry = TV0_TCON_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_VIDEO0, PLL_VIDEO1, PLL_VIDEO0_2X, PLL_VIDEO1_2X, PLL_MIPI},
},
{
.entry = TV1_TCON_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_VIDEO0, PLL_VIDEO1, PLL_VIDEO0_2X, PLL_VIDEO1_2X, PLL_MIPI},
},
{
.entry = DEINTERLACE_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_PERIPH0, PLL_PERIPH1},
},
{
.entry = CSI_MISC_CLK,
.parent_shift_bits = 8,
.parent_mask_bits = 7 << 8,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = CLK_NO_DIV_RATIO,
.div_m_mask = 0x01,
.clk_parents = {OSC_24M, PLL_VIDEO1, PLL_PERIPH1},
},
{
.entry = CSI0_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 16,
.div_m_mask = 0x0F,
.clk_parents = {PLL_PERIPH0, PLL_PERIPH1},
},
{
.entry = VE_CLK,
.parent_shift_bits = 0,
.parent_mask_bits = 0,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 16,
.div_m_mask = 0x7,
.clk_parents = {PLL_VE},
},
{
.entry = ADDA_CLK,
.parent_shift_bits = 0,
.parent_mask_bits = 0,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = CLK_NO_DIV_RATIO,
.div_m_mask = 0x01,
.clk_parents = {PLL_AUDIO},
},
{
.entry = AVS_CLK,
.parent_shift_bits = 0,
.parent_mask_bits = 0,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = CLK_NO_DIV_RATIO,
.div_m_mask = 0x01,
.clk_parents = {OSC_24M},
},
{
.entry = HDMI0_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_VIDEO0, PLL_VIDEO1},
},
{
.entry = HDMI1_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_VIDEO0, PLL_VIDEO1}, //???
},
{
.entry = HDMI_SLOW_CLK,
.parent_shift_bits = 0,
.parent_mask_bits = 0,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = CLK_NO_DIV_RATIO,
.div_m_mask = 0x01,
.clk_parents = {OSC_24M},
},
{
.entry = MBUS0_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = 16,
.div_n_mask = 0x3 << 16,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {OSC_24M, PLL_PERIPH0_2X, PLL_DDR0},
},
{
.entry = MIPI_DSI_CLK,
.parent_shift_bits = 8,
.parent_mask_bits = 0x3 << 8,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_VIDEO0, PLL_VIDEO1, PLL_PERIPH0},
},
{
.entry = TVE0_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_VIDEO0, PLL_VIDEO1, PLL_VIDEO0_2X, PLL_VIDEO1_2X, PLL_MIPI},
},
{
.entry = TVE1_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_VIDEO0, PLL_VIDEO1, PLL_VIDEO0_2X, PLL_VIDEO1_2X, PLL_MIPI},
},
{
.entry = TVD0_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_VIDEO0, PLL_VIDEO1, PLL_VIDEO0_2X, PLL_VIDEO1_2X},
},
{
.entry = TVD1_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_VIDEO0, PLL_VIDEO1, PLL_VIDEO0_2X, PLL_VIDEO1_2X},
},
{
.entry = TVD2_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_VIDEO0, PLL_VIDEO1, PLL_VIDEO0_2X, PLL_VIDEO1_2X},
},
{
.entry = TVD3_CLK,
.parent_shift_bits = CLK_PARENT_SHIFT,
.parent_mask_bits = CLK_PARENT_MASK,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x0F,
.clk_parents = {PLL_VIDEO0, PLL_VIDEO1, PLL_VIDEO0_2X, PLL_VIDEO1_2X},
},
{
.entry = GPU_CLK,
.parent_shift_bits = 0,
.parent_mask_bits = 0,
.div_n_shift = CLK_NO_DIV_RATIO,
.div_n_mask = 0x01,
.div_m_shift = 0,
.div_m_mask = 0x3,
.clk_parents = {PLL_GPU},
},
};
struct clk_parent_map* get_clk_parent_map(enum sunxi_clk_index clk_id)
{
struct clk_parent_map *p = parent_array;
int i;
for (i = 0; i < ARRAY_SIZE(parent_array); i++, p++)
{
if (clk_id == p->entry)
{
return p;
}
}
return (NULL);
}
static struct pll_map pll_array[] = {
{
.entry = PLL_CPU0_CTRL,
.div_p_shift = PLL_FACTOR_P_SHIFT,
.div_p_mask = 0x03 << PLL_FACTOR_P_SHIFT,
.div_n_shift = PLL_FACTOR_N_SHIFT,
.div_n_mask = 0x1F << PLL_FACTOR_N_SHIFT,
.div_k_shift = PLL_FACTOR_K_SHIFT,
.div_k_mask = PLL_FACTOR_K_MASK,
.div_m_shift = PLL_FACTOR_M_SHIFT,
.div_m_mask = 0x03,
},
{
.entry = PLL_AUDIO_CTRL,
.div_p_shift = PLL_FACTOR_P_SHIFT,
.div_p_mask = PLL_FACTOR_P_MASK,
.div_n_shift = PLL_FACTOR_N_SHIFT,
.div_n_mask = PLL_FACTOR_N_MASK,
.div_k_shift = CLK_NO_DIV_RATIO,
.div_k_mask = 0x01,
.div_m_shift = PLL_FACTOR_M_SHIFT,
.div_m_mask = PLL_FACTOR_M_MASK,
},
{
.entry = PLL_VIDEO0_CTRL,
.div_p_shift = CLK_NO_DIV_RATIO,
.div_p_mask = 0x01,
.div_n_shift = PLL_FACTOR_N_SHIFT,
.div_n_mask = PLL_FACTOR_N_MASK,
.div_k_shift = CLK_NO_DIV_RATIO,
.div_k_mask = 0x01,
.div_m_shift = PLL_FACTOR_M_SHIFT,
.div_m_mask = 0x0F,
},
{
.entry = PLL_VIDEO1_CTRL,
.div_p_shift = CLK_NO_DIV_RATIO,
.div_p_mask = 0x01,
.div_n_shift = PLL_FACTOR_N_SHIFT,
.div_n_mask = PLL_FACTOR_N_MASK,
.div_k_shift = CLK_NO_DIV_RATIO,
.div_k_mask = 0x01,
.div_m_shift = PLL_FACTOR_M_SHIFT,
.div_m_mask = 0x0F,
},
{
.entry = PLL_VE_CTRL,
.div_p_shift = CLK_NO_DIV_RATIO,
.div_p_mask = 0x01,
.div_n_shift = PLL_FACTOR_N_SHIFT,
.div_n_mask = PLL_FACTOR_N_MASK,
.div_k_shift = CLK_NO_DIV_RATIO,
.div_k_mask = 0x01,
.div_m_shift = PLL_FACTOR_M_SHIFT,
.div_m_mask = 0x0F,
},
{
.entry = PLL_DDR0_CTRL,
.div_p_shift = CLK_NO_DIV_RATIO,
.div_p_mask = 0x01,
.div_n_shift = PLL_FACTOR_N_SHIFT,
.div_n_mask = 0x1F << PLL_FACTOR_N_SHIFT,
.div_k_shift = PLL_FACTOR_K_SHIFT,
.div_k_mask = PLL_FACTOR_K_MASK,
.div_m_shift = PLL_FACTOR_M_SHIFT,
.div_m_mask = 0x03,
},
{
.entry = PLL_DDR1_CTRL,
.div_p_shift = CLK_NO_DIV_RATIO,
.div_p_mask = 0x01,
.div_n_shift = PLL_FACTOR_N_SHIFT,
.div_n_mask = 0x1F << PLL_FACTOR_N_SHIFT,
.div_k_shift = PLL_FACTOR_K_SHIFT,
.div_k_mask = PLL_FACTOR_K_MASK,
.div_m_shift = PLL_FACTOR_M_SHIFT,
.div_m_mask = 0x03,
},
{
.entry = PLL_PERIPH0_CTRL,
.div_p_shift = PLL_FACTOR_P_SHIFT,
.div_p_mask = 0x03 << PLL_FACTOR_P_SHIFT,
.div_n_shift = PLL_FACTOR_N_SHIFT,
.div_n_mask = 0x1F << PLL_FACTOR_N_SHIFT,
.div_k_shift = PLL_FACTOR_K_SHIFT,
.div_k_mask = PLL_FACTOR_K_MASK,
.div_m_shift = PLL_FACTOR_M_SHIFT,
.div_m_mask = 0x03,
},
{
.entry = PLL_PERIPH1_CTRL,
.div_p_shift = PLL_FACTOR_P_SHIFT,
.div_p_mask = 0x03 << PLL_FACTOR_P_SHIFT,
.div_n_shift = PLL_FACTOR_N_SHIFT,
.div_n_mask = 0x1F << PLL_FACTOR_N_SHIFT,
.div_k_shift = PLL_FACTOR_K_SHIFT,
.div_k_mask = PLL_FACTOR_K_MASK,
.div_m_shift = PLL_FACTOR_M_SHIFT,
.div_m_mask = 0x03,
},
{
.entry = PLL_GPU_CTRL,
.div_p_shift = CLK_NO_DIV_RATIO,
.div_p_mask = 0x01,
.div_n_shift = PLL_FACTOR_N_SHIFT,
.div_n_mask = PLL_FACTOR_N_MASK,
.div_k_shift = CLK_NO_DIV_RATIO,
.div_k_mask = 0x01,
.div_m_shift = PLL_FACTOR_M_SHIFT,
.div_m_mask = 0x0F,
},
{
.entry = PLL_DE_CTRL,
.div_p_shift = CLK_NO_DIV_RATIO,
.div_p_mask = 0x01,
.div_n_shift = PLL_FACTOR_N_SHIFT,
.div_n_mask = PLL_FACTOR_N_MASK,
.div_k_shift = CLK_NO_DIV_RATIO,
.div_k_mask = 0x01,
.div_m_shift = PLL_FACTOR_M_SHIFT,
.div_m_mask = 0x0F,
},
{
.entry = PLL_SATA_CTRL,
.div_p_shift = CLK_NO_DIV_RATIO,
.div_p_mask = 0x01,
.div_n_shift = PLL_FACTOR_N_SHIFT,
.div_n_mask = 0x1F << PLL_FACTOR_N_SHIFT,
.div_k_shift = PLL_FACTOR_K_SHIFT,
.div_k_mask = PLL_FACTOR_K_MASK,
.div_m_shift = PLL_FACTOR_M_SHIFT,
.div_m_mask = 0x03,
},
{
.entry = PLL_MIPI_CTRL,
.div_p_shift = CLK_NO_DIV_RATIO,
.div_p_mask = 0x01,
.div_n_shift = PLL_FACTOR_N_SHIFT,
.div_n_mask = 0x0F << PLL_FACTOR_N_SHIFT,
.div_k_shift = PLL_FACTOR_K_SHIFT,
.div_k_mask = PLL_FACTOR_K_MASK,
.div_m_shift = PLL_FACTOR_M_SHIFT,
.div_m_mask = 0x0F,
},
};
struct pll_map* get_pll_map(enum sunxi_pll_clocks pll_id)
{
struct pll_map *p = pll_array;
int i;
for (i = 0; i < ARRAY_SIZE(pll_array); i++, p++)
{
if (pll_id == p->entry)
{
return p;
}
}
return (NULL);
}

23
devp/sunxi/common.mk Исполняемый файл
Просмотреть файл

@ -0,0 +1,23 @@
ifndef QCONFIG
QCONFIG=qconfig.mk
endif
include $(QCONFIG)
include $(MKFILES_ROOT)/qmacros.mk
NAME := devp-sunxi
USEFILE=$(PROJECT_ROOT)/$(NAME).use
EXTRA_SILENT_VARIANTS+=$(SECTION)
EXTRA_INCVPATH+=$(PROJECT_ROOT)/private
define PINFO
PINFO DESCRIPTION = SUNXI Platform Related Blocks driver
endef
include $(PROJECT_ROOT)/pinfo.mk
LDVFLAG_dll= -L.
LIBS += drvrS
include $(MKFILES_ROOT)/qtargets.mk
-include $(PROJECT_ROOT)/roots.mk

7
devp/sunxi/devp-sunxi.use Исполняемый файл
Просмотреть файл

@ -0,0 +1,7 @@
%C - Driver for SUNXI Platform Blocks
Syntax:
platform-control -d [driver name] &
Examples:
platform-control -d sunxi &

3
devp/sunxi/pinfo.mk Исполняемый файл
Просмотреть файл

@ -0,0 +1,3 @@
define PINFO
PINFO DESCRIPTION=SUNXI platform system blocks driver
endef

298
devp/sunxi/private/hw/sun8iw7-platform.h Обычный файл
Просмотреть файл

@ -0,0 +1,298 @@
/*
* (c) 2024, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#ifndef _SUN8IW7_PLATFORM_H_INCLUDED
#define _SUN8IW7_PLATFORM_H_INCLUDED
#include <errno.h>
#include <sunxi.h>
#include <clock.h>
/*
* SUN8IW7
* Converting functions of register's
*/
static inline int sun8iw7_convert_clk_index(enum sunxi_clk_index id, int *clk_shift)
{
int res = (EOK);
switch(id)
{
case THS_CLK: *clk_shift = 0x00; break;
case NAND0_CLK: *clk_shift = 0x03; break;
case SDMMC0_CLK: *clk_shift = 0x05; break;
case SDMMC1_CLK: *clk_shift = 0x06; break;
case SDMMC2_CLK: *clk_shift = 0x07; break;
case SS_CLK: *clk_shift = 0x0A; break;
case SPI0_CLK: *clk_shift = 0x0B; break;
case SPI1_CLK: *clk_shift = 0x0C; break;
case I2S0_CLK: *clk_shift = 0x0F; break;
case I2S1_CLK: *clk_shift = 0x10; break;
case I2S2_CLK: *clk_shift = 0x11; break;
case OWA_CLK: *clk_shift = 0x13; break;
case DE_CLK: *clk_shift = 0x24; break;
case LCD0_TCON_CLK: *clk_shift = 0x29; break;
case LCD1_TCON_CLK: *clk_shift = 0x2A; break;
case TVE0_CLK: *clk_shift = 0x2B; break;
case DEINTERLACE_CLK: *clk_shift = 0x2C; break;
case CSI_MISC_CLK: *clk_shift = 0x2F; break;
case CSI0_CLK: *clk_shift = 0x30; break;
case VE_CLK: *clk_shift = 0x32; break;
case ADDA_CLK: *clk_shift = 0x33; break;
case AVS_CLK: *clk_shift = 0x34; break;
case HDMI0_CLK: *clk_shift = 0x37; break;
case HDMI_SLOW_CLK: *clk_shift = 0x38; break;
case MBUS0_CLK: *clk_shift = 0x39; break;
case GPU_CLK: *clk_shift = 0x4B; break;
case EMAC_CLK: *clk_shift = (-ENOTSUP); break;
case EPHY_CLK: *clk_shift = (-ENOTSUP); break;
default: res = EPERM;
}
return (res);
}
static inline int sun8iw7_convert_pll_index(enum sunxi_pll_clocks id, int *pll_shift)
{
int res = (EOK);
switch(id)
{
case PLL_CPU0_CTRL: *pll_shift = 0x00; break;
case PLL_AUDIO_CTRL: *pll_shift = 0x02; break;
case PLL_VIDEO0_CTRL: *pll_shift = 0x04; break;
case PLL_VE_CTRL: *pll_shift = 0x06; break;
case PLL_DDR0_CTRL: *pll_shift = 0x08; break;
case PLL_PERIPH0_CTRL: *pll_shift = 0x0A; break;
case PLL_GPU_CTRL: *pll_shift = 0x0E; break;
case PLL_PERIPH1_CTRL: *pll_shift = 0x11; break;
case PLL_DE_CTRL: *pll_shift = 0x12; break;
default: res = EPERM; break;
}
return (res);
}
static inline int sun8iw7_check_clk_parent_index(enum sunxi_clk_parent id)
{
switch (id)
{
case PLL_AUDIO_8X:
case PLL_AUDIO_4X:
case PLL_AUDIO_2X:
case PLL_AUDIO:
case PLL_VIDEO0:
case PLL_VE:
case PLL_PERIPH0:
case PLL_PERIPH0_2X:
case PLL_PERIPH1:
case PLL_DDR0:
case PLL_DE:
return (EOK);
default:
return (EINVAL);
}
}
static inline uint8_t sun8iw7_get_struct_bus_gating(enum sunxi_clk_index id, uint8_t *num_bus)
{
/* BUS_CLK_GATING_REG0 */
*num_bus = 0;
switch (id)
{
case SS_CLK: return 5;
case SDMMC0_CLK: return 8;
case SDMMC1_CLK: return 9;
case SDMMC2_CLK: return 10;
case NAND0_CLK: return 13;
case DRAM_CLK: return 14;
case EMAC_CLK: return 17;
case TS_CLK: return 18;
case SPI0_CLK: return 20;
case SPI1_CLK: return 21;
default: break;
}
/* BUS_CLK_GATING_REG1 */
*num_bus = 1;
switch (id)
{
case VE_CLK: return 0;
case LCD0_TCON_CLK: return 3;
case LCD1_TCON_CLK: return 4;
case DEINTERLACE_CLK: return 5;
case CSI0_CLK: return 8;
case TVE0_CLK: return 9;
case HDMI_SLOW_CLK: return (-ENOTSUP);
case HDMI0_CLK: return 11;
case DE_CLK: return 12;
case GPU_CLK: return 20;
default: break;
}
/* BUS_CLK_GATING_REG2 */
*num_bus = 2;
switch (id)
{
case ADDA_CLK: return 0;
case OWA_CLK: return 1;
case THS_CLK: return 8;
case I2S0_CLK: return 12;
case I2S1_CLK: return 13;
case I2S2_CLK: return 14;
default: break;
}
/* BUS_CLK_GATING_REG3 */
*num_bus = 3;
switch (id)
{
default: break;
}
/* BUS_CLK_GATING_REG4 */
*num_bus = 4;
switch (id)
{
case EPHY_CLK: return 0;
default: break;
}
return (ENOTSUP);
}
static inline uint8_t sun8iw7_get_struct_bus_sft_rst(enum sunxi_clk_index id, uint8_t *num_bus)
{
/* BUS_SOFT_RST_REG0 */
*num_bus = 0;
switch (id)
{
case SS_CLK: return 5;
case SDMMC0_CLK: return 8;
case SDMMC1_CLK: return 9;
case SDMMC2_CLK: return 10;
case NAND0_CLK: return 13;
case DRAM_CLK: return 14;
case EMAC_CLK: return 17;
case TS_CLK: return 18;
case SPI0_CLK: return 20;
case SPI1_CLK: return 21;
default: break;
}
/* BUS_SOFT_RST_REG1 */
*num_bus = 1;
switch (id)
{
case VE_CLK: return 0;
case LCD0_TCON_CLK: return 3;
case LCD1_TCON_CLK: return 4;
case DEINTERLACE_CLK: return 5;
case CSI0_CLK: return 8;
case TVE0_CLK: return 9;
case HDMI_SLOW_CLK: return 10;
case HDMI0_CLK: return 11;
case DE_CLK: return 12;
case GPU_CLK: return 20;
default: break;
}
/* BUS_SOFT_RST_REG2 */
*num_bus = 2;
switch (id)
{
case EPHY_CLK: return 2;
default: break;
}
/* BUS_SOFT_RST_REG3 */
*num_bus = 3;
switch (id)
{
case ADDA_CLK: return 0;
case OWA_CLK: return 1;
case THS_CLK: return 8;
case I2S0_CLK: return 12;
case I2S1_CLK: return 13;
case I2S2_CLK: return 14;
default: break;
}
/* BUS_SOFT_RST_REG4 */
*num_bus = 4;
switch (id)
{
default: break;
}
return (ENOTSUP);
}
static inline int sun8iw7_covert_clk_parent_to_pll_ctrl(enum sunxi_clk_parent id, enum sunxi_pll_clocks *pll_id)
{
/*
* x - is the coefficient of pll
* if x < 0 - is a division
* if x > 0 - is a multiplication
*/
int x = 1;
switch (id)
{
case PLL_AUDIO: x = -8; goto set_audio_pll;
case PLL_AUDIO_2X: x = -4; goto set_audio_pll;
case PLL_AUDIO_4X: x = -2;
case PLL_AUDIO_8X:
set_audio_pll:
*pll_id = PLL_AUDIO_CTRL;
break;
case PLL_VIDEO0_2X: x = 2;
case PLL_VIDEO0:
*pll_id = PLL_VIDEO0_CTRL;
break;
case PLL_VE:
*pll_id = PLL_VE_CTRL;
break;
case PLL_PERIPH0: x = -2;
case PLL_PERIPH0_2X:
*pll_id = PLL_PERIPH0_CTRL;
break;
case PLL_PERIPH1:
*pll_id = PLL_PERIPH0_CTRL;
break;
case PLL_DDR0:
*pll_id = PLL_DDR0_CTRL;
break;
case PLL_DE:
*pll_id = PLL_DE_CTRL;
break;
case OSC_24M:
*pll_id = OSC24M; // 24MHz
break;
default:
return (-ENOTSUP);
}
return x;
}
static inline plat_func_t sun8iw7_get_plat_func(void)
{
const static plat_func_t func =
{
.convert_clk_index = sun8iw7_convert_clk_index,
.convert_pll_index = sun8iw7_convert_pll_index,
.check_clk_parent_index = sun8iw7_check_clk_parent_index,
.get_struct_bus_gat = sun8iw7_get_struct_bus_gating,
.get_struct_bus_rst = sun8iw7_get_struct_bus_sft_rst,
.covert_clk_parent_to_pll_ctrl = sun8iw7_covert_clk_parent_to_pll_ctrl,
};
return func;
}
#endif /* _SUN8IW7_PLATFORM_H_INCLUDED */

138
devp/sunxi/public/hw/sunxi-platform.h Обычный файл
Просмотреть файл

@ -0,0 +1,138 @@
/*
* (c) 2024, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#ifndef _SUNXI_PLATFORM_H_INCLUDED
#define _SUNXI_PLATFORM_H_INCLUDED
/*
* CLK IDs
*/
/* CCU CLK IDs */
enum sunxi_clk_index {
THS_CLK,
NAND0_CLK,
NAND1_CLK,
SDMMC0_CLK,
SDMMC1_CLK,
SDMMC2_CLK,
SDMMC3_CLK,
TS_CLK,
SS_CLK,
SPI0_CLK,
SPI1_CLK,
SPI2_CLK,
SPI3_CLK,
I2S0_CLK,
I2S1_CLK,
I2S2_CLK,
TDM_CLK,
OWA_CLK,
KEYPAD_CLK,
SATA_CLK,
USB_CLK,
CIR0_CLK,
CIR1_CLK,
EMAC_CLK,
EPHY_CLK,
DRAM_CLK,
DE_CLK,
DE_MP_CLK,
BE0_CLK,
BE1_CLK,
FE0_CLK,
FE1_CLK,
MP_CLK,
LCD0_TCON_CLK,
LCD1_TCON_CLK,
TV0_TCON_CLK,
TV1_TCON_CLK,
TCON0_CH0_CLK,
TCON1_CH0_CLK,
TVE0_CLK,
TVE1_CLK,
DEINTERLACE_CLK,
TCON0_CH1_CLK,
TCON1_CH1_CLK,
CSI_MISC_CLK,
CSI0_CLK,
CSI1_CLK,
VE_CLK,
ADDA_CLK,
AVS_CLK,
DMIC_CLK,
HDMI0_CLK,
HDMI1_CLK,
HDMI_SLOW_CLK,
PS_CLK,
MTC_CLK,
MBUS0_CLK,
MBUS1_CLK,
GMAC_CLK,
MIPI_DSI_CLK,
MIPI_CSI_CLK,
IEP_DRC0_CLK,
IEP_DRC1_CLK,
IEP_DEU0_CLK,
IEP_DEU1_CLK,
TVD0_CLK,
TVD1_CLK,
TVD2_CLK,
TVD3_CLK,
GPU_CLK,
GPU_MEM_CLK,
GPU_HYD_CLK,
ATS_CLK,
TRACE_CLK,
CLK_OUTA,
CLK_OUTB,
CCU_CLK_MAX,
} sunxi_clk_index;
/* CCU PLL IDs */
enum sunxi_pll_clocks {
PLL_CPU0_CTRL = CCU_CLK_MAX,
PLL_CPU1_CTRL,
PLL_AUDIO_CTRL,
PLL_VIDEO0_CTRL,
PLL_VIDEO1_CTRL,
PLL_VE_CTRL,
PLL_DDR0_CTRL,
PLL_DDR1_CTRL,
PLL_PERIPH0_CTRL,
PLL_PERIPH1_CTRL,
PLL_GPU_CTRL,
PLL_DE_CTRL,
PLL_SATA_CTRL,
PLL_MIPI_CTRL,
CCU_PLL_MAX,
} sunxi_pll_clocks;
/* CCU CLK PARENT IDs */
enum sunxi_clk_parent {
OSC_24M = CCU_PLL_MAX,
PLL_AUDIO,
PLL_AUDIO_2X,
PLL_AUDIO_4X,
PLL_AUDIO_8X,
PLL_VIDEO0,
PLL_VIDEO0_2X,
PLL_VIDEO1,
PLL_VIDEO1_2X,
PLL_VE,
PLL_DDR0,
PLL_DDR1,
PLL_PERIPH0,
PLL_PERIPH0_2X,
PLL_GPU,
PLL_PERIPH1,
PLL_PERIPH1_2X,
PLL_DE,
PLL_SATA,
PLL_MIPI,
CLK_PARENT_MAX,
} sunxi_clk_parent;
#endif /* _SUNXI_PLATFORM_H_INCLUDED */

63
devp/sunxi/reset.c Обычный файл
Просмотреть файл

@ -0,0 +1,63 @@
/*
* (c) 2024, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#include <sunxi.h>
static int reset_enable(sunxi_plat_t *dev, plat_ctrl_reset_cfg_t *cfg)
{
uint8_t shift_bus_rst = ENOTSUP;
uint8_t bus_rst_id = 0xFF;
uint32_t rst_value = 0;
shift_bus_rst = dev->func.get_struct_bus_rst(cfg->id, &bus_rst_id);
if (shift_bus_rst == ENOTSUP)
{
return (-ENOTSUP);
}
if (cfg->state == PLAT_CTRL_RST_STATE_ENABLED)
{
rst_value = 1 << shift_bus_rst;
}
else
{
rst_value = 0;
}
if (shift_bus_rst != (-ENOTSUP))
{
regmap_update_bits(dev->ccu_base, SUNXI_BUS_SFT_RST_OFFSET(bus_rst_id), (1 << shift_bus_rst), rst_value);
delay(10);
}
return (EOK);
}
int sunxi_set_reset(void *hdl, plat_ctrl_reset_cfg_t *cfg)
{
int res = (EOK);
sunxi_plat_t *dev = hdl;
switch (cfg->state)
{
case PLAT_CTRL_RST_STATE_ENABLED:
case PLAT_CTRL_RST_STATE_DISABLED:
{
res = check_valid_id_rst(dev->func, cfg->id);
if (res == EOK)
{
res = reset_enable(dev, cfg);
}
break;
}
default:
{
perror("Not supported RESET config state");
break;
}
}
return (res);
}

207
devp/sunxi/sunxi.c Исполняемый файл
Просмотреть файл

@ -0,0 +1,207 @@
/*
* (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);
}

95
devp/sunxi/sunxi.h Исполняемый файл
Просмотреть файл

@ -0,0 +1,95 @@
/*
* (c) 2024, SWD Embedded Systems Limited, http://www.kpda.ru
*/
#ifndef _SUNXI_H_INCLUDED
#define _SUNXI_H_INCLUDED
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/neutrino.h>
#include <hw/inout.h>
#include <hw/platform-control.h>
#include <hw/sunxi-platform.h>
/*
* SUNXI CCU
*/
#define SUNXI_CCU_BASE 0x01C20000
#define SUNXI_CCU_SIZE 0x400
/*
* SUNXI SYSTEM CONTROL REG
* Used to determine the SoC id
*/
#define SUNXI_SYS_CTL_VER_REG 0x24
#define SUNXI_SYS_CTL_VER_SIZE 0x4
#define SUNXI_SYS_CTL_BASE 0x01C00000
#define SUNXI_MASK_DIV(x) (x - 1)
#define SUNXI_PLL_CTRL_OFFSET(id) (0x000 + (0x04 * id)) // id=0 to PLL_CLK_MAX
#define SUNXI_BUS_CLK_GATING_OFFSET(id) (0x060 + (0x04 * id)) // id=0 to 4
#define SUNXI_CCU_CLK_OFFSET(id) (0x074 + (0x04 * id)) // id=0 to CCU_CLK_MAX
#define SUNXI_BUS_SFT_RST_OFFSET(id) (0x2C0 + (0x04 * id + (id >= 3 ? (id == 3 ? 0x4 : 0x8) : 0))) // id=0 to 4
/*
* Identification of the SUNXI SoC family
*/
enum sunxi_soc_id {
sun8iw1 = 0x1633,
sun8iw2 = 0x1651,
sun8iw3 = 0x1650,
sun8iw5 = 0x1667,
sun8iw6 = 0x1673,
sun8iw7 = 0x1680,
sun8iw8 = 0x1681,
sun8iw10 = 0x1699,
sun8iw11 = 0x1701,
sun8iw12 = 0x1721,
sun8iw15 = 0x1755,
sun8iw16 = 0x1816,
sun8iw17 = 0x1708,
};
typedef struct {
int (*convert_clk_index)(enum sunxi_clk_index id, int *clock_shift);
int (*convert_pll_index)(enum sunxi_pll_clocks id, int *pll_shift);
int (*check_clk_parent_index)(enum sunxi_clk_parent id);
uint8_t (*get_struct_bus_gat)(enum sunxi_clk_index id, uint8_t *num_bus);
uint8_t (*get_struct_bus_rst)(enum sunxi_clk_index id, uint8_t *num_bus);
int (*covert_clk_parent_to_pll_ctrl)(enum sunxi_clk_parent id, enum sunxi_pll_clocks *pll_id);
} plat_func_t;
typedef struct {
PLAT_CTRL plat; /* has to be the first element */
uintptr_t ccu_base;
uintptr_t sys_base;
char soc_version[8];
plat_func_t func;
} sunxi_plat_t;
extern void* sunxi_init(void *hdl, char *options);
extern void sunxi_fini(void *hdl);
extern int sunxi_drvinfo(void *hdl, plat_ctrl_drvinfo_t *info);
extern int sunxi_set_clk(void *hdl, plat_ctrl_clk_cfg_t *cfg);
extern int sunxi_get_clk(void *hdl, plat_ctrl_clk_cfg_t *cfg);
extern int sunxi_set_reset(void *hdl, plat_ctrl_reset_cfg_t *cfg);
void regmap_update_bits(uintptr_t addr, uint32_t offset, uint32_t mask, uint32_t value);
int check_valid_id_clk(plat_func_t func, enum sunxi_clk_index cfg_id, int *shift);
int check_valid_id_rst(plat_func_t func, enum sunxi_clk_index cfg_id);
int check_valid_id_pll(plat_func_t func, enum sunxi_pll_clocks cfg_id, int *shift);
int check_valid_id_clock_parent(plat_func_t func, enum sunxi_clk_parent cfg_id);
#endif /* _SUNXI_H_INCLUDED */