Драйвер devp-sunxi.so для ЗОСРВ Нейтрино редакции 2024
Этот коммит содержится в:
Коммит
30073b5705
2
Makefile
Исполняемый файл
2
Makefile
Исполняемый файл
@ -0,0 +1,2 @@
|
||||
LIST=hardware
|
||||
include recurse.mk
|
66
README.md
Обычный файл
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
Исполняемый файл
2
devp/Makefile
Исполняемый файл
@ -0,0 +1,2 @@
|
||||
LIST=hardware
|
||||
include recurse.mk
|
9
devp/sunxi/Makefile
Исполняемый файл
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
Исполняемый файл
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
Исполняемый файл
1
devp/sunxi/arm/dll.le.v7/Makefile
Исполняемый файл
@ -0,0 +1 @@
|
||||
include ../../common.mk
|
603
devp/sunxi/clock.c
Обычный файл
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 doesn’t 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
Обычный файл
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
Обычный файл
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
Исполняемый файл
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
Исполняемый файл
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
Исполняемый файл
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
Обычный файл
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
Обычный файл
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
Обычный файл
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
Исполняемый файл
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
Исполняемый файл
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 */
|
Загрузка…
Ссылка в новой задаче
Block a user