mirror of
https://github.com/LuckfoxTECH/luckfox-pico.git
synced 2026-01-19 09:52:31 +01:00
project:build.sh: Added fastboot support; custom modifications to U-Boot and kernel implemented using patches.
project:cfg:BoardConfig_IPC: Added fastboot BoardConfig file and firmware post-scripts, distinguishing between the BoardConfigs for Luckfox Pico Pro and Luckfox Pico Max. project:app: Added fastboot_client and rk_smart_door for quick boot applications; updated rkipc app to adapt to the latest media library. media:samples: Added more usage examples. media:rockit: Fixed bugs; removed support for retrieving data frames from VPSS. media:isp: Updated rkaiq library and related tools to support connection to RKISP_Tuner. sysdrv:Makefile: Added support for compiling drv_ko on Luckfox Pico Ultra W using Ubuntu; added support for custom root filesystem. sysdrv:tools:board: Updated Buildroot optional mirror sources, updated some software versions, and stored device tree files and configuration files that undergo multiple modifications for U-Boot and kernel separately. sysdrv:source:mcu: Used RISC-V MCU SDK with RT-Thread system, mainly for initializing camera AE during quick boot. sysdrv:source:uboot: Added support for fastboot; added high baud rate DDR bin for serial firmware upgrades. sysdrv:source:kernel: Upgraded to version 5.10.160; increased NPU frequency for RV1106G3; added support for fastboot. Signed-off-by: luckfox-eng29 <eng29@luckfox.com>
This commit is contained in:
@@ -181,6 +181,21 @@ config PWM_FSL_FTM
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called pwm-fsl-ftm.
|
||||
|
||||
config PWM_GPIO
|
||||
tristate "Generic GPIO bit-banged PWM driver"
|
||||
depends on OF
|
||||
depends on GPIOLIB
|
||||
help
|
||||
Some platforms do not offer any hardware PWM capabilities but do have
|
||||
General Purpose Input Output (GPIO) pins available. Using the kernels
|
||||
High-Resolution Timer API this driver tries to toggle GPIO using the
|
||||
generic kernel PWM framework. The maximum frequency and/or accuracy
|
||||
is dependent on several factors such as system load and the maximum
|
||||
speed a pin can be toggled at the hardware.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called pwm-gpio.
|
||||
|
||||
config PWM_HIBVT
|
||||
tristate "HiSilicon BVT PWM support"
|
||||
depends on ARCH_HISI || COMPILE_TEST
|
||||
|
||||
@@ -15,6 +15,7 @@ obj-$(CONFIG_PWM_CRC) += pwm-crc.o
|
||||
obj-$(CONFIG_PWM_CROS_EC) += pwm-cros-ec.o
|
||||
obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o
|
||||
obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o
|
||||
obj-$(CONFIG_PWM_GPIO) += pwm-gpio.o
|
||||
obj-$(CONFIG_PWM_HIBVT) += pwm-hibvt.o
|
||||
obj-$(CONFIG_PWM_IMG) += pwm-img.o
|
||||
obj-$(CONFIG_PWM_IMX1) += pwm-imx1.o
|
||||
|
||||
@@ -585,6 +585,9 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
|
||||
if (state->period == pwm->state.period &&
|
||||
state->duty_cycle == pwm->state.duty_cycle &&
|
||||
state->polarity == pwm->state.polarity &&
|
||||
#ifdef CONFIG_PWM_ROCKCHIP_ONESHOT
|
||||
state->oneshot_count == pwm->state.oneshot_count &&
|
||||
#endif
|
||||
state->enabled == pwm->state.enabled)
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -157,7 +157,6 @@ static int gpio_pwm_probe(struct platform_device *pdev)
|
||||
pc->chip.npwm = 1;
|
||||
pc->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
pc->chip.of_pwm_n_cells = 3;
|
||||
pc->chip.can_sleep = true;
|
||||
|
||||
pc->gpiod = devm_gpiod_get(&pdev->dev, "pwm", GPIOD_OUT_LOW);
|
||||
|
||||
|
||||
@@ -125,6 +125,7 @@ static int lp3943_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
duty_ns = min(duty_ns, period_ns);
|
||||
val = (u8)(duty_ns * LP3943_MAX_DUTY / period_ns);
|
||||
|
||||
return lp3943_write_byte(lp3943, reg_duty, val);
|
||||
|
||||
@@ -325,7 +325,6 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct lpc18xx_pwm_chip *lpc18xx_pwm;
|
||||
struct pwm_device *pwm;
|
||||
struct resource *res;
|
||||
int ret, i;
|
||||
u64 val;
|
||||
|
||||
@@ -336,8 +335,7 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
lpc18xx_pwm->dev = &pdev->dev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
lpc18xx_pwm->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
lpc18xx_pwm->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(lpc18xx_pwm->base))
|
||||
return PTR_ERR(lpc18xx_pwm->base);
|
||||
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
@@ -15,6 +17,9 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/time.h>
|
||||
#include "pwm-rockchip.h"
|
||||
|
||||
#define PWM_MAX_CHANNEL_NUM 4
|
||||
|
||||
#define PWM_CTRL_TIMER_EN (1 << 0)
|
||||
#define PWM_CTRL_OUTPUT_EN (1 << 3)
|
||||
@@ -32,8 +37,14 @@
|
||||
#define PWM_LP_DISABLE (0 << 8)
|
||||
|
||||
#define PWM_ONESHOT_COUNT_SHIFT 24
|
||||
#define PWM_ONESHOT_COUNT_MASK (0xff << PWM_ONESHOT_COUNT_SHIFT)
|
||||
#define PWM_ONESHOT_COUNT_MAX 256
|
||||
|
||||
#define PWM_REG_INTSTS(n) ((3 - (n)) * 0x10 + 0x10)
|
||||
#define PWM_REG_INT_EN(n) ((3 - (n)) * 0x10 + 0x14)
|
||||
|
||||
#define PWM_CH_INT(n) BIT(n)
|
||||
|
||||
struct rockchip_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
struct clk *clk;
|
||||
@@ -46,6 +57,8 @@ struct rockchip_pwm_chip {
|
||||
bool vop_pwm_en; /* indicate voppwm mirror register state */
|
||||
bool center_aligned;
|
||||
bool oneshot;
|
||||
int channel_id;
|
||||
int irq;
|
||||
};
|
||||
|
||||
struct rockchip_pwm_regs {
|
||||
@@ -103,6 +116,34 @@ static void rockchip_pwm_get_state(struct pwm_chip *chip,
|
||||
clk_disable(pc->pclk);
|
||||
}
|
||||
|
||||
static irqreturn_t rockchip_pwm_oneshot_irq(int irq, void *data)
|
||||
{
|
||||
struct rockchip_pwm_chip *pc = data;
|
||||
struct pwm_state state;
|
||||
unsigned int id = pc->channel_id;
|
||||
int val;
|
||||
|
||||
if (id > 3)
|
||||
return IRQ_NONE;
|
||||
val = readl_relaxed(pc->base + PWM_REG_INTSTS(id));
|
||||
|
||||
if ((val & PWM_CH_INT(id)) == 0)
|
||||
return IRQ_NONE;
|
||||
|
||||
writel_relaxed(PWM_CH_INT(id), pc->base + PWM_REG_INTSTS(id));
|
||||
|
||||
/*
|
||||
* Set pwm state to disabled when the oneshot mode finished.
|
||||
*/
|
||||
pwm_get_state(&pc->chip.pwms[0], &state);
|
||||
state.enabled = false;
|
||||
pwm_apply_state(&pc->chip.pwms[0], &state);
|
||||
|
||||
rockchip_pwm_oneshot_callback(&pc->chip.pwms[0], &state);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
@@ -142,11 +183,24 @@ static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
pc->oneshot = false;
|
||||
dev_err(chip->dev, "Oneshot_count value overflow.\n");
|
||||
} else if (state->oneshot_count > 0) {
|
||||
u32 int_ctrl;
|
||||
|
||||
pc->oneshot = true;
|
||||
ctrl &= ~PWM_ONESHOT_COUNT_MASK;
|
||||
ctrl |= (state->oneshot_count - 1) << PWM_ONESHOT_COUNT_SHIFT;
|
||||
|
||||
int_ctrl = readl_relaxed(pc->base + PWM_REG_INT_EN(pc->channel_id));
|
||||
int_ctrl |= PWM_CH_INT(pc->channel_id);
|
||||
writel_relaxed(int_ctrl, pc->base + PWM_REG_INT_EN(pc->channel_id));
|
||||
} else {
|
||||
u32 int_ctrl;
|
||||
|
||||
pc->oneshot = false;
|
||||
ctrl |= PWM_CONTINUOUS;
|
||||
|
||||
int_ctrl = readl_relaxed(pc->base + PWM_REG_INT_EN(pc->channel_id));
|
||||
int_ctrl &= ~PWM_CH_INT(pc->channel_id);
|
||||
writel_relaxed(int_ctrl, pc->base + PWM_REG_INT_EN(pc->channel_id));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -335,6 +389,13 @@ static const struct of_device_id rockchip_pwm_dt_ids[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids);
|
||||
|
||||
static int rockchip_pwm_get_channel_id(const char *name)
|
||||
{
|
||||
int len = strlen(name);
|
||||
|
||||
return name[len - 2] - '0';
|
||||
}
|
||||
|
||||
static int rockchip_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *id;
|
||||
@@ -392,16 +453,42 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
pc->channel_id = rockchip_pwm_get_channel_id(pdev->dev.of_node->full_name);
|
||||
if (pc->channel_id < 0 || pc->channel_id >= PWM_MAX_CHANNEL_NUM) {
|
||||
dev_err(&pdev->dev, "Channel id is out of range: %d\n", pc->channel_id);
|
||||
ret = -EINVAL;
|
||||
goto err_pclk;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_PWM_ROCKCHIP_ONESHOT)) {
|
||||
pc->irq = platform_get_irq(pdev, 0);
|
||||
if (pc->irq < 0) {
|
||||
dev_err(&pdev->dev, "Get oneshot mode irq failed\n");
|
||||
ret = pc->irq;
|
||||
goto err_pclk;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, pc->irq, rockchip_pwm_oneshot_irq,
|
||||
IRQF_NO_SUSPEND | IRQF_SHARED,
|
||||
"rk_pwm_oneshot_irq", pc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Claim oneshot IRQ failed\n");
|
||||
goto err_pclk;
|
||||
}
|
||||
}
|
||||
|
||||
pc->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
if (IS_ERR(pc->pinctrl)) {
|
||||
dev_err(&pdev->dev, "Get pinctrl failed!\n");
|
||||
return PTR_ERR(pc->pinctrl);
|
||||
ret = PTR_ERR(pc->pinctrl);
|
||||
goto err_pclk;
|
||||
}
|
||||
|
||||
pc->active_state = pinctrl_lookup_state(pc->pinctrl, "active");
|
||||
if (IS_ERR(pc->active_state)) {
|
||||
dev_err(&pdev->dev, "No active pinctrl state\n");
|
||||
return PTR_ERR(pc->active_state);
|
||||
ret = PTR_ERR(pc->active_state);
|
||||
goto err_pclk;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, pc);
|
||||
|
||||
27
sysdrv/source/kernel/drivers/pwm/pwm-rockchip.h
Normal file
27
sysdrv/source/kernel/drivers/pwm/pwm-rockchip.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
|
||||
/*
|
||||
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#ifndef _PWM_ROCKCHIP_H_
|
||||
#define _PWM_ROCKCHIP_H_
|
||||
|
||||
#include <linux/pwm.h>
|
||||
|
||||
static void rockchip_pwm_oneshot_callback(struct pwm_device *pwm, struct pwm_state *state)
|
||||
{
|
||||
/*
|
||||
* If you want to enable oneshot mode again, config and call
|
||||
* pwm_apply_state().
|
||||
*
|
||||
* struct pwm_state new_state;
|
||||
*
|
||||
* pwm_get_state(pwm, &new_state);
|
||||
* new_state.enabled = true;
|
||||
* ......
|
||||
* pwm_apply_state(pwm, &new_state);
|
||||
*
|
||||
*/
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -23,7 +23,7 @@
|
||||
#define PWM_SIFIVE_PWMCFG 0x0
|
||||
#define PWM_SIFIVE_PWMCOUNT 0x8
|
||||
#define PWM_SIFIVE_PWMS 0x10
|
||||
#define PWM_SIFIVE_PWMCMP0 0x20
|
||||
#define PWM_SIFIVE_PWMCMP(i) (0x20 + 4 * (i))
|
||||
|
||||
/* PWMCFG fields */
|
||||
#define PWM_SIFIVE_PWMCFG_SCALE GENMASK(3, 0)
|
||||
@@ -36,8 +36,6 @@
|
||||
#define PWM_SIFIVE_PWMCFG_GANG BIT(24)
|
||||
#define PWM_SIFIVE_PWMCFG_IP BIT(28)
|
||||
|
||||
/* PWM_SIFIVE_SIZE_PWMCMP is used to calculate offset for pwmcmpX registers */
|
||||
#define PWM_SIFIVE_SIZE_PWMCMP 4
|
||||
#define PWM_SIFIVE_CMPWIDTH 16
|
||||
#define PWM_SIFIVE_DEFAULT_PERIOD 10000000
|
||||
|
||||
@@ -112,8 +110,7 @@ static void pwm_sifive_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip);
|
||||
u32 duty, val;
|
||||
|
||||
duty = readl(ddata->regs + PWM_SIFIVE_PWMCMP0 +
|
||||
pwm->hwpwm * PWM_SIFIVE_SIZE_PWMCMP);
|
||||
duty = readl(ddata->regs + PWM_SIFIVE_PWMCMP(pwm->hwpwm));
|
||||
|
||||
state->enabled = duty > 0;
|
||||
|
||||
@@ -194,8 +191,7 @@ static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
pwm_sifive_update_clock(ddata, clk_get_rate(ddata->clk));
|
||||
}
|
||||
|
||||
writel(frac, ddata->regs + PWM_SIFIVE_PWMCMP0 +
|
||||
pwm->hwpwm * PWM_SIFIVE_SIZE_PWMCMP);
|
||||
writel(frac, ddata->regs + PWM_SIFIVE_PWMCMP(pwm->hwpwm));
|
||||
|
||||
if (state->enabled != enabled)
|
||||
pwm_sifive_enable(chip, state->enabled);
|
||||
@@ -234,6 +230,8 @@ static int pwm_sifive_probe(struct platform_device *pdev)
|
||||
struct pwm_chip *chip;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
u32 val;
|
||||
unsigned int enabled_pwms = 0, enabled_clks = 1;
|
||||
|
||||
ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (!ddata)
|
||||
@@ -264,6 +262,33 @@ static int pwm_sifive_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
val = readl(ddata->regs + PWM_SIFIVE_PWMCFG);
|
||||
if (val & PWM_SIFIVE_PWMCFG_EN_ALWAYS) {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < chip->npwm; ++i) {
|
||||
val = readl(ddata->regs + PWM_SIFIVE_PWMCMP(i));
|
||||
if (val > 0)
|
||||
++enabled_pwms;
|
||||
}
|
||||
}
|
||||
|
||||
/* The clk should be on once for each running PWM. */
|
||||
if (enabled_pwms) {
|
||||
while (enabled_clks < enabled_pwms) {
|
||||
/* This is not expected to fail as the clk is already on */
|
||||
ret = clk_enable(ddata->clk);
|
||||
if (unlikely(ret)) {
|
||||
dev_err_probe(dev, ret, "Failed to enable clk\n");
|
||||
goto disable_clk;
|
||||
}
|
||||
++enabled_clks;
|
||||
}
|
||||
} else {
|
||||
clk_disable(ddata->clk);
|
||||
enabled_clks = 0;
|
||||
}
|
||||
|
||||
/* Watch for changes to underlying clock frequency */
|
||||
ddata->notifier.notifier_call = pwm_sifive_clock_notifier;
|
||||
ret = clk_notifier_register(ddata->clk, &ddata->notifier);
|
||||
@@ -286,7 +311,11 @@ static int pwm_sifive_probe(struct platform_device *pdev)
|
||||
unregister_clk:
|
||||
clk_notifier_unregister(ddata->clk, &ddata->notifier);
|
||||
disable_clk:
|
||||
clk_disable_unprepare(ddata->clk);
|
||||
while (enabled_clks) {
|
||||
clk_disable(ddata->clk);
|
||||
--enabled_clks;
|
||||
}
|
||||
clk_unprepare(ddata->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -294,25 +323,21 @@ disable_clk:
|
||||
static int pwm_sifive_remove(struct platform_device *dev)
|
||||
{
|
||||
struct pwm_sifive_ddata *ddata = platform_get_drvdata(dev);
|
||||
bool is_enabled = false;
|
||||
struct pwm_device *pwm;
|
||||
int ret, ch;
|
||||
int ch;
|
||||
|
||||
pwmchip_remove(&ddata->chip);
|
||||
clk_notifier_unregister(ddata->clk, &ddata->notifier);
|
||||
|
||||
for (ch = 0; ch < ddata->chip.npwm; ch++) {
|
||||
pwm = &ddata->chip.pwms[ch];
|
||||
if (pwm->state.enabled) {
|
||||
is_enabled = true;
|
||||
break;
|
||||
}
|
||||
if (pwm->state.enabled)
|
||||
clk_disable(ddata->clk);
|
||||
}
|
||||
if (is_enabled)
|
||||
clk_disable(ddata->clk);
|
||||
|
||||
clk_disable_unprepare(ddata->clk);
|
||||
ret = pwmchip_remove(&ddata->chip);
|
||||
clk_notifier_unregister(ddata->clk, &ddata->notifier);
|
||||
clk_unprepare(ddata->clk);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id pwm_sifive_of_match[] = {
|
||||
|
||||
Reference in New Issue
Block a user