mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-02-05 15:23:03 +08:00
[bsp][rockchip] Port to DM
RK3588/RK3576/RK356x/RK3308 Signed-off-by: GuEe-GUI <2991707448@qq.com>
This commit is contained in:
@@ -342,11 +342,11 @@ This document is based on the RT-Thread mainline repository and categorizes the
|
||||
|
||||
#### 🟡 Rockchip
|
||||
|
||||
| BSP Name | GPIO | UART | ADC | I2C | SPI | WDT |
|
||||
|----------|------|------|-----|-----|-----|-----|
|
||||
| [rk2108](rockchip/rk2108) | - | ✅ | - | - | - | - |
|
||||
| [rk3500](rockchip/rk3500) | - | ✅ | - | - | - | - |
|
||||
| [rk3568](rockchip/rk3568) | - | ✅ | - | - | - | - |
|
||||
| BSP Name | GPIO | UART | ADC | I2C | SPI | WDT | HWTimer | PWM | RTC | SDIO | CAN | PCI |
|
||||
|----------|------|------|-----|-----|-----|-----|---------|-----|-----|------|-----|------|
|
||||
| [rk2108](rockchip/rk2108) | - | ✅ | - | - | - | - | - | - | - | - | - | - |
|
||||
| [rk3300](rockchip/rk3300) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | - |
|
||||
| [rk3500](rockchip/rk3500) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
|
||||
#### 🟡 APM32
|
||||
|
||||
@@ -417,22 +417,22 @@ This document is based on the RT-Thread mainline repository and categorizes the
|
||||
| [swm320-mini](synwit/swm320-mini) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [swm341-mini](synwit/swm341-mini) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
|
||||
#### ⚪ N32G452xx
|
||||
#### ⚪ N32G452xx
|
||||
| BSP Name | GPIO | UART | ADC | CAN | DAC | Flash | HWTimer | I2C | PWM | RTC | SDIO | SPI | WDT |
|
||||
|----------|------|------|-----|-----|-----|-------|---------|-----|-----|-----|------|-----|-----|
|
||||
| [n32g452xx-mini-system](n32g452xx/n32g452xx-mini-system) | ✅ | ✅ | ✅ | ✅ | - | ✅ | ✅ | ✅ | ✅ | - | ✅ | ✅ | ✅ |
|
||||
|
||||
#### ⚪ W60x
|
||||
#### ⚪ W60x
|
||||
| BSP Name | GPIO | UART | ADC | Crypto | Flash | HWTimer | WDT | PWM | I2C | SPI |
|
||||
|----------|------|------|-----|--------|-------|---------|-----|-----|-----|-----|
|
||||
| [w60x](w60x) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
|
||||
#### ⚪ Allwinner Tina
|
||||
#### ⚪ Allwinner Tina
|
||||
| BSP Name | GPIO | UART | SPI | SDIO |
|
||||
|----------|------|------|-----|------|
|
||||
| [allwinner_tina](allwinner_tina) | ✅ | ✅ | ✅ | ✅ |
|
||||
|
||||
#### ⚪ HC321136
|
||||
#### ⚪ HC321136
|
||||
| BSP Name | GPIO | UART | I2C |
|
||||
|----------|------|------|-----|
|
||||
| [hc321136](hc32/hc321136) | ✅ | ✅ | ✅ |
|
||||
@@ -442,7 +442,7 @@ This document is based on the RT-Thread mainline repository and categorizes the
|
||||
|----------|------|------|
|
||||
| [hc321196](hc32/hc321196) | ✅ | ✅ |
|
||||
|
||||
#### ⚪ Amebaz
|
||||
#### ⚪ Amebaz
|
||||
| BSP Name | GPIO | UART | WLAN |
|
||||
|----------|------|------|------|
|
||||
| [amebaz](amebaz) | - | ✅ | ✅ |
|
||||
@@ -840,17 +840,17 @@ This document is based on the RT-Thread mainline repository and categorizes the
|
||||
|----------|------|------|-----|-------|---------|------|-----|-----|------|----------|-----|
|
||||
| [ab32vg1-ab-prougen](bluetrum/ab32vg1-ab-prougen) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
|
||||
#### ⚪ Core-V-MCU
|
||||
#### ⚪ Core-V-MCU
|
||||
| BSP Name | UART |
|
||||
|----------|------|
|
||||
| [core-v-cv32e40p](core-v-mcu/core-v-cv32e40p) | ✅ |
|
||||
|
||||
#### ⚪ HiFive1
|
||||
#### ⚪ HiFive1
|
||||
| BSP Name | GPIO | UART |
|
||||
|----------|------|------|
|
||||
| [hifive1](hifive1) | ✅ | ✅ |
|
||||
|
||||
#### ⚪ Sparkfun-RedV
|
||||
#### ⚪ Sparkfun-RedV
|
||||
| BSP Name | GPIO | UART | ADC | I2C | SPI | WDT | Timer | PWM | RTC |
|
||||
|----------|------|------|-----|-----|-----|-----|-------|-----|-----|
|
||||
| [sparkfun-redv](sparkfun-redv) | ✅ | ✅ | - | - | - | - | ✅ | - | - |
|
||||
|
||||
24
bsp/rockchip/dm/Kconfig
Executable file
24
bsp/rockchip/dm/Kconfig
Executable file
@@ -0,0 +1,24 @@
|
||||
SOC_DM_ADC_DIR = $(SOC_DM_DIR)/adc
|
||||
SOC_DM_CAN_DIR = $(SOC_DM_DIR)/can
|
||||
SOC_DM_CLK_DIR = $(SOC_DM_DIR)/clk
|
||||
SOC_DM_HWCRYPTO_DIR = $(SOC_DM_DIR)/hwcrypto
|
||||
SOC_DM_HWSPINLOCK_DIR = $(SOC_DM_DIR)/hwspinlock
|
||||
SOC_DM_HWTIMER_DIR = $(SOC_DM_DIR)/hwtimer
|
||||
SOC_DM_I2C_DIR = $(SOC_DM_DIR)/i2c
|
||||
SOC_DM_INPUT_MISC_DIR = $(SOC_DM_DIR)/input/misc
|
||||
SOC_DM_MBOX_DIR = $(SOC_DM_DIR)/mailbox
|
||||
SOC_DM_MFD_DIR = $(SOC_DM_DIR)/mfd
|
||||
SOC_DM_NVMEM_DIR = $(SOC_DM_DIR)/nvmem
|
||||
SOC_DM_PCI_DIR = $(SOC_DM_DIR)/pci
|
||||
SOC_DM_PHYE_DIR = $(SOC_DM_DIR)/phye
|
||||
SOC_DM_PIN_DIR = $(SOC_DM_DIR)/pin
|
||||
SOC_DM_PINCTRL_DIR = $(SOC_DM_DIR)/pinctrl
|
||||
SOC_DM_PMDOMAIN_DIR = $(SOC_DM_DIR)/pmdomain
|
||||
SOC_DM_PWM_DIR = $(SOC_DM_DIR)/pwm
|
||||
SOC_DM_REGULATOR_DIR = $(SOC_DM_DIR)/regulator
|
||||
SOC_DM_RTC_DIR = $(SOC_DM_DIR)/rtc
|
||||
SOC_DM_SDIO_DIR = $(SOC_DM_DIR)/sdio
|
||||
SOC_DM_SOC_DIR = $(SOC_DM_DIR)/soc
|
||||
SOC_DM_SPI_DIR = $(SOC_DM_DIR)/spi
|
||||
SOC_DM_THERMAL_DIR = $(SOC_DM_DIR)/thermal
|
||||
SOC_DM_WDT_DIR = $(SOC_DM_DIR)/watchdog
|
||||
3
bsp/rockchip/rk3568/SConscript → bsp/rockchip/dm/SConscript
Normal file → Executable file
3
bsp/rockchip/rk3568/SConscript → bsp/rockchip/dm/SConscript
Normal file → Executable file
@@ -1,8 +1,7 @@
|
||||
# for module compiling
|
||||
import os
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
cwd = GetCurrentDir()
|
||||
objs = []
|
||||
list = os.listdir(cwd)
|
||||
|
||||
6
bsp/rockchip/dm/adc/Kconfig
Executable file
6
bsp/rockchip/dm/adc/Kconfig
Executable file
@@ -0,0 +1,6 @@
|
||||
config RT_ADC_ROCKCHIP_SARADC
|
||||
bool "Rockchip SARADC driver"
|
||||
depends on RT_USING_ADC
|
||||
depends on RT_USING_RESET
|
||||
depends on RT_USING_REGULATOR
|
||||
default n
|
||||
14
bsp/rockchip/dm/adc/SConscript
Executable file
14
bsp/rockchip/dm/adc/SConscript
Executable file
@@ -0,0 +1,14 @@
|
||||
from building import *
|
||||
|
||||
group = []
|
||||
cwd = GetCurrentDir()
|
||||
CPPPATH = [cwd + '/../include']
|
||||
|
||||
src = []
|
||||
|
||||
if GetDepend(['RT_USING_ADC']):
|
||||
src += ['adc-rockchip_saradc.c']
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
527
bsp/rockchip/dm/adc/adc-rockchip_saradc.c
Executable file
527
bsp/rockchip/dm/adc/adc-rockchip_saradc.c
Executable file
File diff suppressed because it is too large
Load Diff
7
bsp/rockchip/dm/can/Kconfig
Executable file
7
bsp/rockchip/dm/can/Kconfig
Executable file
@@ -0,0 +1,7 @@
|
||||
config RT_CAN_CANFD_ROCKCHIP
|
||||
bool "Rockchip CANFD controller"
|
||||
depends on RT_CAN_USING_CANFD
|
||||
depends on RT_USING_RESET
|
||||
select RT_USING_DEVICE_IPC
|
||||
select RT_USING_SYSTEM_WORKQUEUE
|
||||
default n
|
||||
12
bsp/rockchip/dm/can/SConscript
Executable file
12
bsp/rockchip/dm/can/SConscript
Executable file
@@ -0,0 +1,12 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = []
|
||||
CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/can']
|
||||
|
||||
if GetDepend(['RT_CAN_CANFD_ROCKCHIP']):
|
||||
src += ['canfd-rockchip.c']
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
1061
bsp/rockchip/dm/can/canfd-rockchip.c
Executable file
1061
bsp/rockchip/dm/can/canfd-rockchip.c
Executable file
File diff suppressed because it is too large
Load Diff
36
bsp/rockchip/dm/clk/Kconfig
Executable file
36
bsp/rockchip/dm/clk/Kconfig
Executable file
@@ -0,0 +1,36 @@
|
||||
menuconfig RT_CLK_ROCKCHIP_RK8XX_CLKOUT
|
||||
bool "Clock driver for RK805/RK808/RK809/RK817/RK818"
|
||||
depends on RT_MFD_RK8XX
|
||||
depends on RT_USING_OFW
|
||||
default n
|
||||
|
||||
menuconfig RT_CLK_ROCKCHIP_LINK
|
||||
bool "Rockchip link clock controller"
|
||||
depends on RT_USING_OFW
|
||||
default y
|
||||
|
||||
menuconfig RT_CLK_ROCKCHIP
|
||||
bool "Rockchip clock controller common"
|
||||
depends on RT_USING_OFW
|
||||
depends on RT_USING_RESET
|
||||
default y
|
||||
|
||||
config RT_CLK_ROCKCHIP_RK3308
|
||||
bool "Rockchip RK3308 clock controller support"
|
||||
depends on RT_CLK_ROCKCHIP
|
||||
default n
|
||||
|
||||
config RT_CLK_ROCKCHIP_RK3568
|
||||
bool "Rockchip RK3568 clock controller support"
|
||||
depends on RT_CLK_ROCKCHIP
|
||||
default n
|
||||
|
||||
config RT_CLK_ROCKCHIP_RK3576
|
||||
bool "Rockchip RK3576 clock controller support"
|
||||
depends on RT_CLK_ROCKCHIP
|
||||
default n
|
||||
|
||||
config RT_CLK_ROCKCHIP_RK3588
|
||||
bool "Rockchip RK3588 clock controller support"
|
||||
depends on RT_CLK_ROCKCHIP
|
||||
default n
|
||||
33
bsp/rockchip/dm/clk/SConscript
Executable file
33
bsp/rockchip/dm/clk/SConscript
Executable file
@@ -0,0 +1,33 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = []
|
||||
CPPPATH = [cwd + '/../include']
|
||||
|
||||
if GetDepend(['RT_CLK_ROCKCHIP_LINK']):
|
||||
src += ['clk-link.c']
|
||||
|
||||
if GetDepend(['RT_CLK_ROCKCHIP_RK8XX_CLKOUT']):
|
||||
src += ['clk-rk8xx-clkout.c']
|
||||
|
||||
if GetDepend(['RT_CLK_ROCKCHIP']):
|
||||
src += ['clk-rk-cpu.c', 'clk-rk-composite.c', 'clk-rk-divider.c', 'clk-rk-factor.c',
|
||||
'clk-rk-fraction-divider.c', 'clk-rk-gate.c', 'clk-rk-mmc-phase.c',
|
||||
'clk-rk-mux.c', 'clk-rk-muxgrf.c', 'clk-rk-pll.c', 'clk-rk-half-divider.c',
|
||||
'clk-rk.c', 'softrst.c']
|
||||
|
||||
if GetDepend(['RT_CLK_ROCKCHIP_RK3308']):
|
||||
src += ['clk-rk3308.c']
|
||||
|
||||
if GetDepend(['RT_CLK_ROCKCHIP_RK3568']):
|
||||
src += ['clk-rk3568.c']
|
||||
|
||||
if GetDepend(['RT_CLK_ROCKCHIP_RK3576']):
|
||||
src += ['clk-rk3576.c']
|
||||
|
||||
if GetDepend(['RT_CLK_ROCKCHIP_RK3588']):
|
||||
src += ['clk-rk3588.c']
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
210
bsp/rockchip/dm/clk/clk-link.c
Executable file
210
bsp/rockchip/dm/clk/clk-link.c
Executable file
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define DBG_TAG "clk.link"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
struct rockchip_link_data
|
||||
{
|
||||
rt_size_t cells_nr;
|
||||
struct rt_clk_cell **cells;
|
||||
};
|
||||
|
||||
struct rockchip_link_cell
|
||||
{
|
||||
struct rt_clk_cell cell;
|
||||
rt_uint32_t bit_idx;
|
||||
};
|
||||
|
||||
#define cell_to_rockchip_link_cell(cell) rt_container_of(cell, struct rockchip_link_cell, cell)
|
||||
|
||||
struct rockchip_link_clk
|
||||
{
|
||||
struct rt_clk_node parent;
|
||||
|
||||
void *base;
|
||||
};
|
||||
|
||||
#define raw_to_rockchip_link_clk(raw) rt_container_of(raw, struct rockchip_link_clk, parent)
|
||||
|
||||
static void clk_gate_endisable(struct rt_clk_cell *cell, int enable)
|
||||
{
|
||||
rt_uint32_t reg;
|
||||
int set = 1 ^ enable;
|
||||
struct rockchip_link_cell *link_cell = cell_to_rockchip_link_cell(cell);
|
||||
struct rockchip_link_clk *link_clk = raw_to_rockchip_link_clk(cell->clk_np);
|
||||
|
||||
reg = RT_BIT(link_cell->bit_idx + 16);
|
||||
|
||||
if (set)
|
||||
{
|
||||
reg |= RT_BIT(link_cell->bit_idx);
|
||||
}
|
||||
|
||||
HWREG32(link_clk->base) = reg;
|
||||
}
|
||||
|
||||
static rt_err_t rockchip_link_clk_enable(struct rt_clk_cell *cell)
|
||||
{
|
||||
clk_gate_endisable(cell, 1);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void rockchip_link_clk_disable(struct rt_clk_cell *cell)
|
||||
{
|
||||
clk_gate_endisable(cell, 0);
|
||||
}
|
||||
|
||||
static rt_bool_t rockchip_link_clk_is_enabled(struct rt_clk_cell *cell)
|
||||
{
|
||||
rt_uint32_t reg;
|
||||
struct rockchip_link_cell *link_cell = cell_to_rockchip_link_cell(cell);
|
||||
struct rockchip_link_clk *link_clk = raw_to_rockchip_link_clk(cell->clk_np);
|
||||
|
||||
reg = HWREG32(link_clk->base);
|
||||
reg ^= RT_BIT(link_cell->bit_idx);
|
||||
reg &= RT_BIT(link_cell->bit_idx);
|
||||
|
||||
return !!reg;
|
||||
}
|
||||
|
||||
const struct rt_clk_ops clk_gate_ops =
|
||||
{
|
||||
.enable = rockchip_link_clk_enable,
|
||||
.disable = rockchip_link_clk_disable,
|
||||
.is_enabled = rockchip_link_clk_is_enabled,
|
||||
};
|
||||
|
||||
#define GATE_LINK(_name, _pname, _bit_idx) \
|
||||
(void *)&(struct rockchip_link_cell) \
|
||||
{ \
|
||||
.cell.name = _name, \
|
||||
.cell.parents_nr = 1, \
|
||||
.cell.parent_name = _pname, \
|
||||
.cell.ops = &clk_gate_ops, \
|
||||
.cell.flags = RT_CLK_F_SET_RATE_PARENT, \
|
||||
.bit_idx = _bit_idx, \
|
||||
}
|
||||
|
||||
static struct rt_clk_cell *rk3562_clk_cells[] =
|
||||
{
|
||||
GATE_LINK("aclk_rga_jdec", "aclk_rga_pre", 3),
|
||||
GATE_LINK("aclk_vdpu", "aclk_vdpu_pre", 5),
|
||||
GATE_LINK("aclk_vepu", "aclk_vepu_pre", 3),
|
||||
GATE_LINK("aclk_vi_isp", "aclk_vi", 3),
|
||||
GATE_LINK("aclk_vo", "aclk_vo_pre", 3),
|
||||
GATE_LINK("hclk_vepu", "hclk_vepu_pre", 4),
|
||||
};
|
||||
|
||||
static const struct rockchip_link_data rk3562_clk_data =
|
||||
{
|
||||
.cells = rk3562_clk_cells,
|
||||
.cells_nr = RT_ARRAY_SIZE(rk3562_clk_cells),
|
||||
};
|
||||
|
||||
static struct rt_clk_cell *rk3588_clk_cells[] =
|
||||
{
|
||||
GATE_LINK("aclk_isp1_pre", "aclk_isp1_root", 6),
|
||||
GATE_LINK("hclk_isp1_pre", "hclk_isp1_root", 8),
|
||||
GATE_LINK("hclk_nvm", "hclk_nvm_root", 2),
|
||||
GATE_LINK("aclk_usb", "aclk_usb_root", 2),
|
||||
GATE_LINK("hclk_usb", "hclk_usb_root", 3),
|
||||
GATE_LINK("aclk_jpeg_decoder_pre", "aclk_jpeg_decoder_root", 7),
|
||||
GATE_LINK("aclk_vdpu_low_pre", "aclk_vdpu_low_root", 5),
|
||||
GATE_LINK("aclk_rkvenc1_pre", "aclk_rkvenc1_root", 3),
|
||||
GATE_LINK("hclk_rkvenc1_pre", "hclk_rkvenc1_root", 2),
|
||||
GATE_LINK("hclk_rkvdec0_pre", "hclk_rkvdec0_root", 5),
|
||||
GATE_LINK("aclk_rkvdec0_pre", "aclk_rkvdec0_root", 6),
|
||||
GATE_LINK("hclk_rkvdec1_pre", "hclk_rkvdec1_root", 4),
|
||||
GATE_LINK("aclk_rkvdec1_pre", "aclk_rkvdec1_root", 5),
|
||||
GATE_LINK("aclk_hdcp0_pre", "aclk_vo0_root", 9),
|
||||
GATE_LINK("hclk_vo0", "hclk_vo0_root", 5),
|
||||
GATE_LINK("aclk_hdcp1_pre", "aclk_hdcp1_root", 6),
|
||||
GATE_LINK("hclk_vo1", "hclk_vo1_root", 9),
|
||||
GATE_LINK("aclk_av1_pre", "aclk_av1_root", 1),
|
||||
GATE_LINK("pclk_av1_pre", "pclk_av1_root", 4),
|
||||
GATE_LINK("hclk_sdio_pre", "hclk_sdio_root", 1),
|
||||
GATE_LINK("pclk_vo0_grf", "pclk_vo0_root", 10),
|
||||
GATE_LINK("pclk_vo1_grf", "pclk_vo1_root", 12),
|
||||
};
|
||||
|
||||
static const struct rockchip_link_data rk3588_clk_data =
|
||||
{
|
||||
.cells = rk3588_clk_cells,
|
||||
.cells_nr = RT_ARRAY_SIZE(rk3588_clk_cells),
|
||||
};
|
||||
|
||||
static rt_err_t rockchip_clk_link_probe(struct rt_platform_device *pdev)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_device *dev = &pdev->parent;
|
||||
const struct rockchip_link_data *clk_data = pdev->id->data;
|
||||
struct rockchip_link_clk *link_clk = rt_calloc(1, sizeof(*link_clk));
|
||||
|
||||
if (!link_clk)
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
if (!(link_clk->base = rt_dm_dev_iomap(dev, 0)))
|
||||
{
|
||||
err = -RT_EIO;
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
link_clk->parent.dev = dev;
|
||||
link_clk->parent.cells = clk_data->cells;
|
||||
link_clk->parent.cells_nr = clk_data->cells_nr;
|
||||
|
||||
if ((err = rt_clk_register(&link_clk->parent)))
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
_fail:
|
||||
if (link_clk->base)
|
||||
{
|
||||
rt_iounmap(link_clk->base);
|
||||
}
|
||||
|
||||
rt_free(link_clk);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct rt_ofw_node_id rockchip_clk_link_ofw_ids[] =
|
||||
{
|
||||
{ .compatible = "rockchip,rk3562-clock-gate-link", .data = &rk3562_clk_data },
|
||||
{ .compatible = "rockchip,rk3588-clock-gate-link", .data = &rk3588_clk_data },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct rt_platform_driver rockchip_clk_link_driver =
|
||||
{
|
||||
.name = "clk-link",
|
||||
.ids = rockchip_clk_link_ofw_ids,
|
||||
|
||||
.probe = rockchip_clk_link_probe,
|
||||
};
|
||||
|
||||
static int rockchip_clk_link_register(void)
|
||||
{
|
||||
rt_platform_driver_register(&rockchip_clk_link_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_SUBSYS_EXPORT(rockchip_clk_link_register);
|
||||
51
bsp/rockchip/dm/clk/clk-rk-composite.c
Executable file
51
bsp/rockchip/dm/clk/clk-rk-composite.c
Executable file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include "clk-rk-composite.h"
|
||||
#include "clk-rk-divider.h"
|
||||
#include "clk-rk-gate.h"
|
||||
#include "clk-rk-mux.h"
|
||||
|
||||
void rockchip_composite_clk_cell_init(struct rockchip_clk_cell *rk_cell)
|
||||
{
|
||||
struct rockchip_composite_clk_cell *composite_cell = cell_to_rockchip_composite_cell(&rk_cell->cell);
|
||||
|
||||
rk_cell->cell.ops = &composite_cell->ops;
|
||||
|
||||
if (rk_cell->cell.parents_nr > 1)
|
||||
{
|
||||
rockchip_mux_clk_cell_init(rk_cell);
|
||||
|
||||
composite_cell->ops.get_parent = rockchip_mux_clk_ops.get_parent;
|
||||
|
||||
if (!((rk_cell->mux_flags & CLK_MUX_READ_ONLY)))
|
||||
{
|
||||
composite_cell->ops.set_parent = rockchip_mux_clk_ops.set_parent;
|
||||
}
|
||||
}
|
||||
|
||||
if (rk_cell->gate_offset >= 0)
|
||||
{
|
||||
composite_cell->ops.enable = rockchip_gate_clk_ops.enable;
|
||||
composite_cell->ops.disable = rockchip_gate_clk_ops.disable;
|
||||
composite_cell->ops.is_enabled = rockchip_gate_clk_ops.is_enabled;
|
||||
}
|
||||
|
||||
if (rk_cell->div_width > 0)
|
||||
{
|
||||
composite_cell->ops.recalc_rate = clk_divider_ops.recalc_rate;
|
||||
composite_cell->ops.round_rate = clk_divider_ops.round_rate;
|
||||
|
||||
if (!((rk_cell->div_flags & CLK_DIVIDER_READ_ONLY)))
|
||||
{
|
||||
composite_cell->ops.set_rate = clk_divider_ops.set_rate;
|
||||
}
|
||||
}
|
||||
}
|
||||
191
bsp/rockchip/dm/clk/clk-rk-composite.h
Executable file
191
bsp/rockchip/dm/clk/clk-rk-composite.h
Executable file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#ifndef __CLK_RK_COMPOSITE_H__
|
||||
#define __CLK_RK_COMPOSITE_H__
|
||||
|
||||
#include "clk-rk.h"
|
||||
|
||||
struct rockchip_composite_clk_cell
|
||||
{
|
||||
struct rockchip_clk_cell rk_cell;
|
||||
|
||||
struct rt_clk_ops ops;
|
||||
};
|
||||
|
||||
#define COMPOSITE(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw, df, go, gs, gf) \
|
||||
(void *)&(struct rockchip_composite_clk_cell) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.parent_names = pnames, \
|
||||
.rk_cell.cell.parents_nr = RT_ARRAY_SIZE(pnames), \
|
||||
.rk_cell.cell.flags = f, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.muxdiv_offset = mo, \
|
||||
.rk_cell.mux_shift = ms, \
|
||||
.rk_cell.mux_width = mw, \
|
||||
.rk_cell.mux_flags = mf, \
|
||||
.rk_cell.div_shift = ds, \
|
||||
.rk_cell.div_width = dw, \
|
||||
.rk_cell.div_flags = df, \
|
||||
.rk_cell.gate_offset = go, \
|
||||
.rk_cell.gate_shift = gs, \
|
||||
.rk_cell.gate_flags = gf, \
|
||||
.rk_cell.init = rockchip_composite_clk_cell_init, \
|
||||
}
|
||||
|
||||
#define COMPOSITE_MUXTBL(_id, cname, pnames, f, mo, ms, mw, mf, mt, ds, dw, df, go, gs, gf) \
|
||||
(void *)&(struct rockchip_composite_clk_cell) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.parent_names = pnames, \
|
||||
.rk_cell.cell.parents_nr = RT_ARRAY_SIZE(pnames), \
|
||||
.rk_cell.cell.flags = f, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.muxdiv_offset = mo, \
|
||||
.rk_cell.mux_shift = ms, \
|
||||
.rk_cell.mux_width = mw, \
|
||||
.rk_cell.mux_flags = mf, \
|
||||
.rk_cell.mux_table = mt, \
|
||||
.rk_cell.div_shift = ds, \
|
||||
.rk_cell.div_width = dw, \
|
||||
.rk_cell.div_flags = df, \
|
||||
.rk_cell.gate_offset = go, \
|
||||
.rk_cell.gate_shift = gs, \
|
||||
.rk_cell.gate_flags = gf, \
|
||||
.rk_cell.init = rockchip_composite_clk_cell_init, \
|
||||
}
|
||||
|
||||
#define COMPOSITE_DIV_OFFSET(_id, cname, pnames, f, mo, ms, mw, mf, do, ds, dw, df, go, gs, gf) \
|
||||
(void *)&(struct rockchip_composite_clk_cell) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.parent_names = pnames, \
|
||||
.rk_cell.cell.parents_nr = RT_ARRAY_SIZE(pnames), \
|
||||
.rk_cell.cell.flags = f, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.muxdiv_offset = mo, \
|
||||
.rk_cell.mux_shift = ms, \
|
||||
.rk_cell.mux_width = mw, \
|
||||
.rk_cell.mux_flags = mf, \
|
||||
.rk_cell.div_offset = do, \
|
||||
.rk_cell.div_shift = ds, \
|
||||
.rk_cell.div_width = dw, \
|
||||
.rk_cell.div_flags = df, \
|
||||
.rk_cell.gate_offset = go, \
|
||||
.rk_cell.gate_shift = gs, \
|
||||
.rk_cell.gate_flags = gf, \
|
||||
.rk_cell.init = rockchip_composite_clk_cell_init, \
|
||||
}
|
||||
|
||||
#define COMPOSITE_NOMUX(_id, cname, pname, f, mo, ds, dw, df, go, gs, gf) \
|
||||
(void *)&(struct rockchip_composite_clk_cell) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.parent_name = pname, \
|
||||
.rk_cell.cell.parents_nr = 1, \
|
||||
.rk_cell.cell.flags = f, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.muxdiv_offset = mo, \
|
||||
.rk_cell.div_shift = ds, \
|
||||
.rk_cell.div_width = dw, \
|
||||
.rk_cell.div_flags = df, \
|
||||
.rk_cell.gate_offset = go, \
|
||||
.rk_cell.gate_shift = gs, \
|
||||
.rk_cell.gate_flags = gf, \
|
||||
.rk_cell.init = rockchip_composite_clk_cell_init, \
|
||||
}
|
||||
|
||||
#define COMPOSITE_NOMUX_DIVTBL(_id, cname, pname, f, mo, ds, dw, df, dt, go, gs, gf) \
|
||||
(void *)&(struct rockchip_composite_clk_cell) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.parent_name = pname, \
|
||||
.rk_cell.cell.parents_nr = 1, \
|
||||
.rk_cell.cell.flags = f, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.muxdiv_offset = mo, \
|
||||
.rk_cell.div_shift = ds, \
|
||||
.rk_cell.div_width = dw, \
|
||||
.rk_cell.div_flags = df, \
|
||||
.rk_cell.div_table = dt, \
|
||||
.rk_cell.gate_offset = go, \
|
||||
.rk_cell.gate_shift = gs, \
|
||||
.rk_cell.gate_flags = gf, \
|
||||
.rk_cell.init = rockchip_composite_clk_cell_init, \
|
||||
}
|
||||
|
||||
#define COMPOSITE_NODIV(_id, cname, pnames, f, mo, ms, mw, mf, go, gs, gf) \
|
||||
(void *)&(struct rockchip_composite_clk_cell) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.parent_names = pnames, \
|
||||
.rk_cell.cell.parents_nr = RT_ARRAY_SIZE(pnames), \
|
||||
.rk_cell.cell.flags = f, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.muxdiv_offset = mo, \
|
||||
.rk_cell.mux_shift = ms, \
|
||||
.rk_cell.mux_width = mw, \
|
||||
.rk_cell.mux_flags = mf, \
|
||||
.rk_cell.gate_offset = go, \
|
||||
.rk_cell.gate_shift = gs, \
|
||||
.rk_cell.gate_flags = gf, \
|
||||
.rk_cell.init = rockchip_composite_clk_cell_init, \
|
||||
}
|
||||
|
||||
#define COMPOSITE_NOGATE(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw, df) \
|
||||
(void *)&(struct rockchip_composite_clk_cell) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.parent_names = pnames, \
|
||||
.rk_cell.cell.parents_nr = RT_ARRAY_SIZE(pnames), \
|
||||
.rk_cell.cell.flags = f, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.muxdiv_offset = mo, \
|
||||
.rk_cell.mux_shift = ms, \
|
||||
.rk_cell.mux_width = mw, \
|
||||
.rk_cell.mux_flags = mf, \
|
||||
.rk_cell.div_shift = ds, \
|
||||
.rk_cell.div_width = dw, \
|
||||
.rk_cell.div_flags = df, \
|
||||
.rk_cell.gate_offset = -1, \
|
||||
.rk_cell.init = rockchip_composite_clk_cell_init, \
|
||||
}
|
||||
|
||||
#define COMPOSITE_NOGATE_DIVTBL(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw, df, dt) \
|
||||
(void *)&(struct rockchip_composite_clk_cell) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.parent_names = pnames, \
|
||||
.rk_cell.cell.parents_nr = RT_ARRAY_SIZE(pnames), \
|
||||
.rk_cell.cell.flags = f, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.muxdiv_offset = mo, \
|
||||
.rk_cell.mux_shift = ms, \
|
||||
.rk_cell.mux_width = mw, \
|
||||
.rk_cell.mux_flags = mf, \
|
||||
.rk_cell.div_shift = ds, \
|
||||
.rk_cell.div_width = dw, \
|
||||
.rk_cell.div_flags = df, \
|
||||
.rk_cell.div_table = dt, \
|
||||
.rk_cell.gate_offset = -1, \
|
||||
.rk_cell.init = rockchip_composite_clk_cell_init, \
|
||||
}
|
||||
|
||||
rt_inline struct rockchip_composite_clk_cell *cell_to_rockchip_composite_cell(struct rt_clk_cell *cell)
|
||||
{
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
return rt_container_of(rk_cell, struct rockchip_composite_clk_cell, rk_cell);
|
||||
}
|
||||
|
||||
void rockchip_composite_clk_cell_init(struct rockchip_clk_cell *rk_cell);
|
||||
|
||||
#endif /* __CLK_RK_COMPOSITE_H__ */
|
||||
278
bsp/rockchip/dm/clk/clk-rk-cpu.c
Executable file
278
bsp/rockchip/dm/clk/clk-rk-cpu.c
Executable file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include "clk-rk-cpu.h"
|
||||
|
||||
static rt_ubase_t rockchip_cpu_clk_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate)
|
||||
{
|
||||
void *base;
|
||||
rt_uint32_t clksel0;
|
||||
struct rockchip_cpu_clk_cell *cpu_clk_cell = cell_to_rockchip_cpu_cell(cell);
|
||||
const struct rockchip_cpu_clk_reg_data *reg_data = cpu_clk_cell->reg_data;
|
||||
|
||||
base = cpu_clk_cell->rk_cell.provider->reg_base;
|
||||
|
||||
clksel0 = HWREG32(base + reg_data->core_reg[0]);
|
||||
clksel0 >>= reg_data->div_core_shift[0];
|
||||
clksel0 &= reg_data->div_core_mask[0];
|
||||
|
||||
return parent_rate / (clksel0 + 1);
|
||||
}
|
||||
|
||||
const struct rt_clk_ops rockchip_cpu_clk_ops =
|
||||
{
|
||||
.recalc_rate = rockchip_cpu_clk_recalc_rate,
|
||||
};
|
||||
|
||||
static const struct rockchip_cpu_clk_rate_table *rockchip_get_cpu_clk_settings(
|
||||
struct rockchip_cpu_clk_cell *cpu_clk_cell, rt_ubase_t rate)
|
||||
{
|
||||
const struct rockchip_cpu_clk_rate_table *rate_table = cpu_clk_cell->rate_table;
|
||||
|
||||
for (int i = 0; i < cpu_clk_cell->rate_count; ++i)
|
||||
{
|
||||
if (rate == rate_table[i].prate)
|
||||
{
|
||||
return &rate_table[i];
|
||||
}
|
||||
}
|
||||
|
||||
return RT_NULL;
|
||||
}
|
||||
|
||||
static void rockchip_cpu_clk_set_dividers(struct rockchip_cpu_clk_cell *cpu_clk_cell,
|
||||
const struct rockchip_cpu_clk_rate_table *rate)
|
||||
{
|
||||
void *base = cpu_clk_cell->rk_cell.provider->reg_base;
|
||||
|
||||
/* Alternate parent is active now. set the dividers */
|
||||
for (int i = 0; i < RT_ARRAY_SIZE(rate->divs); ++i)
|
||||
{
|
||||
const struct rockchip_cpu_clk_clksel *clksel = &rate->divs[i];
|
||||
|
||||
if (!clksel->reg)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
HWREG32(base + clksel->reg) = clksel->val;
|
||||
}
|
||||
}
|
||||
|
||||
static void rockchip_cpu_clk_set_pre_muxs(struct rockchip_cpu_clk_cell *cpu_clk_cell,
|
||||
const struct rockchip_cpu_clk_rate_table *rate)
|
||||
{
|
||||
void *base = cpu_clk_cell->rk_cell.provider->reg_base;
|
||||
|
||||
/* Alternate parent is active now. set the pre_muxs */
|
||||
for (int i = 0; i < RT_ARRAY_SIZE(rate->pre_muxs); ++i)
|
||||
{
|
||||
const struct rockchip_cpu_clk_clksel *clksel = &rate->pre_muxs[i];
|
||||
|
||||
if (!clksel->reg)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
HWREG32(base + clksel->reg) = clksel->val;
|
||||
}
|
||||
}
|
||||
|
||||
static void rockchip_cpu_clk_set_post_muxs(struct rockchip_cpu_clk_cell *cpu_clk_cell,
|
||||
const struct rockchip_cpu_clk_rate_table *rate)
|
||||
{
|
||||
void *base = cpu_clk_cell->rk_cell.provider->reg_base;
|
||||
|
||||
/* Alternate parent is active now. set the muxs */
|
||||
for (int i = 0; i < RT_ARRAY_SIZE(rate->post_muxs); ++i)
|
||||
{
|
||||
const struct rockchip_cpu_clk_clksel *clksel = &rate->post_muxs[i];
|
||||
|
||||
if (!clksel->reg)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
HWREG32(base + clksel->reg) = clksel->val;
|
||||
}
|
||||
}
|
||||
|
||||
static int rockchip_cpu_clk_pre_rate_change(struct rockchip_cpu_clk_cell *cpu_clk_cell,
|
||||
rt_ubase_t old_rate, rt_ubase_t new_rate)
|
||||
{
|
||||
rt_ubase_t alt_prate, alt_div;
|
||||
void *base = cpu_clk_cell->rk_cell.provider->reg_base;
|
||||
const struct rockchip_cpu_clk_reg_data *reg_data = cpu_clk_cell->reg_data;
|
||||
const struct rockchip_cpu_clk_rate_table *rate;
|
||||
|
||||
/* Check validity of the new rate */
|
||||
if (!(rate = rockchip_get_cpu_clk_settings(cpu_clk_cell, new_rate)))
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
alt_prate = rt_clk_cell_get_rate(&cpu_clk_cell->rk_cell_alt_parent->cell);
|
||||
|
||||
/*
|
||||
* If the old parent clock speed is less than the clock speed
|
||||
* of the alternate parent, then it should be ensured that at no point
|
||||
* the armclk speed is more than the old_rate until the dividers are
|
||||
* set.
|
||||
*/
|
||||
if (alt_prate > old_rate)
|
||||
{
|
||||
/* Calculate dividers */
|
||||
alt_div = RT_DIV_ROUND_UP(alt_prate, old_rate) - 1;
|
||||
|
||||
if (alt_div > reg_data->div_core_mask[0])
|
||||
{
|
||||
alt_div = reg_data->div_core_mask[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* Change parents and add dividers in a single transaction.
|
||||
*
|
||||
* NOTE: we do this in a single transaction so we're never
|
||||
* dividing the primary parent by the extra dividers that were
|
||||
* needed for the alt.
|
||||
*/
|
||||
|
||||
for (int i = 0; i < reg_data->num_cores; ++i)
|
||||
{
|
||||
HWREG32(base + reg_data->core_reg[i]) = HIWORD_UPDATE(
|
||||
alt_div,
|
||||
reg_data->div_core_mask[i],
|
||||
reg_data->div_core_shift[i]);
|
||||
}
|
||||
}
|
||||
|
||||
rockchip_cpu_clk_set_pre_muxs(cpu_clk_cell, rate);
|
||||
|
||||
/* select alternate parent */
|
||||
if (reg_data->mux_core_reg)
|
||||
{
|
||||
HWREG32(base + reg_data->mux_core_reg) = HIWORD_UPDATE(
|
||||
reg_data->mux_core_alt,
|
||||
reg_data->mux_core_mask,
|
||||
reg_data->mux_core_shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
HWREG32(base + reg_data->core_reg[0]) = HIWORD_UPDATE(
|
||||
reg_data->mux_core_alt,
|
||||
reg_data->mux_core_mask,
|
||||
reg_data->mux_core_shift);
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t rockchip_cpu_clk_post_rate_change(struct rockchip_cpu_clk_cell *cpu_clk_cell,
|
||||
rt_ubase_t old_rate, rt_ubase_t new_rate)
|
||||
{
|
||||
void *base = cpu_clk_cell->rk_cell.provider->reg_base;
|
||||
const struct rockchip_cpu_clk_rate_table *rate;
|
||||
const struct rockchip_cpu_clk_reg_data *reg_data = cpu_clk_cell->reg_data;
|
||||
|
||||
if (!(rate = rockchip_get_cpu_clk_settings(cpu_clk_cell, new_rate)))
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
if (old_rate < new_rate)
|
||||
{
|
||||
rockchip_cpu_clk_set_dividers(cpu_clk_cell, rate);
|
||||
}
|
||||
|
||||
/*
|
||||
* post-rate change event, re-mux to primary parent and remove dividers.
|
||||
*
|
||||
* NOTE: we do this in a single transaction so we're never dividing the
|
||||
* primary parent by the extra dividers that were needed for the alt.
|
||||
*/
|
||||
|
||||
if (reg_data->mux_core_reg)
|
||||
{
|
||||
HWREG32(base + reg_data->mux_core_reg) = HIWORD_UPDATE(
|
||||
reg_data->mux_core_main,
|
||||
reg_data->mux_core_mask,
|
||||
reg_data->mux_core_shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
HWREG32(base + reg_data->core_reg[0]) = HIWORD_UPDATE(
|
||||
reg_data->mux_core_main,
|
||||
reg_data->mux_core_mask,
|
||||
reg_data->mux_core_shift);
|
||||
}
|
||||
|
||||
rockchip_cpu_clk_set_post_muxs(cpu_clk_cell, rate);
|
||||
|
||||
/* Remove dividers */
|
||||
for (int i = 0; i < reg_data->num_cores; ++i)
|
||||
{
|
||||
HWREG32(base + reg_data->core_reg[i]) = HIWORD_UPDATE(
|
||||
0,
|
||||
reg_data->div_core_mask[i],
|
||||
reg_data->div_core_shift[i]);
|
||||
}
|
||||
|
||||
if (old_rate > new_rate)
|
||||
{
|
||||
rockchip_cpu_clk_set_dividers(cpu_clk_cell, rate);
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t rockchip_cpu_clk_notify(struct rt_clk_notifier *notifier,
|
||||
rt_ubase_t msg, rt_ubase_t old_rate, rt_ubase_t new_rate)
|
||||
{
|
||||
rt_err_t err = RT_EOK;
|
||||
struct rockchip_cpu_clk_cell *cpu_cell;
|
||||
|
||||
cpu_cell = rt_container_of(notifier, struct rockchip_cpu_clk_cell, notifier);
|
||||
|
||||
if (msg == RT_CLK_MSG_PRE_RATE_CHANGE)
|
||||
{
|
||||
err = rockchip_cpu_clk_pre_rate_change(cpu_cell, old_rate, new_rate);
|
||||
}
|
||||
else if (msg == RT_CLK_MSG_POST_RATE_CHANGE)
|
||||
{
|
||||
err = rockchip_cpu_clk_post_rate_change(cpu_cell, old_rate, new_rate);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void rockchip_cpu_clk_cell_init(struct rockchip_clk_cell *rk_cell)
|
||||
{
|
||||
struct rockchip_cpu_clk_cell *cpu_clk_cell = cell_to_rockchip_cpu_cell(&rk_cell->cell);
|
||||
|
||||
rk_cell->cell.parents_nr = 1;
|
||||
rk_cell->cell.parent_name = cpu_clk_cell->rk_cell_parent->cell.name;
|
||||
|
||||
if (cpu_clk_cell->rate_count > 0)
|
||||
{
|
||||
rk_cell->cell.flags |= RT_CLK_F_SET_RATE_PARENT;
|
||||
}
|
||||
}
|
||||
|
||||
void rockchip_cpu_clk_cell_setup(struct rockchip_clk_cell *rk_cell)
|
||||
{
|
||||
struct rockchip_cpu_clk_cell *cpu_clk_cell = cell_to_rockchip_cpu_cell(&rk_cell->cell);
|
||||
|
||||
rt_clk_prepare_enable(rt_clk_cell_get_clk(&cpu_clk_cell->rk_cell_alt_parent->cell, RT_NULL));
|
||||
|
||||
cpu_clk_cell->notifier.callback = rockchip_cpu_clk_notify;
|
||||
|
||||
rt_clk_notifier_register(rt_clk_cell_get_clk(&cpu_clk_cell->rk_cell_parent->cell, RT_NULL),
|
||||
&cpu_clk_cell->notifier);
|
||||
}
|
||||
87
bsp/rockchip/dm/clk/clk-rk-cpu.h
Executable file
87
bsp/rockchip/dm/clk/clk-rk-cpu.h
Executable file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#ifndef __CLK_RK_CPU_H__
|
||||
#define __CLK_RK_CPU_H__
|
||||
|
||||
#include "clk-rk.h"
|
||||
|
||||
#define ROCKCHIP_CPUCLK_NUM_DIVIDERS 6
|
||||
#define ROCKCHIP_CPUCLK_MAX_CORES 4
|
||||
|
||||
struct rockchip_cpu_clk_clksel
|
||||
{
|
||||
int reg;
|
||||
rt_uint32_t val;
|
||||
};
|
||||
|
||||
struct rockchip_cpu_clk_rate_table
|
||||
{
|
||||
rt_ubase_t prate;
|
||||
struct rockchip_cpu_clk_clksel divs[ROCKCHIP_CPUCLK_NUM_DIVIDERS];
|
||||
struct rockchip_cpu_clk_clksel pre_muxs[ROCKCHIP_CPUCLK_NUM_DIVIDERS];
|
||||
struct rockchip_cpu_clk_clksel post_muxs[ROCKCHIP_CPUCLK_NUM_DIVIDERS];
|
||||
};
|
||||
|
||||
struct rockchip_cpu_clk_reg_data
|
||||
{
|
||||
int core_reg[ROCKCHIP_CPUCLK_MAX_CORES];
|
||||
rt_uint8_t div_core_shift[ROCKCHIP_CPUCLK_MAX_CORES];
|
||||
rt_uint32_t div_core_mask[ROCKCHIP_CPUCLK_MAX_CORES];
|
||||
int num_cores;
|
||||
int mux_core_reg;
|
||||
rt_uint8_t mux_core_alt;
|
||||
rt_uint8_t mux_core_main;
|
||||
rt_uint8_t mux_core_shift;
|
||||
rt_uint32_t mux_core_mask;
|
||||
const char *pll_name;
|
||||
};
|
||||
|
||||
struct rockchip_cpu_clk_cell
|
||||
{
|
||||
struct rockchip_clk_cell rk_cell;
|
||||
struct rockchip_clk_cell *rk_cell_parent, *rk_cell_alt_parent;
|
||||
|
||||
int rate_count;
|
||||
const struct rockchip_cpu_clk_rate_table *rate_table;
|
||||
const struct rockchip_cpu_clk_reg_data *reg_data;
|
||||
|
||||
struct rt_clk_notifier notifier;
|
||||
};
|
||||
|
||||
#define CPU(_id, cname, parent, alt_parent, _rates, _nrates, _reg_data) \
|
||||
(void *)&(struct rockchip_cpu_clk_cell) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.ops = &rockchip_cpu_clk_ops, \
|
||||
.rk_cell.cell.flags = RT_CLK_F_GET_RATE_NOCACHE, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.init = rockchip_cpu_clk_cell_init, \
|
||||
.rk_cell.setup = rockchip_cpu_clk_cell_setup, \
|
||||
.rk_cell_parent = parent, \
|
||||
.rk_cell_alt_parent = alt_parent, \
|
||||
.rate_count = _nrates, \
|
||||
.rate_table = _rates, \
|
||||
.reg_data = _reg_data, \
|
||||
}
|
||||
|
||||
extern const struct rt_clk_ops rockchip_cpu_clk_ops;
|
||||
|
||||
rt_inline struct rockchip_cpu_clk_cell *cell_to_rockchip_cpu_cell(struct rt_clk_cell *cell)
|
||||
{
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
return rt_container_of(rk_cell, struct rockchip_cpu_clk_cell, rk_cell);
|
||||
}
|
||||
|
||||
void rockchip_cpu_clk_cell_init(struct rockchip_clk_cell *rk_cell);
|
||||
void rockchip_cpu_clk_cell_setup(struct rockchip_clk_cell *rk_cell);
|
||||
|
||||
#endif /* __CLK_RK_cpu_H__ */
|
||||
595
bsp/rockchip/dm/clk/clk-rk-divider.c
Executable file
595
bsp/rockchip/dm/clk/clk-rk-divider.c
Executable file
File diff suppressed because it is too large
Load Diff
52
bsp/rockchip/dm/clk/clk-rk-divider.h
Executable file
52
bsp/rockchip/dm/clk/clk-rk-divider.h
Executable file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#ifndef __CLK_RK_DIVIDER_H__
|
||||
#define __CLK_RK_DIVIDER_H__
|
||||
|
||||
#include "clk-rk.h"
|
||||
|
||||
#define DIV(_id, cname, pname, f, o, s, w, df) \
|
||||
(void *)&(struct rockchip_clk_cell) \
|
||||
{ \
|
||||
.cell.name = cname, \
|
||||
.cell.parent_name = pname, \
|
||||
.cell.parents_nr = 1, \
|
||||
.cell.flags = f, \
|
||||
.id = _id, \
|
||||
.muxdiv_offset = o, \
|
||||
.div_shift = s, \
|
||||
.div_width = w, \
|
||||
.div_flags = df, \
|
||||
.gate_offset = -1, \
|
||||
.init = rockchip_divider_clk_cell_init, \
|
||||
}
|
||||
|
||||
#define DIVTBL(_id, cname, pname, f, o, s, w, df, dt) \
|
||||
(void *)&(struct rockchip_clk_cell) \
|
||||
{ \
|
||||
.cell.name = cname, \
|
||||
.cell.parent_name = pname, \
|
||||
.cell.parents_nr = 1, \
|
||||
.cell.flags = f, \
|
||||
.id = _id, \
|
||||
.muxdiv_offset = o, \
|
||||
.div_shift = s, \
|
||||
.div_width = w, \
|
||||
.div_flags = df, \
|
||||
.div_table = dt, \
|
||||
.init = rockchip_divider_clk_cell_init, \
|
||||
}
|
||||
|
||||
extern const struct rt_clk_ops clk_divider_ops, clk_divider_ro_ops;
|
||||
|
||||
void rockchip_divider_clk_cell_init(struct rockchip_clk_cell *rk_cell);
|
||||
|
||||
#endif /* __CLK_RK_DIVIDER_H__ */
|
||||
61
bsp/rockchip/dm/clk/clk-rk-factor.c
Executable file
61
bsp/rockchip/dm/clk/clk-rk-factor.c
Executable file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include "clk-rk-factor.h"
|
||||
#include "clk-rk-gate.h"
|
||||
|
||||
static rt_ubase_t clk_factor_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate)
|
||||
{
|
||||
rt_uint64_t rate;
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
rate = (rt_uint64_t)parent_rate * rk_cell->div_shift;
|
||||
rt_do_div(rate, rk_cell->div_width);
|
||||
|
||||
return (rt_ubase_t)rate;
|
||||
}
|
||||
|
||||
static rt_base_t clk_factor_round_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t *prate)
|
||||
{
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
if (cell->flags & RT_CLK_F_SET_RATE_PARENT)
|
||||
{
|
||||
rt_ubase_t best_parent;
|
||||
|
||||
best_parent = (rate / rk_cell->div_shift) * rk_cell->div_width;
|
||||
*prate = rt_clk_cell_round_rate(rt_clk_cell_get_parent(cell), best_parent);
|
||||
}
|
||||
|
||||
return (*prate / rk_cell->div_width) * rk_cell->div_shift;
|
||||
}
|
||||
|
||||
static rt_err_t clk_factor_set_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t parent_rate)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
void rockchip_factor_clk_cell_init(struct rockchip_clk_cell *rk_cell)
|
||||
{
|
||||
struct rockchip_factor_clk_cell *factor_cell = cell_to_rockchip_factor_clk_cell(&rk_cell->cell);
|
||||
|
||||
rk_cell->cell.ops = &factor_cell->ops;
|
||||
|
||||
factor_cell->ops.recalc_rate = clk_factor_recalc_rate;
|
||||
factor_cell->ops.round_rate = clk_factor_round_rate;
|
||||
factor_cell->ops.set_rate = clk_factor_set_rate;
|
||||
|
||||
if (rk_cell->gate_offset >= 0)
|
||||
{
|
||||
factor_cell->ops.enable = rockchip_gate_clk_ops.enable;
|
||||
factor_cell->ops.disable = rockchip_gate_clk_ops.disable;
|
||||
factor_cell->ops.is_enabled = rockchip_gate_clk_ops.is_enabled;
|
||||
}
|
||||
}
|
||||
63
bsp/rockchip/dm/clk/clk-rk-factor.h
Executable file
63
bsp/rockchip/dm/clk/clk-rk-factor.h
Executable file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#ifndef __CLK_RK_FACTOR_H__
|
||||
#define __CLK_RK_FACTOR_H__
|
||||
|
||||
#include "clk-rk.h"
|
||||
|
||||
struct rockchip_factor_clk_cell
|
||||
{
|
||||
struct rockchip_clk_cell rk_cell;
|
||||
|
||||
struct rt_clk_ops ops;
|
||||
};
|
||||
|
||||
#define FACTOR(_id, cname, pname, f, fm, fd) \
|
||||
(void *)&(struct rockchip_factor_clk_cell) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.parent_name = pname, \
|
||||
.rk_cell.cell.parents_nr = 1, \
|
||||
.rk_cell.cell.flags = f, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.div_shift = fm, \
|
||||
.rk_cell.div_width = fd, \
|
||||
.rk_cell.init = rockchip_factor_clk_cell_init, \
|
||||
}
|
||||
|
||||
#define FACTOR_GATE(_id, cname, pname, f, fm, fd, go, gb, gf) \
|
||||
(void *)&(struct rockchip_factor_clk_cell) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.parent_name = pname, \
|
||||
.rk_cell.cell.parents_nr = 1, \
|
||||
.rk_cell.cell.flags = f, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.div_shift = fm, \
|
||||
.rk_cell.div_width = fd, \
|
||||
.rk_cell.gate_offset = go, \
|
||||
.rk_cell.gate_shift = gb, \
|
||||
.rk_cell.gate_flags = gf, \
|
||||
.rk_cell.init = rockchip_factor_clk_cell_init, \
|
||||
}
|
||||
|
||||
#define SGRF_GATE(_id, cname, pname) FACTOR(_id, cname, pname, 0, 1, 1)
|
||||
|
||||
rt_inline struct rockchip_factor_clk_cell *cell_to_rockchip_factor_clk_cell(struct rt_clk_cell *cell)
|
||||
{
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
return rt_container_of(rk_cell, struct rockchip_factor_clk_cell, rk_cell);
|
||||
}
|
||||
|
||||
void rockchip_factor_clk_cell_init(struct rockchip_clk_cell *rk_cell);
|
||||
|
||||
#endif /* __CLK_RK_FACTOR_H__ */
|
||||
370
bsp/rockchip/dm/clk/clk-rk-fraction-divider.c
Executable file
370
bsp/rockchip/dm/clk/clk-rk-fraction-divider.c
Executable file
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include "clk-rk-fraction-divider.h"
|
||||
#include "clk-rk-mux.h"
|
||||
#include "clk-rk-gate.h"
|
||||
|
||||
struct u32_fract
|
||||
{
|
||||
rt_uint32_t numerator;
|
||||
rt_uint32_t denominator;
|
||||
};
|
||||
|
||||
#define CLK_FD_MSHIFT 16
|
||||
#define CLK_FD_MWIDTH 16
|
||||
#define CLK_FD_NSHIFT 0
|
||||
#define CLK_FD_NWIDTH 16
|
||||
|
||||
rt_inline rt_uint32_t clk_fd_readl(struct rockchip_clk_cell *rk_cell)
|
||||
{
|
||||
void *base = rk_cell->provider->reg_base;
|
||||
|
||||
if (rk_cell->div_flags & CLK_FRAC_DIVIDER_BIG_ENDIAN)
|
||||
{
|
||||
return rt_be32_to_cpu(HWREG32(base + rk_cell->muxdiv_offset));
|
||||
}
|
||||
|
||||
return HWREG32(base + rk_cell->muxdiv_offset);
|
||||
}
|
||||
|
||||
rt_inline void clk_fd_writel(struct rockchip_clk_cell *rk_cell, rt_uint32_t val)
|
||||
{
|
||||
void *base = rk_cell->provider->reg_base;
|
||||
|
||||
if (rk_cell->div_flags & CLK_FRAC_DIVIDER_BIG_ENDIAN)
|
||||
{
|
||||
HWREG32(base + rk_cell->muxdiv_offset) = rt_cpu_to_be32(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
HWREG32(base + rk_cell->muxdiv_offset) = val;
|
||||
}
|
||||
}
|
||||
|
||||
static void clk_fd_get_div(struct rt_clk_cell *cell, struct u32_fract *fract)
|
||||
{
|
||||
rt_ubase_t m, n;
|
||||
rt_uint32_t val, mmask, nmask;
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
val = clk_fd_readl(rk_cell);
|
||||
|
||||
mmask = RT_GENMASK(CLK_FD_MWIDTH - 1, 0) << CLK_FD_MSHIFT;
|
||||
nmask = RT_GENMASK(CLK_FD_NWIDTH - 1, 0) << CLK_FD_NSHIFT;
|
||||
|
||||
m = (val & mmask) >> CLK_FD_MSHIFT;
|
||||
n = (val & nmask) >> CLK_FD_NSHIFT;
|
||||
|
||||
if (rk_cell->div_flags & CLK_FRAC_DIVIDER_ZERO_BASED)
|
||||
{
|
||||
++m;
|
||||
++n;
|
||||
}
|
||||
|
||||
fract->numerator = m;
|
||||
fract->denominator = n;
|
||||
}
|
||||
|
||||
static rt_ubase_t clk_fd_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate)
|
||||
{
|
||||
rt_uint64_t ret;
|
||||
struct u32_fract fract;
|
||||
|
||||
clk_fd_get_div(cell, &fract);
|
||||
|
||||
if (!fract.numerator || !fract.denominator)
|
||||
{
|
||||
return parent_rate;
|
||||
}
|
||||
|
||||
ret = (rt_uint64_t)parent_rate * fract.numerator;
|
||||
rt_do_div(ret, fract.denominator);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void clk_fractional_divider_general_approximation(struct rt_clk_cell *cell,
|
||||
rt_ubase_t rate, rt_ubase_t *parent_rate, rt_ubase_t *m, rt_ubase_t *n)
|
||||
{
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
/*
|
||||
* Get rate closer to *parent_rate to guarantee there is no overflow
|
||||
* for m and n. In the result it will be the nearest rate left shifted
|
||||
* by (scale - CLK_FD_NWIDTH) bits.
|
||||
*
|
||||
* For the detailed explanation see the top comment in this file.
|
||||
*/
|
||||
if (rk_cell->div_flags & CLK_FRAC_DIVIDER_POWER_OF_TWO_PS)
|
||||
{
|
||||
rt_ubase_t scale = fls_long(*parent_rate / rate - 1);
|
||||
|
||||
if (scale > CLK_FD_NWIDTH)
|
||||
{
|
||||
rate <<= scale - CLK_FD_NWIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
rational_best_approximation(rate, *parent_rate,
|
||||
RT_GENMASK(CLK_FD_MWIDTH - 1, 0), RT_GENMASK(CLK_FD_NWIDTH - 1, 0), m, n);
|
||||
}
|
||||
|
||||
/*
|
||||
* fractional divider must set that denominator is 20 times larger than
|
||||
* numerator to generate precise clock frequency.
|
||||
*/
|
||||
static void rockchip_fractional_approximation(struct rt_clk_cell *cell,
|
||||
rt_ubase_t rate, rt_ubase_t *parent_rate, rt_ubase_t *m, rt_ubase_t *n)
|
||||
{
|
||||
struct rt_clk_cell *p_parent;
|
||||
rt_ubase_t p_rate, p_parent_rate;
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
if (rate == 0)
|
||||
{
|
||||
*m = 0;
|
||||
*n = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
p_rate = rt_clk_cell_get_rate(rt_clk_cell_get_parent(cell));
|
||||
|
||||
if (rate * 20 > p_rate && p_rate % rate != 0)
|
||||
{
|
||||
p_parent = rt_clk_cell_get_parent(rt_clk_cell_get_parent(cell));
|
||||
|
||||
if (!p_parent)
|
||||
{
|
||||
*parent_rate = p_rate;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_parent_rate = rt_clk_cell_get_rate(p_parent);
|
||||
*parent_rate = p_parent_rate;
|
||||
}
|
||||
|
||||
if (*parent_rate == 0)
|
||||
{
|
||||
*m = 0;
|
||||
*n = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (*parent_rate < rate * 20)
|
||||
{
|
||||
/*
|
||||
* Fractional frequency divider to do
|
||||
* integer frequency divider does not need 20 times the limit.
|
||||
*/
|
||||
if (!(*parent_rate % rate))
|
||||
{
|
||||
*m = 1;
|
||||
*n = *parent_rate / rate;
|
||||
return;
|
||||
}
|
||||
else if (!(rk_cell->div_flags & CLK_FRAC_DIVIDER_NO_LIMIT))
|
||||
{
|
||||
*m = 0;
|
||||
*n = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rk_cell->div_flags |= CLK_FRAC_DIVIDER_POWER_OF_TWO_PS;
|
||||
|
||||
clk_fractional_divider_general_approximation(cell, rate, parent_rate, m, n);
|
||||
}
|
||||
|
||||
static rt_base_t clk_fd_round_rate(struct rt_clk_cell *cell,
|
||||
rt_ubase_t rate, rt_ubase_t *parent_rate)
|
||||
{
|
||||
rt_ubase_t m, n;
|
||||
rt_uint64_t ret;
|
||||
|
||||
if (!rate || rate >= *parent_rate)
|
||||
{
|
||||
return *parent_rate;
|
||||
}
|
||||
|
||||
rockchip_fractional_approximation(cell, rate, parent_rate, &m, &n);
|
||||
|
||||
ret = (rt_uint64_t)*parent_rate * m;
|
||||
rt_do_div(ret, n);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static rt_err_t clk_fd_set_rate(struct rt_clk_cell *cell, rt_ubase_t rate, rt_ubase_t parent_rate)
|
||||
{
|
||||
rt_ubase_t m, n;
|
||||
rt_uint32_t mmask, nmask, val;
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
rational_best_approximation(rate, parent_rate,
|
||||
RT_GENMASK(CLK_FD_MWIDTH - 1, 0), RT_GENMASK(CLK_FD_NWIDTH - 1, 0), &m, &n);
|
||||
|
||||
if (rk_cell->div_flags & CLK_FRAC_DIVIDER_ZERO_BASED)
|
||||
{
|
||||
--m;
|
||||
--n;
|
||||
}
|
||||
|
||||
mmask = RT_GENMASK(CLK_FD_MWIDTH - 1, 0) << CLK_FD_MSHIFT;
|
||||
nmask = RT_GENMASK(CLK_FD_NWIDTH - 1, 0) << CLK_FD_NSHIFT;
|
||||
|
||||
/*
|
||||
* When compensation the fractional divider,
|
||||
* the [1:0] bits of the numerator register are omitted,
|
||||
* which will lead to a large deviation in the result.
|
||||
* Therefore, it is required that the numerator must
|
||||
* be greater than 4.
|
||||
*
|
||||
* Note that there are some exceptions here:
|
||||
* If there is an even frac div, we need to keep the original
|
||||
* numerator(<4) and denominator. Otherwise, it may cause the
|
||||
* issue that the duty ratio is not 50%.
|
||||
*/
|
||||
if (m < 4 && m != 0)
|
||||
{
|
||||
if (n % 2 == 0)
|
||||
{
|
||||
val = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
val = RT_DIV_ROUND_UP(4, m);
|
||||
}
|
||||
|
||||
n *= val;
|
||||
m *= val;
|
||||
|
||||
if (n > nmask)
|
||||
{
|
||||
n = nmask;
|
||||
}
|
||||
}
|
||||
|
||||
mmask = RT_GENMASK(CLK_FD_MWIDTH - 1, 0) << CLK_FD_MSHIFT;
|
||||
nmask = RT_GENMASK(CLK_FD_NWIDTH - 1, 0) << CLK_FD_NSHIFT;
|
||||
|
||||
val = clk_fd_readl(rk_cell);
|
||||
val &= ~(mmask | nmask);
|
||||
val |= (m << CLK_FD_MSHIFT) | (n << CLK_FD_NSHIFT);
|
||||
clk_fd_writel(rk_cell, val);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t rockchip_clk_frac_notify(struct rt_clk_notifier *notifier,
|
||||
rt_ubase_t msg, rt_ubase_t old_rate, rt_ubase_t new_rate)
|
||||
{
|
||||
struct rt_clk_cell *cell;
|
||||
struct rockchip_fraction_divider_clk_cell *fraction_divider_cell;
|
||||
|
||||
fraction_divider_cell = rt_container_of(notifier, struct rockchip_fraction_divider_clk_cell, notifier);
|
||||
cell = &fraction_divider_cell->rk_cell_child->cell;
|
||||
|
||||
if (msg == RT_CLK_MSG_PRE_RATE_CHANGE)
|
||||
{
|
||||
fraction_divider_cell->rate_change_idx = cell->ops->get_parent(cell);
|
||||
|
||||
if (fraction_divider_cell->rate_change_idx != fraction_divider_cell->mux_frac_idx)
|
||||
{
|
||||
cell->ops->set_parent(cell, fraction_divider_cell->mux_frac_idx);
|
||||
fraction_divider_cell->rate_change_remuxed = 1;
|
||||
}
|
||||
}
|
||||
else if (msg == RT_CLK_MSG_POST_RATE_CHANGE)
|
||||
{
|
||||
/*
|
||||
* The RT_CLK_MSG_POST_RATE_CHANGE notifier runs directly after the
|
||||
* divider clock is set in clk_change_rate, so we'll have
|
||||
* remuxed back to the original parent before clk_change_rate
|
||||
* reaches the mux itself.
|
||||
*/
|
||||
if (fraction_divider_cell->rate_change_remuxed)
|
||||
{
|
||||
cell->ops->set_parent(cell, fraction_divider_cell->rate_change_idx);
|
||||
fraction_divider_cell->rate_change_remuxed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int match_string(const char * const *array, size_t n, const char *string)
|
||||
{
|
||||
for (int index = 0; index < n; ++index)
|
||||
{
|
||||
const char *item = array[index];
|
||||
|
||||
if (!item)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (!rt_strcmp(item, string))
|
||||
{
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
void rockchip_fraction_divider_clk_cell_init(struct rockchip_clk_cell *rk_cell)
|
||||
{
|
||||
struct rockchip_fraction_divider_clk_cell *fraction_divider_cell = cell_to_rockchip_fraction_divider_clk_cell(&rk_cell->cell);
|
||||
|
||||
rk_cell->cell.ops = &fraction_divider_cell->ops;
|
||||
rk_cell->cell.flags |= RT_CLK_F_SET_RATE_UNGATE;
|
||||
|
||||
if (fraction_divider_cell->rk_cell_child)
|
||||
{
|
||||
struct rockchip_clk_cell *rk_cell_child = fraction_divider_cell->rk_cell_child;
|
||||
struct rt_clk_cell *cell = &rk_cell_child->cell;
|
||||
|
||||
rk_cell_child->cell.flags |= RT_CLK_F_SET_RATE_PARENT;
|
||||
|
||||
fraction_divider_cell->mux_frac_idx = match_string(cell->parent_names, cell->parents_nr,
|
||||
rk_cell->cell.name);
|
||||
|
||||
rockchip_mux_clk_cell_init(rk_cell);
|
||||
|
||||
fraction_divider_cell->ops.get_parent = rockchip_mux_clk_ops.get_parent;
|
||||
fraction_divider_cell->ops.set_parent = rockchip_mux_clk_ops.set_parent;
|
||||
}
|
||||
|
||||
if (rk_cell->gate_offset >= 0)
|
||||
{
|
||||
fraction_divider_cell->ops.enable = rockchip_gate_clk_ops.enable;
|
||||
fraction_divider_cell->ops.disable = rockchip_gate_clk_ops.disable;
|
||||
fraction_divider_cell->ops.is_enabled = rockchip_gate_clk_ops.is_enabled;
|
||||
}
|
||||
|
||||
fraction_divider_cell->ops.recalc_rate = clk_fd_recalc_rate;
|
||||
fraction_divider_cell->ops.round_rate = clk_fd_round_rate;
|
||||
fraction_divider_cell->ops.set_rate = clk_fd_set_rate;
|
||||
}
|
||||
|
||||
void rockchip_fraction_divider_clk_cell_setup(struct rockchip_clk_cell *rk_cell)
|
||||
{
|
||||
struct rockchip_fraction_divider_clk_cell *fraction_divider_cell = cell_to_rockchip_fraction_divider_clk_cell(&rk_cell->cell);
|
||||
struct rockchip_clk_cell *rk_cell_child = fraction_divider_cell->rk_cell_child;
|
||||
|
||||
if (fraction_divider_cell->mux_frac_idx >= 0)
|
||||
{
|
||||
fraction_divider_cell->notifier.callback = rockchip_clk_frac_notify;
|
||||
|
||||
rt_clk_notifier_register(rt_clk_cell_get_clk(&rk_cell_child->cell, RT_NULL),
|
||||
&fraction_divider_cell->notifier);
|
||||
}
|
||||
}
|
||||
95
bsp/rockchip/dm/clk/clk-rk-fraction-divider.h
Executable file
95
bsp/rockchip/dm/clk/clk-rk-fraction-divider.h
Executable file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#ifndef __CLK_RK_FRACTION_DIVIDER_H__
|
||||
#define __CLK_RK_FRACTION_DIVIDER_H__
|
||||
|
||||
#include "clk-rk.h"
|
||||
|
||||
struct rockchip_fraction_divider_clk_cell
|
||||
{
|
||||
struct rockchip_clk_cell rk_cell;
|
||||
|
||||
struct rt_clk_ops ops;
|
||||
struct rockchip_clk_cell *rk_cell_child;
|
||||
|
||||
int mux_frac_idx;
|
||||
int rate_change_idx;
|
||||
int rate_change_remuxed;
|
||||
struct rt_clk_notifier notifier;
|
||||
};
|
||||
|
||||
#define COMPOSITE_FRAC(_id, cname, pname, f, mo, df, go, gs, gf)\
|
||||
(void *)&(struct rockchip_fraction_divider_clk_cell) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.parent_name = pname, \
|
||||
.rk_cell.cell.parents_nr = 1, \
|
||||
.rk_cell.cell.flags = f, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.muxdiv_offset = mo, \
|
||||
.rk_cell.div_shift = 16, \
|
||||
.rk_cell.div_width = 16, \
|
||||
.rk_cell.div_flags = df, \
|
||||
.rk_cell.gate_offset = go, \
|
||||
.rk_cell.gate_shift = gs, \
|
||||
.rk_cell.gate_flags = gf, \
|
||||
.rk_cell.init = rockchip_fraction_divider_clk_cell_init, \
|
||||
}
|
||||
|
||||
#define COMPOSITE_FRACMUX(_id, cname, pname, f, mo, df, go, gs, gf, ch) \
|
||||
(void *)&(struct rockchip_fraction_divider_clk_cell) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.parent_name = pname, \
|
||||
.rk_cell.cell.parents_nr = 1, \
|
||||
.rk_cell.cell.flags = f, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.muxdiv_offset = mo, \
|
||||
.rk_cell.div_shift = 16, \
|
||||
.rk_cell.div_width = 16, \
|
||||
.rk_cell.div_flags = df, \
|
||||
.rk_cell.gate_offset = go, \
|
||||
.rk_cell.gate_shift = gs, \
|
||||
.rk_cell.gate_flags = gf, \
|
||||
.rk_cell.init = rockchip_fraction_divider_clk_cell_init, \
|
||||
.rk_cell.setup = rockchip_fraction_divider_clk_cell_setup, \
|
||||
.rk_cell_child = ch, \
|
||||
}
|
||||
|
||||
#define COMPOSITE_FRACMUX_NOGATE(_id, cname, pname, f, mo, df, ch) \
|
||||
(void *)&(struct rockchip_fraction_divider_clk_cell) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.parent_name = pname, \
|
||||
.rk_cell.cell.parents_nr = 1, \
|
||||
.rk_cell.cell.flags = f, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.muxdiv_offset = mo, \
|
||||
.rk_cell.div_shift = 16, \
|
||||
.rk_cell.div_width = 16, \
|
||||
.rk_cell.div_flags = df, \
|
||||
.rk_cell.gate_offset = -1, \
|
||||
.rk_cell.init = rockchip_fraction_divider_clk_cell_init, \
|
||||
.rk_cell.setup = rockchip_fraction_divider_clk_cell_setup, \
|
||||
.rk_cell_child = ch, \
|
||||
}
|
||||
|
||||
rt_inline struct rockchip_fraction_divider_clk_cell *cell_to_rockchip_fraction_divider_clk_cell(struct rt_clk_cell *cell)
|
||||
{
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
return rt_container_of(rk_cell, struct rockchip_fraction_divider_clk_cell, rk_cell);
|
||||
}
|
||||
|
||||
void rockchip_fraction_divider_clk_cell_init(struct rockchip_clk_cell *rk_cell);
|
||||
void rockchip_fraction_divider_clk_cell_setup(struct rockchip_clk_cell *rk_cell);
|
||||
|
||||
#endif /* __CLK_RK_FRACTION_DIVIDER_H__ */
|
||||
109
bsp/rockchip/dm/clk/clk-rk-gate.c
Executable file
109
bsp/rockchip/dm/clk/clk-rk-gate.c
Executable file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include "clk-rk-gate.h"
|
||||
|
||||
rt_inline rt_uint32_t clk_gate_readl(struct rockchip_clk_cell *rk_cell)
|
||||
{
|
||||
void *base = rk_cell->provider->reg_base;
|
||||
|
||||
if (rk_cell->gate_flags & CLK_GATE_BIG_ENDIAN)
|
||||
{
|
||||
return rt_be32_to_cpu(HWREG32(base + rk_cell->gate_offset));
|
||||
}
|
||||
|
||||
return HWREG32(base + rk_cell->gate_offset);
|
||||
}
|
||||
|
||||
rt_inline void clk_gate_writel(struct rockchip_clk_cell *rk_cell, rt_uint32_t val)
|
||||
{
|
||||
void *base = rk_cell->provider->reg_base;
|
||||
|
||||
if (rk_cell->gate_flags & CLK_GATE_BIG_ENDIAN)
|
||||
{
|
||||
HWREG32(base + rk_cell->gate_offset) = rt_cpu_to_be32(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
HWREG32(base + rk_cell->gate_offset) = val;
|
||||
}
|
||||
}
|
||||
|
||||
static void clk_gate_endisable(struct rt_clk_cell *cell, int enable)
|
||||
{
|
||||
int set;
|
||||
rt_uint32_t reg;
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
set = rk_cell->gate_flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
|
||||
set ^= enable;
|
||||
|
||||
if (rk_cell->gate_flags & CLK_GATE_HIWORD_MASK)
|
||||
{
|
||||
reg = RT_BIT(rk_cell->gate_shift + 16);
|
||||
|
||||
if (set)
|
||||
{
|
||||
reg |= RT_BIT(rk_cell->gate_shift);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reg = clk_gate_readl(rk_cell);
|
||||
|
||||
if (set)
|
||||
{
|
||||
reg |= RT_BIT(rk_cell->gate_shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
reg &= ~RT_BIT(rk_cell->gate_shift);
|
||||
}
|
||||
}
|
||||
|
||||
clk_gate_writel(rk_cell, reg);
|
||||
}
|
||||
|
||||
static rt_err_t rockchip_gate_clk_enable(struct rt_clk_cell *cell)
|
||||
{
|
||||
clk_gate_endisable(cell, 1);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static void rockchip_gate_clk_disable(struct rt_clk_cell *cell)
|
||||
{
|
||||
clk_gate_endisable(cell, 0);
|
||||
}
|
||||
|
||||
static rt_bool_t rockchip_gate_clk_is_enabled(struct rt_clk_cell *cell)
|
||||
{
|
||||
rt_uint32_t reg;
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
reg = clk_gate_readl(rk_cell);
|
||||
|
||||
/* If a set bit disables this clk, flip it before masking */
|
||||
if (rk_cell->gate_flags & CLK_GATE_SET_TO_DISABLE)
|
||||
{
|
||||
reg ^= RT_BIT(rk_cell->gate_shift);
|
||||
}
|
||||
|
||||
reg &= RT_BIT(rk_cell->gate_shift);
|
||||
|
||||
return !!reg;
|
||||
}
|
||||
|
||||
const struct rt_clk_ops rockchip_gate_clk_ops =
|
||||
{
|
||||
.enable = rockchip_gate_clk_enable,
|
||||
.disable = rockchip_gate_clk_disable,
|
||||
.is_enabled = rockchip_gate_clk_is_enabled,
|
||||
};
|
||||
32
bsp/rockchip/dm/clk/clk-rk-gate.h
Executable file
32
bsp/rockchip/dm/clk/clk-rk-gate.h
Executable file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#ifndef __CLK_RK_GATE_H__
|
||||
#define __CLK_RK_GATE_H__
|
||||
|
||||
#include "clk-rk.h"
|
||||
|
||||
#define GATE(_id, cname, pname, f, o, b, gf) \
|
||||
(void *)&(struct rockchip_clk_cell) \
|
||||
{ \
|
||||
.cell.name = cname, \
|
||||
.cell.ops = &rockchip_gate_clk_ops, \
|
||||
.cell.parent_name = pname, \
|
||||
.cell.parents_nr = 1, \
|
||||
.cell.flags = f | RT_CLK_F_SET_RATE_PARENT, \
|
||||
.id = _id, \
|
||||
.gate_offset = o, \
|
||||
.gate_shift = b, \
|
||||
.gate_flags = gf, \
|
||||
}
|
||||
|
||||
extern const struct rt_clk_ops rockchip_gate_clk_ops;
|
||||
|
||||
#endif /* __CLK_RK_GATE_H__ */
|
||||
182
bsp/rockchip/dm/clk/clk-rk-half-divider.c
Executable file
182
bsp/rockchip/dm/clk/clk-rk-half-divider.c
Executable file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include "clk-rk-half-divider.h"
|
||||
#include "clk-rk-gate.h"
|
||||
#include "clk-rk-mux.h"
|
||||
|
||||
#define clk_div_mask(width) ((1 << (width)) - 1)
|
||||
|
||||
static rt_bool_t _is_best_half_div(rt_ubase_t rate, rt_ubase_t now,
|
||||
rt_ubase_t best, rt_ubase_t flags)
|
||||
{
|
||||
if (flags & CLK_DIVIDER_ROUND_CLOSEST)
|
||||
{
|
||||
return rt_abs(rate - now) <= rt_abs(rate - best);
|
||||
}
|
||||
|
||||
return now <= rate && now >= best;
|
||||
}
|
||||
|
||||
rt_inline rt_uint32_t clk_div_readl(struct rockchip_clk_cell *rk_cell)
|
||||
{
|
||||
return HWREG32(rk_cell->provider->reg_base + (rk_cell->div_offset ? : rk_cell->muxdiv_offset));
|
||||
}
|
||||
|
||||
rt_inline void clk_div_writel(struct rockchip_clk_cell *rk_cell, rt_uint32_t val)
|
||||
{
|
||||
HWREG32(rk_cell->provider->reg_base + (rk_cell->div_offset ? : rk_cell->muxdiv_offset)) = val;
|
||||
}
|
||||
|
||||
static rt_ubase_t clk_div_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate)
|
||||
{
|
||||
rt_uint32_t val;
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
val = clk_div_readl(rk_cell) >> rk_cell->div_shift;
|
||||
val &= clk_div_mask(rk_cell->div_width);
|
||||
val = val * 2 + 3;
|
||||
|
||||
return RT_DIV_ROUND_UP_ULL(((rt_uint64_t)parent_rate * 2), val);
|
||||
}
|
||||
|
||||
static int clk_div_bestdiv(struct rt_clk_cell *cell, rt_ubase_t rate,
|
||||
rt_ubase_t *best_parent_rate, rt_uint8_t width, rt_ubase_t flags)
|
||||
{
|
||||
rt_uint32_t bestdiv = 0;
|
||||
rt_bool_t is_bestdiv = RT_FALSE;
|
||||
rt_ubase_t parent_rate, best = 0, now, maxdiv;
|
||||
|
||||
if (!rate)
|
||||
{
|
||||
rate = 1;
|
||||
}
|
||||
|
||||
maxdiv = clk_div_mask(width);
|
||||
|
||||
if (!(cell->flags & RT_CLK_F_SET_RATE_PARENT))
|
||||
{
|
||||
parent_rate = *best_parent_rate;
|
||||
bestdiv = RT_DIV_ROUND_UP_ULL(((rt_uint64_t)parent_rate * 2), rate);
|
||||
|
||||
if (bestdiv < 3)
|
||||
{
|
||||
bestdiv = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
bestdiv = RT_DIV_ROUND_UP(bestdiv - 3, 2);
|
||||
}
|
||||
|
||||
bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
|
||||
|
||||
return bestdiv;
|
||||
}
|
||||
|
||||
/*
|
||||
* The maximum divider we can use without overflowing
|
||||
* rt_ubase_t in rate * i below
|
||||
*/
|
||||
maxdiv = rt_min((~0UL) / rate, maxdiv);
|
||||
|
||||
for (int i = 0; i <= maxdiv; ++i)
|
||||
{
|
||||
parent_rate = rt_clk_cell_round_rate(rt_clk_cell_get_parent(cell),
|
||||
((rt_uint64_t)rate * (i * 2 + 3)) / 2);
|
||||
now = RT_DIV_ROUND_UP_ULL(((rt_uint64_t)parent_rate * 2), (i * 2 + 3));
|
||||
|
||||
if (_is_best_half_div(rate, now, best, flags))
|
||||
{
|
||||
is_bestdiv = RT_TRUE;
|
||||
bestdiv = i;
|
||||
best = now;
|
||||
*best_parent_rate = parent_rate;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_bestdiv)
|
||||
{
|
||||
bestdiv = clk_div_mask(width);
|
||||
*best_parent_rate = rt_clk_cell_round_rate(rt_clk_cell_get_parent(cell), 1);
|
||||
}
|
||||
|
||||
return bestdiv;
|
||||
}
|
||||
|
||||
static rt_base_t clk_div_round_rate(struct rt_clk_cell *cell,
|
||||
rt_ubase_t rate, rt_ubase_t *prate)
|
||||
{
|
||||
int div;
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
div = clk_div_bestdiv(cell, rate, prate, rk_cell->div_width, rk_cell->div_flags);
|
||||
|
||||
return RT_DIV_ROUND_UP_ULL(((rt_uint64_t)*prate * 2), div * 2 + 3);
|
||||
}
|
||||
|
||||
static rt_err_t clk_div_set_rate(struct rt_clk_cell *cell,
|
||||
rt_ubase_t rate, rt_ubase_t parent_rate)
|
||||
{
|
||||
rt_uint32_t value, val;
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
value = RT_DIV_ROUND_UP_ULL(((rt_uint64_t)parent_rate * 2), rate);
|
||||
value = RT_DIV_ROUND_UP(value - 3, 2);
|
||||
value = rt_min_t(rt_uint32_t, value, clk_div_mask(rk_cell->div_width));
|
||||
|
||||
if (rk_cell->div_flags & CLK_DIVIDER_HIWORD_MASK)
|
||||
{
|
||||
val = clk_div_mask(rk_cell->div_width) << (rk_cell->div_shift + 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
val = clk_div_readl(rk_cell);
|
||||
val &= ~(clk_div_mask(rk_cell->div_width) << rk_cell->div_shift);
|
||||
}
|
||||
|
||||
val |= value << rk_cell->div_shift;
|
||||
clk_div_writel(rk_cell, val);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
void rockchip_half_divider_clk_cell_init(struct rockchip_clk_cell *rk_cell)
|
||||
{
|
||||
struct rockchip_half_divider_clk_cell *half_divider_cell = cell_to_rockchip_half_divider_clk_cell(&rk_cell->cell);
|
||||
|
||||
rk_cell->cell.ops = &half_divider_cell->ops;
|
||||
|
||||
if (rk_cell->cell.parents_nr > 1)
|
||||
{
|
||||
rockchip_mux_clk_cell_init(rk_cell);
|
||||
|
||||
half_divider_cell->ops.get_parent = rockchip_mux_clk_ops.get_parent;
|
||||
|
||||
if (!((rk_cell->mux_flags & CLK_MUX_READ_ONLY)))
|
||||
{
|
||||
half_divider_cell->ops.set_parent = rockchip_mux_clk_ops.set_parent;
|
||||
}
|
||||
}
|
||||
|
||||
if (rk_cell->gate_offset >= 0)
|
||||
{
|
||||
half_divider_cell->ops.enable = rockchip_gate_clk_ops.enable;
|
||||
half_divider_cell->ops.disable = rockchip_gate_clk_ops.disable;
|
||||
half_divider_cell->ops.is_enabled = rockchip_gate_clk_ops.is_enabled;
|
||||
half_divider_cell->ops.recalc_rate = clk_div_recalc_rate;
|
||||
half_divider_cell->ops.round_rate = clk_div_round_rate;
|
||||
half_divider_cell->ops.set_rate = clk_div_set_rate;
|
||||
}
|
||||
|
||||
if (rk_cell->div_width > 0)
|
||||
{
|
||||
half_divider_cell->ops.set_rate = clk_div_set_rate;
|
||||
}
|
||||
}
|
||||
126
bsp/rockchip/dm/clk/clk-rk-half-divider.h
Executable file
126
bsp/rockchip/dm/clk/clk-rk-half-divider.h
Executable file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#ifndef __CLK_RK_HALF_DIVIDER_H__
|
||||
#define __CLK_RK_HALF_DIVIDER_H__
|
||||
|
||||
#include "clk-rk.h"
|
||||
|
||||
struct rockchip_half_divider_clk_cell
|
||||
{
|
||||
struct rockchip_clk_cell rk_cell;
|
||||
|
||||
struct rt_clk_ops ops;
|
||||
};
|
||||
|
||||
#define COMPOSITE_HALFDIV(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw, df, go, gs, gf) \
|
||||
(void *)&(struct rockchip_half_divider_clk_cell) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.parent_names = pnames, \
|
||||
.rk_cell.cell.parents_nr = RT_ARRAY_SIZE(pnames), \
|
||||
.rk_cell.cell.flags = f, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.muxdiv_offset = mo, \
|
||||
.rk_cell.mux_shift = ms, \
|
||||
.rk_cell.mux_width = mw, \
|
||||
.rk_cell.mux_flags = mf, \
|
||||
.rk_cell.div_shift = ds, \
|
||||
.rk_cell.div_width = dw, \
|
||||
.rk_cell.div_flags = df, \
|
||||
.rk_cell.gate_offset = go, \
|
||||
.rk_cell.gate_shift = gs, \
|
||||
.rk_cell.gate_flags = gf, \
|
||||
.rk_cell.init = rockchip_half_divider_clk_cell_init,\
|
||||
}
|
||||
|
||||
#define COMPOSITE_HALFDIV_OFFSET(_id, cname, pnames, f, mo, ms, mw, mf, do, ds, dw, df, go, gs, gf) \
|
||||
(void *)&(struct rockchip_half_divider_clk_cell) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.parent_names = pnames, \
|
||||
.rk_cell.cell.parents_nr = RT_ARRAY_SIZE(pnames), \
|
||||
.rk_cell.cell.flags = f, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.muxdiv_offset = mo, \
|
||||
.rk_cell.mux_shift = ms, \
|
||||
.rk_cell.mux_width = mw, \
|
||||
.rk_cell.mux_flags = mf, \
|
||||
.rk_cell.div_offset = do, \
|
||||
.rk_cell.div_shift = ds, \
|
||||
.rk_cell.div_width = dw, \
|
||||
.rk_cell.div_flags = df, \
|
||||
.rk_cell.gate_offset = go, \
|
||||
.rk_cell.gate_shift = gs, \
|
||||
.rk_cell.gate_flags = gf, \
|
||||
.rk_cell.init = rockchip_half_divider_clk_cell_init,\
|
||||
}
|
||||
|
||||
#define COMPOSITE_NOGATE_HALFDIV(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw, df) \
|
||||
(void *)&(struct rockchip_half_divider_clk_cell) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.parent_names = pnames, \
|
||||
.rk_cell.cell.parents_nr = RT_ARRAY_SIZE(pnames), \
|
||||
.rk_cell.cell.flags = f, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.muxdiv_offset = mo, \
|
||||
.rk_cell.mux_shift = ms, \
|
||||
.rk_cell.mux_width = mw, \
|
||||
.rk_cell.mux_flags = mf, \
|
||||
.rk_cell.div_shift = ds, \
|
||||
.rk_cell.div_width = dw, \
|
||||
.rk_cell.div_flags = df, \
|
||||
.rk_cell.gate_offset = -1, \
|
||||
.rk_cell.init = rockchip_half_divider_clk_cell_init,\
|
||||
}
|
||||
|
||||
#define COMPOSITE_NOMUX_HALFDIV(_id, cname, pname, f, mo, ds, dw, df, go, gs, gf) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.parent_name = pname, \
|
||||
.rk_cell.cell.parents_nr = 1, \
|
||||
.rk_cell.cell.flags = f, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.muxdiv_offset = mo, \
|
||||
.rk_cell.div_shift = ds, \
|
||||
.rk_cell.div_width = dw, \
|
||||
.rk_cell.div_flags = df, \
|
||||
.rk_cell.gate_offset = go, \
|
||||
.rk_cell.gate_shift = gs, \
|
||||
.rk_cell.gate_flags = gf, \
|
||||
.rk_cell.init = rockchip_half_divider_clk_cell_init,\
|
||||
}
|
||||
|
||||
#define DIV_HALF(_id, cname, pname, f, o, s, w, df) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.parent_name = pname, \
|
||||
.rk_cell.cell.parents_nr = 1, \
|
||||
.rk_cell.cell.flags = f, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.muxdiv_offset = o, \
|
||||
.rk_cell.div_shift = s, \
|
||||
.rk_cell.div_width = w, \
|
||||
.rk_cell.div_flags = df, \
|
||||
.rk_cell.gate_offset = -1, \
|
||||
.rk_cell.init = rockchip_half_divider_clk_cell_init,\
|
||||
}
|
||||
|
||||
rt_inline struct rockchip_half_divider_clk_cell *cell_to_rockchip_half_divider_clk_cell(struct rt_clk_cell *cell)
|
||||
{
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
return rt_container_of(rk_cell, struct rockchip_half_divider_clk_cell, rk_cell);
|
||||
}
|
||||
|
||||
void rockchip_half_divider_clk_cell_init(struct rockchip_clk_cell *rk_cell);
|
||||
|
||||
#endif /* __CLK_RK_HALF_DIVIDER_H__ */
|
||||
87
bsp/rockchip/rk3500/driver/clk/clk-mmc-phase.c → bsp/rockchip/dm/clk/clk-rk-mmc-phase.c
Normal file → Executable file
87
bsp/rockchip/rk3500/driver/clk/clk-mmc-phase.c → bsp/rockchip/dm/clk/clk-rk-mmc-phase.c
Normal file → Executable file
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@@ -8,10 +8,11 @@
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#define ROCKCHIP_MMC_DELAY_SEL RT_BIT(11)
|
||||
#define ROCKCHIP_MMC_DEGREE_OFFSET 1
|
||||
#define ROCKCHIP_MMC_DEGREE_MASK (0x3 << ROCKCHIP_MMC_DEGREE_OFFSET)
|
||||
#define ROCKCHIP_MMC_DELAYNUM_OFFSET 3
|
||||
#include "clk-rk-mmc-phase.h"
|
||||
|
||||
#define ROCKCHIP_MMC_DELAY_SEL RT_BIT(10)
|
||||
#define ROCKCHIP_MMC_DEGREE_MASK 0x3
|
||||
#define ROCKCHIP_MMC_DELAYNUM_OFFSET 2
|
||||
#define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
|
||||
/*
|
||||
* Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
|
||||
@@ -19,20 +20,24 @@
|
||||
*/
|
||||
#define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
|
||||
|
||||
#define PSECS_PER_SEC 1000000000000LL
|
||||
#define PSECS_PER_SEC 1000000000000LL
|
||||
|
||||
#define RK3288_MMC_CLKGEN_DIV 2
|
||||
#define RK3288_MMC_CLKGEN_DIV 2
|
||||
|
||||
rt_inline rt_ubase_t rk_clk_mmc_recalc(rt_ubase_t parent_rate)
|
||||
static rt_ubase_t rockchip_mmc_recalc(struct rt_clk_cell *cell, rt_ubase_t parent_rate)
|
||||
{
|
||||
return parent_rate / RK3288_MMC_CLKGEN_DIV;
|
||||
}
|
||||
|
||||
static rt_err_t rk_clk_mmc_set_phase(rt_ubase_t rate, void *reg, int shift,
|
||||
int degrees)
|
||||
static rt_err_t rockchip_mmc_set_phase(struct rt_clk_cell *cell, int degrees)
|
||||
{
|
||||
rt_ubase_t rate;
|
||||
rt_uint32_t raw_value, delay;
|
||||
rt_uint8_t nineties, remainder, delay_num;
|
||||
struct rockchip_mmc_clk_cell *mmc_cell = cell_to_rockchip_mmc_clk_cell(cell);
|
||||
struct rockchip_clk_cell *rk_cell = &mmc_cell->rk_cell;
|
||||
|
||||
rate = rt_clk_cell_get_rate(cell);
|
||||
|
||||
/*
|
||||
* The below calculation is based on the output clock from
|
||||
@@ -48,8 +53,6 @@ static rt_err_t rk_clk_mmc_set_phase(rt_ubase_t rate, void *reg, int shift,
|
||||
*/
|
||||
if (!rate)
|
||||
{
|
||||
LOG_E("Invalid CLK rate in phase setting");
|
||||
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
@@ -81,23 +84,30 @@ static rt_err_t rk_clk_mmc_set_phase(rt_ubase_t rate, void *reg, int shift,
|
||||
*/
|
||||
delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
|
||||
delay *= remainder;
|
||||
delay = RT_DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
|
||||
(ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
|
||||
delay = RT_DIV_ROUND_CLOSEST(delay,
|
||||
(rate / 1000) * 36 * (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
|
||||
|
||||
delay_num = (rt_uint8_t)rt_min_t(rt_uint32_t, delay, 255);
|
||||
|
||||
raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
|
||||
raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
|
||||
raw_value |= nineties;
|
||||
HWREG32(reg) = HIWORD_UPDATE(raw_value, 0x07ff, shift);
|
||||
|
||||
HWREG32(rk_cell->provider->reg_base + rk_cell->muxdiv_offset) =
|
||||
HIWORD_UPDATE(raw_value, 0x07ff, rk_cell->div_shift);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_base_t rk_clk_mmc_get_phase(rt_ubase_t rate, void *reg, int shift)
|
||||
static rt_base_t rockchip_mmc_get_phase(struct rt_clk_cell *cell)
|
||||
{
|
||||
rt_ubase_t rate;
|
||||
rt_uint16_t degrees;
|
||||
rt_uint32_t raw_value, delay_num = 0;
|
||||
struct rockchip_mmc_clk_cell *mmc_cell = cell_to_rockchip_mmc_clk_cell(cell);
|
||||
struct rockchip_clk_cell *rk_cell = &mmc_cell->rk_cell;
|
||||
|
||||
rate = rt_clk_cell_get_rate(cell);
|
||||
|
||||
/* Constant signal, no measurable phase shift */
|
||||
if (!rate)
|
||||
@@ -105,14 +115,14 @@ static rt_base_t rk_clk_mmc_get_phase(rt_ubase_t rate, void *reg, int shift)
|
||||
return 0;
|
||||
}
|
||||
|
||||
raw_value = HWREG32(reg) >> shift;
|
||||
raw_value = HWREG32(rk_cell->provider->reg_base + rk_cell->muxdiv_offset) >> rk_cell->div_shift;
|
||||
|
||||
degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
|
||||
|
||||
if (raw_value & ROCKCHIP_MMC_DELAY_SEL)
|
||||
{
|
||||
/* degrees/delaynum * 1000000 */
|
||||
rt_ubase_t factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
|
||||
36 * (rate / 10000);
|
||||
rt_ubase_t factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) * 36 * (rate / 10000);
|
||||
|
||||
delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
|
||||
delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
|
||||
@@ -121,3 +131,42 @@ static rt_base_t rk_clk_mmc_get_phase(rt_ubase_t rate, void *reg, int shift)
|
||||
|
||||
return degrees % 360;
|
||||
}
|
||||
|
||||
const struct rt_clk_ops rockchip_mmc_clk_ops =
|
||||
{
|
||||
.recalc_rate = rockchip_mmc_recalc,
|
||||
.set_phase = rockchip_mmc_set_phase,
|
||||
.get_phase = rockchip_mmc_get_phase,
|
||||
};
|
||||
|
||||
static rt_err_t rockchip_mmc_clk_rate_notify(struct rt_clk_notifier *notifier,
|
||||
rt_ubase_t msg, rt_ubase_t old_rate, rt_ubase_t new_rate)
|
||||
{
|
||||
struct rockchip_mmc_clk_cell *mmc_cell = rt_container_of(notifier, struct rockchip_mmc_clk_cell, notifier);
|
||||
|
||||
if (old_rate <= new_rate)
|
||||
{
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
if (msg == RT_CLK_MSG_PRE_RATE_CHANGE)
|
||||
{
|
||||
mmc_cell->cached_phase = rockchip_mmc_get_phase(&mmc_cell->rk_cell.cell);
|
||||
}
|
||||
else if (mmc_cell->cached_phase != -RT_EINVAL && msg == RT_CLK_MSG_POST_RATE_CHANGE)
|
||||
{
|
||||
rockchip_mmc_set_phase(&mmc_cell->rk_cell.cell, mmc_cell->cached_phase);
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
void rockchip_mmc_clk_cell_setup(struct rockchip_clk_cell *rk_cell)
|
||||
{
|
||||
struct rt_clk_cell *cell = &rk_cell->cell;
|
||||
struct rockchip_mmc_clk_cell *mmc_cell = cell_to_rockchip_mmc_clk_cell(cell);
|
||||
|
||||
mmc_cell->notifier.callback = rockchip_mmc_clk_rate_notify;
|
||||
|
||||
rt_clk_notifier_register(rt_clk_cell_get_clk(cell, RT_NULL), &mmc_cell->notifier);
|
||||
}
|
||||
48
bsp/rockchip/dm/clk/clk-rk-mmc-phase.h
Executable file
48
bsp/rockchip/dm/clk/clk-rk-mmc-phase.h
Executable file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#ifndef __CLK_RK_MMC_PHASE_H__
|
||||
#define __CLK_RK_MMC_PHASE_H__
|
||||
|
||||
#include "clk-rk.h"
|
||||
|
||||
struct rockchip_mmc_clk_cell
|
||||
{
|
||||
struct rockchip_clk_cell rk_cell;
|
||||
|
||||
int cached_phase;
|
||||
struct rt_clk_notifier notifier;
|
||||
};
|
||||
|
||||
#define MMC(_id, cname, pname, offset, shift) \
|
||||
(void *)&(struct rockchip_mmc_clk_cell) \
|
||||
{ \
|
||||
.rk_cell.cell.name = cname, \
|
||||
.rk_cell.cell.ops = &rockchip_mmc_clk_ops, \
|
||||
.rk_cell.cell.parent_name = pname, \
|
||||
.rk_cell.cell.parents_nr = 1, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.muxdiv_offset = offset, \
|
||||
.rk_cell.div_shift = shift, \
|
||||
.rk_cell.setup = rockchip_mmc_clk_cell_setup, \
|
||||
}
|
||||
|
||||
extern const struct rt_clk_ops rockchip_mmc_clk_ops;
|
||||
|
||||
rt_inline struct rockchip_mmc_clk_cell *cell_to_rockchip_mmc_clk_cell(struct rt_clk_cell *cell)
|
||||
{
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
return rt_container_of(rk_cell, struct rockchip_mmc_clk_cell, rk_cell);
|
||||
}
|
||||
|
||||
void rockchip_mmc_clk_cell_setup(struct rockchip_clk_cell *rk_cell);
|
||||
|
||||
#endif /* __CLK_RK_MMC_PHASE_H__ */
|
||||
159
bsp/rockchip/dm/clk/clk-rk-mux.c
Executable file
159
bsp/rockchip/dm/clk/clk-rk-mux.c
Executable file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include "clk-rk-mux.h"
|
||||
|
||||
rt_inline rt_uint32_t clk_mux_readl(struct rockchip_clk_cell *rk_cell)
|
||||
{
|
||||
void *base = rk_cell->provider->reg_base;
|
||||
|
||||
if (rk_cell->mux_flags & CLK_MUX_BIG_ENDIAN)
|
||||
{
|
||||
return rt_be32_to_cpu(HWREG32(base + rk_cell->muxdiv_offset));
|
||||
}
|
||||
|
||||
return HWREG32(base + rk_cell->muxdiv_offset);
|
||||
}
|
||||
|
||||
rt_inline void clk_mux_writel(struct rockchip_clk_cell *rk_cell, rt_uint32_t val)
|
||||
{
|
||||
void *base = rk_cell->provider->reg_base;
|
||||
|
||||
if (rk_cell->mux_flags & CLK_MUX_BIG_ENDIAN)
|
||||
{
|
||||
HWREG32(base + rk_cell->muxdiv_offset) = rt_cpu_to_be32(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
HWREG32(base + rk_cell->muxdiv_offset) = val;
|
||||
}
|
||||
}
|
||||
|
||||
static int clk_mux_val_to_index(struct rt_clk_cell *cell,
|
||||
const rt_uint32_t *table, rt_uint32_t flags, rt_uint32_t val)
|
||||
{
|
||||
int num_parents = cell->parents_nr;
|
||||
|
||||
if (table)
|
||||
{
|
||||
for (int i = 0; i < num_parents; ++i)
|
||||
{
|
||||
if (table[i] == val)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
if (val && (flags & CLK_MUX_INDEX_BIT))
|
||||
{
|
||||
val = __rt_ffs(val) - 1;
|
||||
}
|
||||
|
||||
if (val && (flags & CLK_MUX_INDEX_ONE))
|
||||
{
|
||||
--val;
|
||||
}
|
||||
|
||||
if (val >= num_parents)
|
||||
{
|
||||
return -RT_EINVAL;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static rt_uint32_t clk_mux_index_to_val(const rt_uint32_t *table, rt_uint32_t flags, rt_uint8_t index)
|
||||
{
|
||||
rt_uint32_t val = index;
|
||||
|
||||
if (table)
|
||||
{
|
||||
val = table[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flags & CLK_MUX_INDEX_BIT)
|
||||
{
|
||||
val = 1 << index;
|
||||
}
|
||||
|
||||
if (flags & CLK_MUX_INDEX_ONE)
|
||||
{
|
||||
val++;
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static rt_err_t rockchip_mux_clk_set_parent(struct rt_clk_cell *cell, rt_uint8_t index)
|
||||
{
|
||||
rt_uint32_t val, reg;
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
val = clk_mux_index_to_val(rk_cell->mux_table, rk_cell->mux_flags, index);
|
||||
|
||||
if (rk_cell->mux_flags & CLK_MUX_HIWORD_MASK)
|
||||
{
|
||||
reg = rk_cell->mux_mask << (rk_cell->mux_shift + 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
reg = clk_mux_readl(rk_cell);
|
||||
reg &= ~(rk_cell->mux_mask << rk_cell->mux_shift);
|
||||
}
|
||||
val = val << rk_cell->mux_shift;
|
||||
reg |= val;
|
||||
clk_mux_writel(rk_cell, reg);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_uint8_t rockchip_mux_clk_get_parent(struct rt_clk_cell *cell)
|
||||
{
|
||||
rt_uint32_t val;
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
val = clk_mux_readl(rk_cell) >> rk_cell->mux_shift;
|
||||
val &= rk_cell->mux_mask;
|
||||
|
||||
return clk_mux_val_to_index(cell, rk_cell->mux_table, rk_cell->mux_flags, val);
|
||||
}
|
||||
|
||||
const struct rt_clk_ops rockchip_mux_clk_ops =
|
||||
{
|
||||
.set_parent = rockchip_mux_clk_set_parent,
|
||||
.get_parent = rockchip_mux_clk_get_parent,
|
||||
};
|
||||
|
||||
const struct rt_clk_ops rockchip_mux_ro_clk_ops =
|
||||
{
|
||||
.get_parent = rockchip_mux_clk_get_parent,
|
||||
};
|
||||
|
||||
void rockchip_mux_clk_cell_init(struct rockchip_clk_cell *rk_cell)
|
||||
{
|
||||
rk_cell->mux_mask = RT_BIT(rk_cell->mux_width) - 1;
|
||||
|
||||
if (!rk_cell->cell.ops)
|
||||
{
|
||||
if (!((rk_cell->mux_flags & CLK_MUX_READ_ONLY)))
|
||||
{
|
||||
rk_cell->cell.ops = &rockchip_mux_clk_ops;
|
||||
}
|
||||
else
|
||||
{
|
||||
rk_cell->cell.ops = &rockchip_mux_ro_clk_ops;
|
||||
}
|
||||
}
|
||||
}
|
||||
57
bsp/rockchip/dm/clk/clk-rk-mux.h
Executable file
57
bsp/rockchip/dm/clk/clk-rk-mux.h
Executable file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#ifndef __CLK_RK_MUX_H__
|
||||
#define __CLK_RK_MUX_H__
|
||||
|
||||
#include "clk-rk.h"
|
||||
|
||||
#define MUX_RAW(_id, cname, pnames, f, o, s, w, mf) \
|
||||
{ \
|
||||
.cell.name = cname, \
|
||||
.cell.parent_names = pnames, \
|
||||
.cell.parents_nr = RT_ARRAY_SIZE(pnames), \
|
||||
.cell.flags = f, \
|
||||
.id = _id, \
|
||||
.muxdiv_offset = o, \
|
||||
.mux_shift = s, \
|
||||
.mux_width = w, \
|
||||
.mux_flags = mf, \
|
||||
.gate_offset = -1, \
|
||||
.init = rockchip_mux_clk_cell_init, \
|
||||
}
|
||||
|
||||
#define MUX(_id, cname, pnames, f, o, s, w, mf) \
|
||||
(void *)&(struct rockchip_clk_cell)MUX_RAW(_id, cname, pnames, f, o, s, w, mf)
|
||||
|
||||
#define MUXTBL_RAW(_id, cname, pnames, f, o, s, w, mf, mt) \
|
||||
{ \
|
||||
.cell.name = cname, \
|
||||
.cell.parent_names = pname, \
|
||||
.cell.parents_nr = RT_ARRAY_SIZE(pnames), \
|
||||
.cell.flags = f, \
|
||||
.id = _id, \
|
||||
.muxdiv_offset = o, \
|
||||
.mux_shift = s, \
|
||||
.mux_width = w, \
|
||||
.mux_flags = mf, \
|
||||
.gate_offset = -1, \
|
||||
.mux_table = mt, \
|
||||
.init = rockchip_mux_clk_cell_init, \
|
||||
}
|
||||
|
||||
#define MUXTBL(_id, cname, pnames, f, o, s, w, mf, mt) \
|
||||
(void *)&(struct rockchip_clk_cell)MUXTBL_RAW(_id, cname, pnames, f, o, s, w, mf, mt)
|
||||
|
||||
extern const struct rt_clk_ops rockchip_mux_clk_ops, rockchip_mux_ro_clk_ops;
|
||||
|
||||
void rockchip_mux_clk_cell_init(struct rockchip_clk_cell *rk_cell);
|
||||
|
||||
#endif /* __CLK_RK_MUX_H__ */
|
||||
85
bsp/rockchip/dm/clk/clk-rk-muxgrf.c
Executable file
85
bsp/rockchip/dm/clk/clk-rk-muxgrf.c
Executable file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include "clk-rk-muxgrf.h"
|
||||
|
||||
static rt_err_t rockchip_muxgrf_set_parent_common(struct rt_clk_cell *cell, struct rt_syscon *grf,
|
||||
rt_uint8_t index)
|
||||
{
|
||||
rt_uint32_t mask, val;
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
mask = RT_GENMASK(rk_cell->mux_width + rk_cell->mux_shift - 1, rk_cell->mux_shift);
|
||||
|
||||
val = index;
|
||||
val <<= rk_cell->mux_shift;
|
||||
|
||||
if (rk_cell->mux_flags & CLK_MUX_HIWORD_MASK)
|
||||
{
|
||||
return rt_syscon_write(grf, rk_cell->muxdiv_offset, val | (mask << 16));
|
||||
}
|
||||
|
||||
return rt_syscon_update_bits(grf, rk_cell->muxdiv_offset, mask, val);
|
||||
}
|
||||
|
||||
static rt_uint8_t rockchip_muxgrf_get_parent_common(struct rt_clk_cell *cell, struct rt_syscon *grf)
|
||||
{
|
||||
rt_uint32_t mask, val;
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
mask = RT_GENMASK(rk_cell->mux_width - 1, 0);
|
||||
|
||||
rt_syscon_read(grf, rk_cell->muxdiv_offset, &val);
|
||||
|
||||
val >>= rk_cell->mux_shift;
|
||||
val &= mask;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static rt_err_t rockchip_muxgrf_set_parent(struct rt_clk_cell *cell, rt_uint8_t index)
|
||||
{
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
return rockchip_muxgrf_set_parent_common(cell, rk_cell->provider->grf, index);
|
||||
}
|
||||
|
||||
static rt_uint8_t rockchip_muxgrf_get_parent(struct rt_clk_cell *cell)
|
||||
{
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
return rockchip_muxgrf_get_parent_common(cell, rk_cell->provider->grf);
|
||||
}
|
||||
|
||||
const struct rt_clk_ops rockchip_muxgrf_clk_ops =
|
||||
{
|
||||
.set_parent = rockchip_muxgrf_set_parent,
|
||||
.get_parent = rockchip_muxgrf_get_parent,
|
||||
};
|
||||
|
||||
static rt_err_t rockchip_muxpmugrf_set_parent(struct rt_clk_cell *cell, rt_uint8_t index)
|
||||
{
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
return rockchip_muxgrf_set_parent_common(cell, rk_cell->provider->pmugrf, index);
|
||||
}
|
||||
|
||||
static rt_uint8_t rockchip_muxpmugrf_get_parent(struct rt_clk_cell *cell)
|
||||
{
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
return rockchip_muxgrf_get_parent_common(cell, rk_cell->provider->pmugrf);
|
||||
}
|
||||
|
||||
const struct rt_clk_ops rockchip_muxpmugrf_clk_ops =
|
||||
{
|
||||
.set_parent = rockchip_muxpmugrf_set_parent,
|
||||
.get_parent = rockchip_muxpmugrf_get_parent,
|
||||
};
|
||||
50
bsp/rockchip/dm/clk/clk-rk-muxgrf.h
Executable file
50
bsp/rockchip/dm/clk/clk-rk-muxgrf.h
Executable file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#ifndef __CLK_RK_MUXGRF_H__
|
||||
#define __CLK_RK_MUXGRF_H__
|
||||
|
||||
#include "clk-rk.h"
|
||||
|
||||
#define MUXGRF(_id, cname, pnames, f, o, s, w, mf) \
|
||||
(void *)&(struct rockchip_clk_cell) \
|
||||
{ \
|
||||
.cell.name = cname, \
|
||||
.cell.ops = &rockchip_muxgrf_clk_ops, \
|
||||
.cell.parent_names = pnames, \
|
||||
.cell.parents_nr = RT_ARRAY_SIZE(pnames), \
|
||||
.cell.flags = f, \
|
||||
.id = _id, \
|
||||
.muxdiv_offset = o, \
|
||||
.mux_shift = s, \
|
||||
.mux_width = w, \
|
||||
.mux_flags = mf, \
|
||||
.gate_offset = -1, \
|
||||
}
|
||||
|
||||
#define MUXPMUGRF(_id, cname, pnames, f, o, s, w, mf) \
|
||||
(void *)&(struct rockchip_clk_cell) \
|
||||
{ \
|
||||
.cell.name = cname, \
|
||||
.cell.ops = &rockchip_muxpmugrf_clk_ops, \
|
||||
.cell.parent_names = pnames, \
|
||||
.cell.parents_nr = RT_ARRAY_SIZE(pnames), \
|
||||
.cell.flags = f, \
|
||||
.id = _id, \
|
||||
.muxdiv_offset = o, \
|
||||
.mux_shift = s, \
|
||||
.mux_width = w, \
|
||||
.mux_flags = mf, \
|
||||
.gate_offset = -1, \
|
||||
}
|
||||
|
||||
extern const struct rt_clk_ops rockchip_muxgrf_clk_ops, rockchip_muxpmugrf_clk_ops;
|
||||
|
||||
#endif /* __CLK_RK_MUXGRF_H__ */
|
||||
1546
bsp/rockchip/dm/clk/clk-rk-pll.c
Executable file
1546
bsp/rockchip/dm/clk/clk-rk-pll.c
Executable file
File diff suppressed because it is too large
Load Diff
144
bsp/rockchip/dm/clk/clk-rk-pll.h
Executable file
144
bsp/rockchip/dm/clk/clk-rk-pll.h
Executable file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#ifndef __CLK_RK_PLL_H__
|
||||
#define __CLK_RK_PLL_H__
|
||||
|
||||
#include "clk-rk.h"
|
||||
|
||||
enum rockchip_pll_type
|
||||
{
|
||||
pll_type_rk3036,
|
||||
pll_type_rk3066,
|
||||
pll_type_rk3328,
|
||||
pll_type_rk3399,
|
||||
pll_type_rk3588,
|
||||
pll_type_rk3588_core,
|
||||
pll_type_rk3588_ddr,
|
||||
};
|
||||
|
||||
struct rockchip_pll_rate_table
|
||||
{
|
||||
rt_ubase_t rate;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/* For RK3066 */
|
||||
rt_uint32_t nr;
|
||||
rt_uint32_t nf;
|
||||
rt_uint32_t no;
|
||||
rt_uint32_t nb;
|
||||
};
|
||||
struct
|
||||
{
|
||||
/* For RK3036/RK3399 */
|
||||
rt_uint32_t fbdiv;
|
||||
rt_uint32_t postdiv1;
|
||||
rt_uint32_t refdiv;
|
||||
rt_uint32_t postdiv2;
|
||||
rt_uint32_t dsmpd;
|
||||
rt_uint32_t frac;
|
||||
};
|
||||
struct
|
||||
{
|
||||
/* For RK3588 */
|
||||
rt_uint32_t m;
|
||||
rt_uint32_t p;
|
||||
rt_uint32_t s;
|
||||
rt_uint32_t k;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#define RK3066_PLL_RATE(_rate, _nr, _nf, _no) \
|
||||
{ \
|
||||
.rate = _rate##U, \
|
||||
.nr = _nr, \
|
||||
.nf = _nf, \
|
||||
.no = _no, \
|
||||
.nb = ((_nf) < 2) ? 1 : (_nf) >> 1, \
|
||||
}
|
||||
|
||||
#define RK3036_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac) \
|
||||
{ \
|
||||
.rate = _rate##U, \
|
||||
.fbdiv = _fbdiv, \
|
||||
.postdiv1 = _postdiv1, \
|
||||
.refdiv = _refdiv, \
|
||||
.postdiv2 = _postdiv2, \
|
||||
.dsmpd = _dsmpd, \
|
||||
.frac = _frac, \
|
||||
}
|
||||
|
||||
#define RK3588_PLL_RATE(_rate, _p, _m, _s, _k) \
|
||||
{ \
|
||||
.rate = _rate##U, \
|
||||
.p = _p, \
|
||||
.m = _m, \
|
||||
.s = _s, \
|
||||
.k = _k, \
|
||||
}
|
||||
|
||||
struct rockchip_pll_clk_cell
|
||||
{
|
||||
struct rockchip_clk_cell rk_cell;
|
||||
|
||||
enum rockchip_pll_type type;
|
||||
|
||||
int con_offset;
|
||||
int mode_offset;
|
||||
int mode_shift;
|
||||
int lock_shift;
|
||||
int grf_lock_offset;
|
||||
|
||||
int sel;
|
||||
rt_ubase_t scaling;
|
||||
|
||||
#define ROCKCHIP_PLL_SYNC_RATE RT_BIT(0)
|
||||
#define ROCKCHIP_PLL_FIXED_MODE RT_BIT(1)
|
||||
#define ROCKCHIP_PLL_ALLOW_POWER_DOWN RT_BIT(2)
|
||||
rt_uint8_t flags;
|
||||
struct rockchip_pll_rate_table *rate_table;
|
||||
};
|
||||
|
||||
#define PLL_RAW(_type, _id, _name, _pnames, _pnames_nr, _flags, _con, _mode, _mshift, _lshift, _glock, _pflags, _rtable) \
|
||||
{ \
|
||||
.rk_cell.cell.name = _name, \
|
||||
.rk_cell.cell.parent_names = (void *)_pnames, \
|
||||
.rk_cell.cell.parents_nr = _pnames_nr, \
|
||||
.rk_cell.cell.flags = RT_CLK_F_GET_RATE_NOCACHE | _flags, \
|
||||
.rk_cell.id = _id, \
|
||||
.rk_cell.init = rockchip_pll_clk_cell_init, \
|
||||
.rk_cell.setup = rockchip_pll_clk_cell_setup, \
|
||||
.type = _type, \
|
||||
.con_offset = _con, \
|
||||
.mode_offset = _mode, \
|
||||
.mode_shift = _mshift, \
|
||||
.lock_shift = _lshift, \
|
||||
.grf_lock_offset = _glock, \
|
||||
.flags = _pflags, \
|
||||
.rate_table = _rtable, \
|
||||
}
|
||||
|
||||
#define PLL(_type, _id, _name, _pnames, _pnames_nr, _flags, _con, _mode, _mshift, _lshift, _glock, _pflags, _rtable) \
|
||||
(void *)&(struct rockchip_pll_clk_cell)PLL_RAW(_type, _id, _name, _pnames, _pnames_nr, _flags, _con, _mode, _mshift, _lshift, _glock, _pflags, _rtable)
|
||||
|
||||
rt_inline struct rockchip_pll_clk_cell *cell_to_rockchip_pll_clk_cell(struct rt_clk_cell *cell)
|
||||
{
|
||||
struct rockchip_clk_cell *rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
return rt_container_of(rk_cell, struct rockchip_pll_clk_cell, rk_cell);
|
||||
}
|
||||
|
||||
void rockchip_pll_clk_cell_init(struct rockchip_clk_cell *rk_cell);
|
||||
void rockchip_pll_clk_cell_setup(struct rockchip_clk_cell *rk_cell);
|
||||
|
||||
#endif /* __CLK_RK_PLL_H__ */
|
||||
169
bsp/rockchip/dm/clk/clk-rk.c
Executable file
169
bsp/rockchip/dm/clk/clk-rk.c
Executable file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include "clk-rk.h"
|
||||
|
||||
int rockchip_gcd(int m, int n)
|
||||
{
|
||||
while (m > 0)
|
||||
{
|
||||
if (n > m)
|
||||
{
|
||||
int t = m;
|
||||
m = n;
|
||||
n = t;
|
||||
}
|
||||
m -= n;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* rational_best_approximation(31415, 10000,
|
||||
* (1 << 8) - 1, (1 << 5) - 1, &n, &d);
|
||||
*
|
||||
* you may look at given_numerator as a fixed point number,
|
||||
* with the fractional part size described in given_denominator.
|
||||
*
|
||||
* for theoretical background, see:
|
||||
* http://en.wikipedia.org/wiki/Continued_fraction
|
||||
*/
|
||||
void rational_best_approximation(rt_ubase_t given_numerator,
|
||||
rt_ubase_t given_denominator,
|
||||
rt_ubase_t max_numerator,
|
||||
rt_ubase_t max_denominator,
|
||||
rt_ubase_t *best_numerator,
|
||||
rt_ubase_t *best_denominator)
|
||||
{
|
||||
rt_ubase_t n, d, n0, d0, n1, d1;
|
||||
|
||||
n = given_numerator;
|
||||
d = given_denominator;
|
||||
n0 = 0;
|
||||
d1 = 0;
|
||||
n1 = 1;
|
||||
d0 = 1;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
rt_ubase_t t, a;
|
||||
|
||||
if (n1 > max_numerator || d1 > max_denominator)
|
||||
{
|
||||
n1 = n0;
|
||||
d1 = d0;
|
||||
break;
|
||||
}
|
||||
if (d == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
t = d;
|
||||
a = n / d;
|
||||
d = n % d;
|
||||
n = t;
|
||||
t = n0 + a * n1;
|
||||
n0 = n1;
|
||||
n1 = t;
|
||||
t = d0 + a * d1;
|
||||
d0 = d1;
|
||||
d1 = t;
|
||||
}
|
||||
*best_numerator = n1;
|
||||
*best_denominator = d1;
|
||||
}
|
||||
|
||||
void rockchip_clk_init(struct rockchip_clk_provider *provider,
|
||||
struct rt_clk_cell **cells, rt_size_t cells_nr)
|
||||
{
|
||||
for (rt_size_t i = 0; i < cells_nr; ++i)
|
||||
{
|
||||
struct rt_clk_cell *cell = cells[i];
|
||||
struct rockchip_clk_cell *rk_cell;
|
||||
|
||||
if (!cell)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
rk_cell->provider = provider;
|
||||
|
||||
if (rk_cell->init)
|
||||
{
|
||||
rk_cell->init(rk_cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rockchip_clk_setup(struct rockchip_clk_provider *provider,
|
||||
struct rt_clk_cell **cells, rt_size_t cells_nr)
|
||||
{
|
||||
for (rt_size_t i = 0; i < cells_nr; ++i)
|
||||
{
|
||||
struct rt_clk_cell *cell = cells[i];
|
||||
struct rockchip_clk_cell *rk_cell;
|
||||
|
||||
if (!cell)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
rk_cell = cell_to_rockchip_clk_cell(cell);
|
||||
|
||||
if (rk_cell->setup)
|
||||
{
|
||||
rk_cell->setup(rk_cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct rockchip_restart
|
||||
{
|
||||
struct rt_device parent;
|
||||
|
||||
rt_uint32_t reg;
|
||||
struct rockchip_clk_provider *provider;
|
||||
void (*callback)(struct rockchip_clk_provider *provider);
|
||||
};
|
||||
|
||||
static rt_err_t rockchip_restart_handler(struct rt_device *dev)
|
||||
{
|
||||
struct rockchip_restart *rdev = rt_container_of(dev, struct rockchip_restart, parent);
|
||||
|
||||
if (rdev->callback)
|
||||
{
|
||||
rdev->callback(rdev->provider);
|
||||
}
|
||||
|
||||
HWREG32(rdev->provider->reg_base + rdev->reg) = 0xfdb9;
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
void rockchip_register_restart_notifier(struct rockchip_clk_provider *provider,
|
||||
rt_uint32_t reg, void (*callback)(struct rockchip_clk_provider *provider))
|
||||
{
|
||||
struct rockchip_restart *rdev = rt_calloc(1, sizeof(*rdev));
|
||||
|
||||
if (!rdev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rdev->reg = reg;
|
||||
rdev->provider = provider;
|
||||
rdev->callback = callback;
|
||||
rt_dm_dev_set_name(&rdev->parent, "RK-CLK");
|
||||
|
||||
rt_dm_power_off_handler(&rdev->parent, RT_DM_POWER_OFF_MODE_RESET,
|
||||
RT_DM_POWER_OFF_PRIO_PLATFORM, rockchip_restart_handler);
|
||||
}
|
||||
107
bsp/rockchip/dm/clk/clk-rk.h
Executable file
107
bsp/rockchip/dm/clk/clk-rk.h
Executable file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#ifndef __CLK_RK_H__
|
||||
#define __CLK_RK_H__
|
||||
|
||||
#include <rockchip.h>
|
||||
|
||||
struct rockchip_clk_provider
|
||||
{
|
||||
void *reg_base;
|
||||
struct rt_syscon *grf;
|
||||
struct rt_syscon *pmugrf;
|
||||
};
|
||||
|
||||
struct clk_div_table
|
||||
{
|
||||
rt_uint32_t val;
|
||||
rt_uint32_t div;
|
||||
};
|
||||
|
||||
struct rockchip_clk_cell
|
||||
{
|
||||
struct rt_clk_cell cell;
|
||||
|
||||
int id;
|
||||
|
||||
int muxdiv_offset;
|
||||
rt_uint8_t mux_shift;
|
||||
rt_uint8_t mux_width;
|
||||
#define CLK_MUX_INDEX_ONE RT_BIT(0)
|
||||
#define CLK_MUX_INDEX_BIT RT_BIT(1)
|
||||
#define CLK_MUX_HIWORD_MASK RT_BIT(2)
|
||||
#define CLK_MUX_READ_ONLY RT_BIT(3)
|
||||
#define CLK_MUX_ROUND_CLOSEST RT_BIT(4)
|
||||
#define CLK_MUX_BIG_ENDIAN RT_BIT(5)
|
||||
rt_uint8_t mux_flags;
|
||||
rt_uint32_t mux_mask;
|
||||
rt_uint32_t *mux_table;
|
||||
|
||||
int div_offset;
|
||||
rt_uint8_t div_shift;
|
||||
rt_uint8_t div_width;
|
||||
#define CLK_DIVIDER_ONE_BASED RT_BIT(0)
|
||||
#define CLK_DIVIDER_POWER_OF_TWO RT_BIT(1)
|
||||
#define CLK_DIVIDER_ALLOW_ZERO RT_BIT(2)
|
||||
#define CLK_DIVIDER_HIWORD_MASK RT_BIT(3)
|
||||
#define CLK_DIVIDER_ROUND_CLOSEST RT_BIT(4)
|
||||
#define CLK_DIVIDER_READ_ONLY RT_BIT(5)
|
||||
#define CLK_DIVIDER_MAX_AT_ZERO RT_BIT(6)
|
||||
#define CLK_DIVIDER_BIG_ENDIAN RT_BIT(7)
|
||||
|
||||
#define CLK_FRAC_DIVIDER_ZERO_BASED RT_BIT(0)
|
||||
#define CLK_FRAC_DIVIDER_BIG_ENDIAN RT_BIT(1)
|
||||
#define CLK_FRAC_DIVIDER_POWER_OF_TWO_PS RT_BIT(2)
|
||||
#define CLK_FRAC_DIVIDER_NO_LIMIT RT_BIT(3)
|
||||
rt_uint8_t div_flags;
|
||||
struct clk_div_table *div_table;
|
||||
|
||||
int gate_offset;
|
||||
rt_uint8_t gate_shift;
|
||||
#define CLK_GATE_SET_TO_DISABLE RT_BIT(0)
|
||||
#define CLK_GATE_HIWORD_MASK RT_BIT(1)
|
||||
#define CLK_GATE_BIG_ENDIAN RT_BIT(2)
|
||||
rt_uint8_t gate_flags;
|
||||
|
||||
struct rockchip_clk_provider *provider;
|
||||
void (*init)(struct rockchip_clk_cell *cell);
|
||||
void (*setup)(struct rockchip_clk_cell *cell);
|
||||
};
|
||||
|
||||
#define cell_to_rockchip_clk_cell(cell) rt_container_of(cell, struct rockchip_clk_cell, cell)
|
||||
|
||||
#define PNAME(x) static const char *const x
|
||||
#define PNAMES(x) PNAME(x)[]
|
||||
|
||||
void rational_best_approximation(rt_ubase_t given_numerator,
|
||||
rt_ubase_t given_denominator,
|
||||
rt_ubase_t max_numerator,
|
||||
rt_ubase_t max_denominator,
|
||||
rt_ubase_t *best_numerator,
|
||||
rt_ubase_t *best_denominator);
|
||||
|
||||
#define ROCKCHIP_SOFTRST_HIWORD_MASK RT_BIT(0)
|
||||
|
||||
int rockchip_gcd(int m, int n);
|
||||
|
||||
void rockchip_clk_init(struct rockchip_clk_provider *provider,
|
||||
struct rt_clk_cell **cells, rt_size_t cells_nr);
|
||||
|
||||
void rockchip_clk_setup(struct rockchip_clk_provider *provider,
|
||||
struct rt_clk_cell **cells, rt_size_t cells_nr);
|
||||
|
||||
rt_err_t rockchip_register_softrst(struct rt_reset_controller *rstcer,
|
||||
struct rt_ofw_node *np, const int *lookup_table, void *regs, rt_uint8_t flags);
|
||||
|
||||
void rockchip_register_restart_notifier(struct rockchip_clk_provider *provider,
|
||||
rt_uint32_t reg, void (*callback)(struct rockchip_clk_provider *provider));
|
||||
|
||||
#endif /* __CLK_RK_H__ */
|
||||
950
bsp/rockchip/dm/clk/clk-rk3308.c
Executable file
950
bsp/rockchip/dm/clk/clk-rk3308.c
Executable file
File diff suppressed because it is too large
Load Diff
1488
bsp/rockchip/dm/clk/clk-rk3568.c
Executable file
1488
bsp/rockchip/dm/clk/clk-rk3568.c
Executable file
File diff suppressed because it is too large
Load Diff
1839
bsp/rockchip/dm/clk/clk-rk3576.c
Executable file
1839
bsp/rockchip/dm/clk/clk-rk3576.c
Executable file
File diff suppressed because it is too large
Load Diff
2166
bsp/rockchip/dm/clk/clk-rk3588.c
Executable file
2166
bsp/rockchip/dm/clk/clk-rk3588.c
Executable file
File diff suppressed because it is too large
Load Diff
203
bsp/rockchip/dm/clk/clk-rk8xx-clkout.c
Executable file
203
bsp/rockchip/dm/clk/clk-rk8xx-clkout.c
Executable file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-11-26 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#define DBG_TAG "clk.rk8xx"
|
||||
#define DBG_LVL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include "rk8xx.h"
|
||||
|
||||
struct rk8xx_clkout
|
||||
{
|
||||
struct rt_clk_node parent;
|
||||
|
||||
struct rk8xx *rk8xx;
|
||||
};
|
||||
|
||||
#define raw_to_rk8xx_clkout(raw) rt_container_of(raw, struct rk8xx_clkout, parent)
|
||||
|
||||
static rt_ubase_t rk808_clkout_recalc_rate(struct rt_clk_cell *cell, rt_ubase_t parent_rate)
|
||||
{
|
||||
return 32768;
|
||||
}
|
||||
|
||||
static const struct rt_clk_ops rk808_clkout1_ops =
|
||||
{
|
||||
.recalc_rate = rk808_clkout_recalc_rate,
|
||||
};
|
||||
|
||||
static rt_err_t rk808_clkout2_enable(struct rt_clk_cell *cell, rt_bool_t enable)
|
||||
{
|
||||
struct rk8xx_clkout *clkout = raw_to_rk8xx_clkout(cell->clk_np);
|
||||
|
||||
return rk8xx_update_bits(clkout->rk8xx, RK808_CLK32OUT_REG,
|
||||
CLK32KOUT2_EN, enable ? CLK32KOUT2_EN : 0);
|
||||
}
|
||||
|
||||
static rt_err_t rk808_clkout2_prepare(struct rt_clk_cell *cell)
|
||||
{
|
||||
return rk808_clkout2_enable(cell, RT_TRUE);
|
||||
}
|
||||
|
||||
static void rk808_clkout2_unprepare(struct rt_clk_cell *cell)
|
||||
{
|
||||
rk808_clkout2_enable(cell, RT_FALSE);
|
||||
}
|
||||
|
||||
static rt_bool_t rk808_clkout2_is_prepared(struct rt_clk_cell *cell)
|
||||
{
|
||||
rt_uint32_t val;
|
||||
struct rk8xx_clkout *clkout = raw_to_rk8xx_clkout(cell->clk_np);
|
||||
|
||||
val = rk8xx_read(clkout->rk8xx, RK808_CLK32OUT_REG);
|
||||
|
||||
if ((rt_err_t)val < 0)
|
||||
{
|
||||
return RT_FALSE;
|
||||
}
|
||||
|
||||
return !!(val & CLK32KOUT2_EN);
|
||||
}
|
||||
|
||||
static const struct rt_clk_ops rk808_clkout2_ops =
|
||||
{
|
||||
.prepare = rk808_clkout2_prepare,
|
||||
.unprepare = rk808_clkout2_unprepare,
|
||||
.is_prepared = rk808_clkout2_is_prepared,
|
||||
.recalc_rate = rk808_clkout_recalc_rate,
|
||||
};
|
||||
|
||||
static rt_err_t rk817_clkout2_enable(struct rt_clk_cell *cell, rt_bool_t enable)
|
||||
{
|
||||
struct rk8xx_clkout *clkout = raw_to_rk8xx_clkout(cell->clk_np);
|
||||
|
||||
return rk8xx_update_bits(clkout->rk8xx, RK817_SYS_CFG(1),
|
||||
RK817_CLK32KOUT2_EN, enable ? RK817_CLK32KOUT2_EN : 0);
|
||||
}
|
||||
|
||||
static rt_err_t rk817_clkout2_prepare(struct rt_clk_cell *cell)
|
||||
{
|
||||
return rk817_clkout2_enable(cell, RT_TRUE);
|
||||
}
|
||||
|
||||
static void rk817_clkout2_unprepare(struct rt_clk_cell *cell)
|
||||
{
|
||||
rk817_clkout2_enable(cell, RT_FALSE);
|
||||
}
|
||||
|
||||
static rt_bool_t rk817_clkout2_is_prepared(struct rt_clk_cell *cell)
|
||||
{
|
||||
rt_uint32_t val;
|
||||
struct rk8xx_clkout *clkout = raw_to_rk8xx_clkout(cell->clk_np);
|
||||
|
||||
val = rk8xx_read(clkout->rk8xx, RK817_SYS_CFG(1));
|
||||
|
||||
if ((rt_err_t)val < 0)
|
||||
{
|
||||
return RT_FALSE;
|
||||
}
|
||||
|
||||
return !!(val & RK817_CLK32KOUT2_EN);
|
||||
}
|
||||
|
||||
static const struct rt_clk_ops rk817_clkout2_ops =
|
||||
{
|
||||
.prepare = rk817_clkout2_prepare,
|
||||
.unprepare = rk817_clkout2_unprepare,
|
||||
.is_prepared = rk817_clkout2_is_prepared,
|
||||
.recalc_rate = rk808_clkout_recalc_rate,
|
||||
};
|
||||
|
||||
static struct rt_clk_cell *rk8xx_clkout_cell[] =
|
||||
{
|
||||
&(struct rt_clk_cell) { .name = "rk808-clkout1" },
|
||||
&(struct rt_clk_cell) { .name = "rk808-clkout2" },
|
||||
};
|
||||
|
||||
static rt_err_t rk8xx_clkout_probe(struct rt_platform_device *pdev)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_clk_cell *cell;
|
||||
struct rt_device *dev = &pdev->parent;
|
||||
struct rk8xx *rk8xx = pdev->priv;
|
||||
struct rk8xx_clkout *clkout = rt_calloc(1, sizeof(*clkout));
|
||||
|
||||
if (!clkout)
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
clkout->rk8xx = rk8xx;
|
||||
|
||||
/* clkout1 */
|
||||
cell = rk8xx_clkout_cell[0];
|
||||
cell->ops = &rk808_clkout1_ops;
|
||||
rt_dm_dev_prop_read_string_index(dev, "clock-output-names", 0, &cell->name);
|
||||
|
||||
/* clkout2 */
|
||||
cell = rk8xx_clkout_cell[1];
|
||||
switch (rk8xx->variant)
|
||||
{
|
||||
case RK809_ID:
|
||||
case RK817_ID:
|
||||
cell->ops = &rk817_clkout2_ops;
|
||||
break;
|
||||
|
||||
/*
|
||||
* For the default case, it match the following PMIC type.
|
||||
* RK805_ID
|
||||
* RK808_ID
|
||||
* RK818_ID
|
||||
*/
|
||||
default:
|
||||
cell->ops = &rk808_clkout2_ops;
|
||||
break;
|
||||
}
|
||||
rt_dm_dev_prop_read_string_index(dev, "clock-output-names", 1, &cell->name);
|
||||
|
||||
if (rt_dm_dev_prop_read_bool(dev, "rockchip,clk-32k-always-on"))
|
||||
{
|
||||
cell->flags |= RT_CLK_F_IS_CRITICAL;
|
||||
}
|
||||
|
||||
clkout->parent.dev = dev;
|
||||
clkout->parent.cells = rk8xx_clkout_cell;
|
||||
clkout->parent.cells_nr = RT_ARRAY_SIZE(rk8xx_clkout_cell);
|
||||
|
||||
if ((err = rt_clk_register(&clkout->parent)))
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
_fail:
|
||||
rt_free(clkout);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct rt_platform_driver rk8xx_clkout_driver =
|
||||
{
|
||||
.name = "rk8xx-clkout",
|
||||
.probe = rk8xx_clkout_probe,
|
||||
};
|
||||
|
||||
static int rk8xx_clkout_register(void)
|
||||
{
|
||||
rt_platform_driver_register(&rk8xx_clkout_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
INIT_SUBSYS_EXPORT(rk8xx_clkout_register);
|
||||
49
bsp/rockchip/rk3500/driver/clk/softrst.c → bsp/rockchip/dm/clk/softrst.c
Normal file → Executable file
49
bsp/rockchip/rk3500/driver/clk/softrst.c → bsp/rockchip/dm/clk/softrst.c
Normal file → Executable file
@@ -1,15 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2022-11-26 GuEe-GUI first version
|
||||
* 2022-3-08 GuEe-GUI the first version
|
||||
*/
|
||||
|
||||
#include "clk-rk.h"
|
||||
|
||||
struct rockchip_softrst
|
||||
{
|
||||
const int *lut;
|
||||
|
||||
void *regs;
|
||||
int num_per_reg;
|
||||
rt_uint8_t flags;
|
||||
@@ -19,11 +23,16 @@ struct rockchip_softrst
|
||||
|
||||
static rt_err_t rockchip_softrst_assert(struct rt_reset_control *rstc)
|
||||
{
|
||||
int bank, offset;
|
||||
int id = rstc->id, bank, offset;
|
||||
struct rockchip_softrst *softrst = rstc->rstcer->priv;
|
||||
|
||||
bank = rstc->id / softrst->num_per_reg;
|
||||
offset = rstc->id % softrst->num_per_reg;
|
||||
if (softrst->lut)
|
||||
{
|
||||
id = softrst->lut[id];
|
||||
}
|
||||
|
||||
bank = id / softrst->num_per_reg;
|
||||
offset = id % softrst->num_per_reg;
|
||||
|
||||
if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK)
|
||||
{
|
||||
@@ -47,15 +56,20 @@ static rt_err_t rockchip_softrst_assert(struct rt_reset_control *rstc)
|
||||
|
||||
static rt_err_t rockchip_softrst_deassert(struct rt_reset_control *rstc)
|
||||
{
|
||||
int bank, offset;
|
||||
int id = rstc->id, bank, offset;
|
||||
struct rockchip_softrst *softrst = rstc->rstcer->priv;
|
||||
|
||||
bank = rstc->id / softrst->num_per_reg;
|
||||
offset = rstc->id % softrst->num_per_reg;
|
||||
if (softrst->lut)
|
||||
{
|
||||
id = softrst->lut[id];
|
||||
}
|
||||
|
||||
bank = id / softrst->num_per_reg;
|
||||
offset = id % softrst->num_per_reg;
|
||||
|
||||
if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK)
|
||||
{
|
||||
HWREG32(softrst->regs + (bank * 4)) = (RT_BIT(offset) << 16);
|
||||
HWREG32(softrst->regs + (bank * 4)) = RT_BIT(offset) << 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -75,12 +89,12 @@ static rt_err_t rockchip_softrst_deassert(struct rt_reset_control *rstc)
|
||||
|
||||
static const struct rt_reset_control_ops rockchip_softrst_ops =
|
||||
{
|
||||
.assert = rockchip_softrst_assert,
|
||||
.deassert = rockchip_softrst_deassert,
|
||||
.assert = rockchip_softrst_assert,
|
||||
.deassert = rockchip_softrst_deassert,
|
||||
};
|
||||
|
||||
static rt_err_t rk_register_softrst(struct rt_reset_controller *rstcer,
|
||||
struct rt_ofw_node *np, void *regs, rt_uint8_t flags)
|
||||
rt_err_t rockchip_register_softrst(struct rt_reset_controller *rstcer,
|
||||
struct rt_ofw_node *np, const int *lookup_table, void *regs, rt_uint8_t flags)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rockchip_softrst *softrst = rt_calloc(1, sizeof(*softrst));
|
||||
@@ -90,16 +104,15 @@ static rt_err_t rk_register_softrst(struct rt_reset_controller *rstcer,
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
rstcer->priv = softrst;
|
||||
|
||||
rt_spin_lock_init(&softrst->lock);
|
||||
|
||||
softrst->lut = lookup_table;
|
||||
softrst->regs = regs;
|
||||
softrst->flags = flags;
|
||||
softrst->num_per_reg = (flags & ROCKCHIP_SOFTRST_HIWORD_MASK) ? 16 : 32;
|
||||
|
||||
rstcer->ofw_node = np;
|
||||
rt_spin_lock_init(&softrst->lock);
|
||||
rstcer->priv = softrst;
|
||||
rstcer->ops = &rockchip_softrst_ops;
|
||||
rstcer->ofw_node = np;
|
||||
|
||||
if ((err = rt_reset_controller_register(rstcer)))
|
||||
{
|
||||
5
bsp/rockchip/dm/hwcrypto/Kconfig
Executable file
5
bsp/rockchip/dm/hwcrypto/Kconfig
Executable file
@@ -0,0 +1,5 @@
|
||||
config RT_HWCRYPTO_RNG_ROCKCHIP
|
||||
bool "Rockchip Random Number Generator support"
|
||||
depends on RT_HWCRYPTO_USING_RNG
|
||||
depends on RT_USING_RESET
|
||||
default n
|
||||
@@ -1,13 +1,12 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
CPPPATH = [cwd]
|
||||
src = []
|
||||
CPPPATH = [cwd + '/../include']
|
||||
|
||||
src = ['core.c', 'early.c']
|
||||
|
||||
if GetDepend(['RT_SERIAL_8250']):
|
||||
src += ['8250-dw.c']
|
||||
src += ['fiq-debugger.c']
|
||||
if GetDepend(['RT_HWCRYPTO_RNG_ROCKCHIP']):
|
||||
src += ['hw-rng-rockchip.c']
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
565
bsp/rockchip/dm/hwcrypto/hw-rng-rockchip.c
Executable file
565
bsp/rockchip/dm/hwcrypto/hw-rng-rockchip.c
Executable file
File diff suppressed because it is too large
Load Diff
3
bsp/rockchip/dm/hwspinlock/Kconfig
Executable file
3
bsp/rockchip/dm/hwspinlock/Kconfig
Executable file
@@ -0,0 +1,3 @@
|
||||
config RT_HWSPINLOCK_ROCKCHIP
|
||||
bool "Rockchip Hardware Spinlock device"
|
||||
default n
|
||||
12
bsp/rockchip/dm/hwspinlock/SConscript
Executable file
12
bsp/rockchip/dm/hwspinlock/SConscript
Executable file
@@ -0,0 +1,12 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = []
|
||||
CPPPATH = [cwd + '/../include', cwd + '/../../../../components/drivers/hwspinlock']
|
||||
|
||||
if GetDepend(['RT_HWSPINLOCK_ROCKCHIP']):
|
||||
src += ['hwspinlock-rockchip.c']
|
||||
|
||||
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
135
bsp/rockchip/dm/hwspinlock/hwspinlock-rockchip.c
Executable file
135
bsp/rockchip/dm/hwspinlock/hwspinlock-rockchip.c
Executable file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2023-09-23 GuEe-GUI first version
|
||||
*/
|
||||
|
||||
#include "hwspinlock_dm.h"
|
||||
|
||||
#define HWSPINLOCK_NUMBER 64
|
||||
#define HWSPINLOCK_STATUS_OFFSET(x) (0x4 * (x))
|
||||
#define HWSPINLOCK_OWNER_ID 0x1
|
||||
|
||||
struct rockchip_hwspinlock
|
||||
{
|
||||
struct rt_hwspinlock_bank parent;
|
||||
|
||||
void *regs;
|
||||
};
|
||||
|
||||
static rt_err_t rockchip_hwspinlock_trylock(struct rt_hwspinlock *hwlock)
|
||||
{
|
||||
void *lock_regs = hwlock->priv;
|
||||
|
||||
HWREG32(lock_regs) = HWSPINLOCK_OWNER_ID;
|
||||
|
||||
/*
|
||||
* Get only first 4bits and compare to HWSPINLOCK_OWNER_ID:
|
||||
* when 4bits is 0, 4bits can be written with new value.
|
||||
* when 4bits is not 0, 4bits cannot be written.
|
||||
* when write data is 0x0000, 4bits clean to 0.
|
||||
*/
|
||||
|
||||
return ((HWREG32(lock_regs) & 0xf) == HWSPINLOCK_OWNER_ID);
|
||||
}
|
||||
|
||||
static void rockchip_hwspinlock_unlock(struct rt_hwspinlock *hwlock)
|
||||
{
|
||||
void *lock_regs = hwlock->priv;
|
||||
|
||||
HWREG32(lock_regs) = 0;
|
||||
}
|
||||
|
||||
static const struct rt_hwspinlock_ops rk_hwspinlock_ops =
|
||||
{
|
||||
.trylock = rockchip_hwspinlock_trylock,
|
||||
.unlock = rockchip_hwspinlock_unlock,
|
||||
};
|
||||
|
||||
static rt_err_t rockchip_hwspinlock_probe(struct rt_platform_device *pdev)
|
||||
{
|
||||
rt_err_t err;
|
||||
struct rt_hwspinlock *hwlock;
|
||||
struct rt_hwspinlock_bank *bank;
|
||||
struct rt_device *dev = &pdev->parent;
|
||||
struct rockchip_hwspinlock *rk_hwspinlock;
|
||||
|
||||
rk_hwspinlock = hwspinlock_bank_alloc(rk_hwspinlock, HWSPINLOCK_NUMBER);
|
||||
|
||||
if (!rk_hwspinlock)
|
||||
{
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
rk_hwspinlock->regs = rt_dm_dev_iomap(dev, 0);
|
||||
|
||||
if (!rk_hwspinlock->regs)
|
||||
{
|
||||
err = -RT_EIO;
|
||||
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
bank = &rk_hwspinlock->parent;
|
||||
hwlock = &bank->locks[0];
|
||||
|
||||
for (int i = 0; i < HWSPINLOCK_NUMBER; ++i, ++hwlock)
|
||||
{
|
||||
hwlock->priv = rk_hwspinlock->regs + HWSPINLOCK_STATUS_OFFSET(i);
|
||||
}
|
||||
|
||||
bank->dev = dev;
|
||||
bank->ops = &rk_hwspinlock_ops;
|
||||
bank->locks_nr = HWSPINLOCK_NUMBER;
|
||||
|
||||
if ((err = rt_hwspinlock_bank_register(bank)))
|
||||
{
|
||||
goto _fail;
|
||||
}
|
||||
|
||||
dev->user_data = rk_hwspinlock;
|
||||
|
||||
return RT_EOK;
|
||||
|
||||
_fail:
|
||||
if (rk_hwspinlock->regs)
|
||||
{
|
||||
rt_iounmap(rk_hwspinlock->regs);
|
||||
}
|
||||
rt_free(rk_hwspinlock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static rt_err_t rockchip_hwspinlock_remove(struct rt_platform_device *pdev)
|
||||
{
|
||||
struct rockchip_hwspinlock *rk_hwspinlock = pdev->parent.user_data;
|
||||
|
||||
rt_hwspinlock_bank_unregister(&rk_hwspinlock->parent);
|
||||
|
||||
rt_iounmap(rk_hwspinlock->regs);
|
||||
|
||||
rt_free(rk_hwspinlock);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static const struct rt_ofw_node_id rockchip_hwspinlock_ofw_ids[] =
|
||||
{
|
||||
{ .compatible = "rockchip,hwspinlock" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct rt_platform_driver rockchip_hwspinlock_driver =
|
||||
{
|
||||
.name = "hwspinlock-rockchip",
|
||||
.ids = rockchip_hwspinlock_ofw_ids,
|
||||
|
||||
.probe = rockchip_hwspinlock_probe,
|
||||
.remove = rockchip_hwspinlock_remove,
|
||||
};
|
||||
RT_PLATFORM_DRIVER_EXPORT(rockchip_hwspinlock_driver);
|
||||
@@ -1,5 +1,3 @@
|
||||
config RT_HWTIMER_ROCKCHIP
|
||||
bool "RockChip Timer"
|
||||
depends on RT_USING_DM
|
||||
depends on RT_USING_HWTIMER
|
||||
default n
|
||||
7
bsp/rockchip/rk3500/driver/hwtimer/SConscript → bsp/rockchip/dm/hwtimer/SConscript
Normal file → Executable file
7
bsp/rockchip/rk3500/driver/hwtimer/SConscript → bsp/rockchip/dm/hwtimer/SConscript
Normal file → Executable file
@@ -1,9 +1,8 @@
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
CPPPATH = [cwd]
|
||||
|
||||
src = []
|
||||
cwd = GetCurrentDir()
|
||||
src = []
|
||||
CPPPATH = [cwd + '/../include']
|
||||
|
||||
if GetDepend(['RT_HWTIMER_ROCKCHIP']):
|
||||
src += ['hwtimer-rockchip_timer.c']
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user