[bsp][rockchip] Port to DM

RK3588/RK3576/RK356x/RK3308

Signed-off-by: GuEe-GUI <2991707448@qq.com>
This commit is contained in:
GuEe-GUI
2026-01-05 17:19:12 +08:00
committed by R b b666
parent f671816aae
commit 45fe9ee96b
191 changed files with 48514 additions and 12368 deletions

View File

@@ -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
View 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

View 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
View 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
View 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')

File diff suppressed because it is too large Load Diff

7
bsp/rockchip/dm/can/Kconfig Executable file
View 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
View 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')

File diff suppressed because it is too large Load Diff

36
bsp/rockchip/dm/clk/Kconfig Executable file
View 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
View 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
View 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);

View 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;
}
}
}

View 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
View 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);
}

View 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__ */

File diff suppressed because it is too large Load Diff

View 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__ */

View 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;
}
}

View 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__ */

View 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);
}
}

View 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
View 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,
};

View 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__ */

View 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;
}
}

View 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__ */

View 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);
}

View 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
View 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;
}
}
}

View 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__ */

View 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,
};

View 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

File diff suppressed because it is too large Load Diff

144
bsp/rockchip/dm/clk/clk-rk-pll.h Executable file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

2166
bsp/rockchip/dm/clk/clk-rk3588.c Executable file

File diff suppressed because it is too large Load Diff

View 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);

View 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)))
{

View 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

View File

@@ -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')

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
config RT_HWSPINLOCK_ROCKCHIP
bool "Rockchip Hardware Spinlock device"
default n

View 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')

View 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);

View File

@@ -1,5 +1,3 @@
config RT_HWTIMER_ROCKCHIP
bool "RockChip Timer"
depends on RT_USING_DM
depends on RT_USING_HWTIMER
default n

View 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