From c9f0e7cdae9cc674b090f85b14d85847fccb2ce3 Mon Sep 17 00:00:00 2001 From: xuxiang Date: Mon, 27 May 2024 18:53:47 +0800 Subject: [PATCH 038/222] perf:update dma, pwm, timer driver Changelogs: 1. Optimizing dma drivers 2. Reconstruct the pwm driver 3. Porting timer driver from 5.17 (not optimized) --- .../dts/eswin/eswin-win2030-die0-soc.dtsi | 4 +- arch/riscv/configs/win2030_defconfig | 1 + drivers/clocksource/Kconfig | 5 + drivers/clocksource/Makefile | 1 + drivers/clocksource/timer-eswin.c | 293 ++++++++++++++ .../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 89 ++--- drivers/hwmon/eswin-fan-control.c | 17 +- drivers/iommu/eswin/eswin-win2030-sid.c | 47 +++ drivers/pwm/Makefile | 2 +- drivers/pwm/pwm-dwc-eswin.c | 348 ++++++++++++++++ drivers/pwm/pwm-eswin.c | 370 ------------------ include/linux/eswin-win2030-sid-cfg.h | 1 + 12 files changed, 738 insertions(+), 440 deletions(-) create mode 100644 drivers/clocksource/timer-eswin.c create mode 100644 drivers/pwm/pwm-dwc-eswin.c delete mode 100644 drivers/pwm/pwm-eswin.c diff --git a/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi b/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi index 7c742eb16669..f4c569697c08 100644 --- a/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi +++ b/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi @@ -1516,11 +1516,11 @@ pwm0: pwm@0x50818000 { compatible = "eswin,pwm-eswin"; #pwm-cells = <2>; reg = <0x0 0x50818000 0x0 0x4000>; - clock-names = "pwm","pclk"; + clock-names = "pclk"; clocks = <&d0_clock WIN2030_CLK_LSP_TIMER_PCLK>; clock-frequency = <200000000>; resets = <&d0_reset TIMER_RST_CTRL SW_TIMER_RST_N>; - reset-names = "pwmrst"; + reset-names = "rst"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pwm0_default>; status = "disabled"; diff --git a/arch/riscv/configs/win2030_defconfig b/arch/riscv/configs/win2030_defconfig index 7311283d7c6d..61b8f4de69ad 100644 --- a/arch/riscv/configs/win2030_defconfig +++ b/arch/riscv/configs/win2030_defconfig @@ -320,3 +320,4 @@ CONFIG_RCU_EQS_DEBUG=y # CONFIG_FTRACE is not set # CONFIG_RUNTIME_TESTING_MENU is not set CONFIG_MEMTEST=y +CONFIG_TIMER_ESWIN=y \ No newline at end of file diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 8208a3d89563..db73c2254f75 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -73,6 +73,11 @@ config DW_APB_TIMER_OF select DW_APB_TIMER select TIMER_OF +config TIMER_ESWIN + tristate "ESWIN timer support" + help + Enables the support for the eswin timer. + config FTTMR010_TIMER bool "Faraday Technology timer driver" if COMPILE_TEST depends on HAS_IOMEM diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 368c3461dab8..cee18fa560c0 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_OMAP_DM_TIMER) += timer-ti-dm.o obj-$(CONFIG_OMAP_DM_SYSTIMER) += timer-ti-dm-systimer.o obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o +obj-$(CONFIG_TIMER_ESWIN) += timer-eswin.o obj-$(CONFIG_FTTMR010_TIMER) += timer-fttmr010.o obj-$(CONFIG_IXP4XX_TIMER) += timer-ixp4xx.o obj-$(CONFIG_ROCKCHIP_TIMER) += timer-rockchip.o diff --git a/drivers/clocksource/timer-eswin.c b/drivers/clocksource/timer-eswin.c new file mode 100644 index 000000000000..089d0f28eba3 --- /dev/null +++ b/drivers/clocksource/timer-eswin.c @@ -0,0 +1,293 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) ESWIN Electronics Co.Ltd + * + * Eswin timer driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define APBT_MIN_PERIOD 4 +#define APBT_MIN_DELTA_USEC 200 + +#define APBTMR_N_LOAD_COUNT 0x00 +#define APBTMR_N_CURRENT_VALUE 0x04 +#define APBTMR_N_CONTROL 0x08 +#define APBTMR_N_EOI 0x0c +#define APBTMR_N_INT_STATUS 0x10 + +#define APBTMRS_INT_STATUS 0xa0 +#define APBTMRS_EOI 0xa4 +#define APBTMRS_RAW_INT_STATUS 0xa8 +#define APBTMRS_COMP_VERSION 0xac + +#define APBTMR_CONTROL_ENABLE (1 << 0) +/* 1: periodic, 0:free running. */ +#define APBTMR_CONTROL_MODE_PERIODIC (1 << 1) +#define APBTMR_CONTROL_INT (1 << 2) + +#define APBTMR_MAX_CNT 0xFFFFFFFF +#define APBTMR_EACH_OFS 0x14 + +struct eswin_timer { + /* Memory Mapped Register */ + struct resource *mem; + void __iomem *mmio_base; + u32 perf_count; +}; + +static struct eswin_timer *perf_timer = NULL; +static void __iomem *perf_cnt_base = NULL; + +static inline u32 eswin_readl(struct eswin_timer *timer, unsigned long offs) +{ + return readl(timer->mmio_base + offs); +} + +static inline void eswin_writel(struct eswin_timer *timer, u32 val, + unsigned long offs) +{ + writel(val, timer->mmio_base + offs); +} + +static inline u32 eswin_readl_relaxed(struct eswin_timer *timer, unsigned long offs) +{ + return readl_relaxed(timer->mmio_base + offs); +} + +static inline void eswin_writel_relaxed(struct eswin_timer *timer, u32 val, + unsigned long offs) +{ + writel_relaxed(val, timer->mmio_base + offs); +} + +static irqreturn_t timer_irq_handler(int irq, void *dev_id) +{ + struct eswin_timer *time = dev_id; + pr_err("Enter timer_irq_handler irq = %x, time->mmio_base = %lx\n",irq,(long)time->mmio_base); + /* + * clear interrupt read(0xa4) + * read intr status read(0xa0) + */ + eswin_readl(time,APBTMRS_INT_STATUS); + eswin_readl(time,APBTMRS_EOI); + return IRQ_HANDLED; +} + +static int __init timer_init(struct device_node *np) +{ + struct clk *pclk, *timer_aclk, *timer3_clk8; + struct reset_control *trstc0,*trstc1,*trstc2,*trstc3,*trstc4,*trstc5,*trstc6,*trstc7,*prstc; + + /* + * Reset the timer if the reset control is available, wiping + * out the state the firmware may have left it + */ + trstc0 = of_reset_control_get(np, "trst0"); + if (!IS_ERR(trstc0)) { + reset_control_assert(trstc0); + reset_control_deassert(trstc0); + } + trstc1 = of_reset_control_get(np, "trst1"); + if (!IS_ERR(trstc1)) { + reset_control_assert(trstc1); + reset_control_deassert(trstc1); + } + trstc2 = of_reset_control_get(np, "trst2"); + if (!IS_ERR(trstc2)) { + reset_control_assert(trstc2); + reset_control_deassert(trstc2); + } + trstc3 = of_reset_control_get(np, "trst3"); + if (!IS_ERR(trstc3)) { + reset_control_assert(trstc3); + reset_control_deassert(trstc3); + } + trstc4 = of_reset_control_get(np, "trst4"); + if (!IS_ERR(trstc4)) { + reset_control_assert(trstc4); + reset_control_deassert(trstc4); + } + trstc5 = of_reset_control_get(np, "trst5"); + if (!IS_ERR(trstc5)) { + reset_control_assert(trstc5); + reset_control_deassert(trstc5); + } + trstc6 = of_reset_control_get(np, "trst6"); + if (!IS_ERR(trstc6)) { + reset_control_assert(trstc6); + reset_control_deassert(trstc6); + } + trstc7 = of_reset_control_get(np, "trst7"); + if (!IS_ERR(trstc7)) { + reset_control_assert(trstc7); + reset_control_deassert(trstc7); + } + prstc = of_reset_control_get(np, "prst"); + if (!IS_ERR(prstc)) { + reset_control_assert(prstc); + reset_control_deassert(prstc); + } + + /* + * Not all implementations use a peripheral clock, so don't panic + * if it's not present + */ + pclk = of_clk_get_by_name(np, "pclk"); + if (!IS_ERR(pclk)) + if (clk_prepare_enable(pclk)) + pr_warn("pclk for %pOFn is present, but could not be activated\n",np); + timer_aclk = of_clk_get_by_name(np, "timer_aclk"); + if (!IS_ERR(timer_aclk)) + if (clk_prepare_enable(timer_aclk)) + pr_warn("timer_aclk for %pOFn is present, but could not be activated\n",np); + timer3_clk8 = of_clk_get_by_name(np, "timer3_clk8"); + if (!IS_ERR(timer3_clk8)) + if (clk_prepare_enable(timer3_clk8)) + pr_warn("timer3_clk8 for %pOFn is present, but could not be activated\n",np); + + return 0; +} + +static int timer_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct resource *res; + u64 base; + if (perf_timer == NULL) { + return -EIO; + } + + res = perf_timer->mem; + + base = res->start + perf_timer->perf_count * 0x14; + printk("%s, %d, chan=%d.\n\n", __func__, __LINE__, perf_timer->perf_count); + remap_pfn_range(vma, vma->vm_start, base >> 12, + vma->vm_end - vma->vm_start, vma->vm_page_prot); + return 0; +} + +static struct file_operations timer_fops = { + .owner = THIS_MODULE, + .mmap = timer_mmap, +}; + +static struct miscdevice timer_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "perf_count", + .fops = &timer_fops, +}; + +/* + * use timer0 channel 7 for performance statics counter. + * + * This counter freq is 24MHz, and max cnt value is 0xFFFF_FFFF, it decrease one every timer_clk, and when + * decrease zero, it will load the max cnt, and repeat this. + * + * resolution: about 42ns per cnt. So the max time that will not overflow is 42 * 0xFFFF_FFFF ~= 180s + */ + +u32 get_perf_timer_cnt(void) +{ + return APBTMR_MAX_CNT - readl(perf_cnt_base); +} +EXPORT_SYMBOL(get_perf_timer_cnt); + +static int init_timer_perf_counter(struct eswin_timer *time, u32 chan) +{ + int ret; + + time->perf_count = chan; + eswin_writel(time, APBTMR_MAX_CNT, chan * APBTMR_EACH_OFS + APBTMR_N_LOAD_COUNT); + eswin_writel(time, 0x7, chan * APBTMR_EACH_OFS + APBTMR_N_CONTROL); + ret = misc_register(&timer_misc); + perf_timer = time; + perf_cnt_base = perf_timer->mmio_base + chan * APBTMR_EACH_OFS + APBTMR_N_CURRENT_VALUE; + return 0; +} + +static int eswin_timer_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct eswin_timer *time; + struct resource *res; + int error, irq, ret; + u32 val; + + dev_err(&pdev->dev, "eswin_timer_probe\n"); + /*add eswin timer*/ + time = devm_kzalloc(&pdev->dev, sizeof(struct eswin_timer), GFP_KERNEL); + if (!time) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to get register memory\n"); + return -EINVAL; + } + time->mem = res; + + time->mmio_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(time->mmio_base)) + return PTR_ERR(time->mmio_base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -ENXIO; + + error = devm_request_irq(&pdev->dev, irq, timer_irq_handler, 0, + pdev->name, time); + if (error) { + dev_err(&pdev->dev, "could not request IRQ %d\n", irq); + return error; + } + + ret = timer_init(np); + if (ret) + return ret; + + time->perf_count = 0xff; + + ret = of_property_read_u32(np, "perf_count", &val); + if (!ret) { + init_timer_perf_counter(time, val); + } + + dev_err(&pdev->dev, "eswin_timer_probe success\n"); + return 0; +} + +static int eswin_timer_remove(struct platform_device *pdev) +{ + return -EBUSY; /* cannot unregister clockevent */ +} + +static const struct of_device_id eswin_timer_of_match[] = { + { .compatible = "eswin,eswin-timer", }, + {}, +}; +MODULE_DEVICE_TABLE(of, eswin_timer_of_match); + +static struct platform_driver eswin_timer_driver = { + .probe = eswin_timer_probe, + .remove = eswin_timer_remove, + .driver = { + .name = "eswin-timer", + .of_match_table = of_match_ptr(eswin_timer_of_match), + }, +}; +module_platform_driver(eswin_timer_driver); + +MODULE_ALIAS("platform:eswin-timer"); +MODULE_DESCRIPTION("eswin timer driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c index dd98cce3dad8..54c1396d974b 100644 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -55,15 +55,14 @@ #define AXI_DMA_FLAG_HAS_APB_REGS BIT(0) #define AXI_DMA_FLAG_HAS_RESETS BIT(1) #define AXI_DMA_FLAG_USE_CFG2 BIT(2) -#define AXI_DMA_FLAG_HAS_2RESETS BIT(3) +#define AXI_DMA_FLAG_HAS_2RESETS BIT(3) +#define AXI_DMA_FLAG_HAS_EIC7700 BIT(4) #define AWSMMUSID GENMASK(31, 24) // The sid of write operation #define AWSMMUSSID GENMASK(23, 16) // The ssid of write operation #define ARSMMUSID GENMASK(15, 8) // The sid of read operation #define ARSMMUSSID GENMASK(7, 0) // The ssid of read operation -static int eswin_dma_sid_cfg(struct device *dev); - static inline void axi_dma_iowrite32(struct axi_dma_chip *chip, u32 reg, u32 val) { @@ -233,6 +232,7 @@ static void axi_dma_hw_init(struct axi_dma_chip *chip) { int ret; u32 i; + int flags; for (i = 0; i < chip->dw->hdata->nr_channels; i++) { axi_chan_irq_disable(&chip->dw->chan[i], DWAXIDMAC_IRQ_ALL); @@ -242,15 +242,19 @@ static void axi_dma_hw_init(struct axi_dma_chip *chip) if (ret) dev_warn(chip->dev, "Unable to set coherent mask\n"); - if (of_node_name_prefix(chip->dev->of_node, "dma-controller-hsp")) { - eswin_dma_sid_cfg(chip->dev); - } - else { - win2030_aon_sid_cfg(chip->dev); + flags = (uintptr_t)of_device_get_match_data(chip->dev); + if (flags & AXI_DMA_FLAG_HAS_EIC7700) { + if (of_node_name_prefix(chip->dev->of_node, "dma-controller-hsp")) { + win2030_dma_sid_cfg(chip->dev); + } + else { + win2030_aon_sid_cfg(chip->dev); + } + + /* TBU power up */ + win2030_tbu_power(chip->dev, true); } - /* TBU power up */ - win2030_tbu_power(chip->dev, true); } static u32 axi_chan_get_xfer_width(struct axi_dma_chan *chan, dma_addr_t src, @@ -717,7 +721,7 @@ static int dw_axi_dma_set_hw_desc(struct axi_dma_chan *chan, hw_desc->lli->block_ts_lo = cpu_to_le32(block_ts - 1); ctllo |= DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS | - DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS; + DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS; hw_desc->lli->ctl_lo = cpu_to_le32(ctllo); set_desc_src_master(hw_desc, chan); @@ -1372,8 +1376,11 @@ static struct dma_chan *dw_axi_dma_of_xlate(struct of_phandle_args *dma_spec, chan = dchan_to_axi_dma_chan(dchan); chan->hw_handshake_num = dma_spec->args[0]; - if (dma_spec->args_count > 1) - win2030_dma_sel_cfg(chan, dma_spec->args[1]); + int flags = (uintptr_t)of_device_get_match_data(chan->chip->dev); + if (flags & AXI_DMA_FLAG_HAS_EIC7700) { + if (dma_spec->args_count > 1) + win2030_dma_sel_cfg(chan, dma_spec->args[1]); + } return dchan; } @@ -1628,57 +1635,13 @@ static int dw_probe(struct platform_device *pdev) return ret; } -static int eswin_dma_sid_cfg(struct device *dev) -{ - int ret; - struct regmap *regmap; - int hsp_mmu_dma_reg; - u32 rdwr_sid_ssid; - u32 sid; - struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); - - /* not behind smmu, use the default reset value(0x0) of the reg as streamID*/ - if (fwspec == NULL) { - dev_dbg(dev, "dev is not behind smmu, skip configuration of sid\n"); - return 0; - } - sid = fwspec->ids[0]; - - regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "eswin,hsp_sp_csr"); - if (IS_ERR(regmap)) { - dev_dbg(dev, "No hsp_sp_csr phandle specified\n"); - return 0; - } - - ret = of_property_read_u32_index(dev->of_node, "eswin,hsp_sp_csr", 1, - &hsp_mmu_dma_reg); - if (ret) { - dev_err(dev, "can't get dma sid cfg reg offset (%d)\n", ret); - return ret; - } - - /* make the reading sid the same as writing sid, ssid is fixed to zero */ - rdwr_sid_ssid = FIELD_PREP(AWSMMUSID, sid); - rdwr_sid_ssid |= FIELD_PREP(ARSMMUSID, sid); - rdwr_sid_ssid |= FIELD_PREP(AWSMMUSSID, 0); - rdwr_sid_ssid |= FIELD_PREP(ARSMMUSSID, 0); - regmap_write(regmap, hsp_mmu_dma_reg, rdwr_sid_ssid); - - ret = win2030_dynm_sid_enable(dev_to_node(dev)); - if (ret < 0) - dev_err(dev, "failed to config dma streamID(%d)!\n", sid); - else - dev_dbg(dev, "success to config dma streamID(%d)!\n", sid); - - return ret; -} - static int dw_remove(struct platform_device *pdev) { struct axi_dma_chip *chip = platform_get_drvdata(pdev); struct dw_axi_dma *dw = chip->dw; struct axi_dma_chan *chan, *_chan; u32 i; + unsigned int flags; /* Enable clk before accessing to registers */ clk_prepare_enable(chip->cfgr_clk); @@ -1702,8 +1665,11 @@ static int dw_remove(struct platform_device *pdev) list_del(&chan->vc.chan.device_node); tasklet_kill(&chan->vc.task); } - /* TBU power down before reset */ - win2030_tbu_power(chip->dev, false); + flags = (uintptr_t)of_device_get_match_data(&pdev->dev); + if (flags & AXI_DMA_FLAG_HAS_EIC7700) { + /* TBU power down before reset */ + win2030_tbu_power(chip->dev, false); + } return 0; } @@ -1723,7 +1689,7 @@ static const struct of_device_id dw_dma_of_id_table[] = { .data = (void *)(AXI_DMA_FLAG_HAS_RESETS | AXI_DMA_FLAG_USE_CFG2), }, { .compatible = "eswin,eic770x-axi-dma", - .data = (void *)(AXI_DMA_FLAG_HAS_2RESETS | AXI_DMA_FLAG_USE_CFG2), + .data = (void *)(AXI_DMA_FLAG_HAS_2RESETS | AXI_DMA_FLAG_USE_CFG2 | AXI_DMA_FLAG_HAS_EIC7700), }, {} }; @@ -1743,3 +1709,4 @@ module_platform_driver(dw_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Synopsys DesignWare AXI DMA Controller platform driver"); MODULE_AUTHOR("Eugeniy Paltsev "); +MODULE_AUTHOR("XuXiang "); diff --git a/drivers/hwmon/eswin-fan-control.c b/drivers/hwmon/eswin-fan-control.c index f7ca5c29520b..ea92a0bb9906 100644 --- a/drivers/hwmon/eswin-fan-control.c +++ b/drivers/hwmon/eswin-fan-control.c @@ -437,6 +437,7 @@ static int eswin_fan_control_probe(struct platform_device *pdev) const struct of_device_id *id; const char *name = "eswin_fan_control"; struct pwm_state state; + struct pwm_args pwm_args; int ret; id = of_match_node(eswin_fan_control_of_match, pdev->dev.of_node); @@ -497,23 +498,27 @@ static int eswin_fan_control_probe(struct platform_device *pdev) return ret; } ctl->pwm = pwm_get(&pdev->dev, NULL); - if (IS_ERR(ctl->pwm)) { - dev_dbg(&pdev->dev, "Unable to request PWM, trying legacy API\n"); - } - if (IS_ERR(ctl->pwm)) { ret = PTR_ERR(ctl->pwm); dev_err(&pdev->dev, "Failed to request pwm device: %d\n", ret); return ret; } - pwm_enable(ctl->pwm); - pwm_init_state(ctl->pwm, &state); + + pwm_get_state(ctl->pwm, &state); + + /* Then fill it with the reference config */ + pwm_get_args(ctl->pwm, &pwm_args); + + state.period = pwm_args.period; state.duty_cycle = state.period/2; + dev_err(&pdev->dev, "state.period: %d state.duty_cycle: %d\n", + state.period,state.duty_cycle); ret = pwm_apply_state(ctl->pwm, &state); if (ret) { dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n", ret); } + pwm_enable(ctl->pwm); ret = devm_add_action_or_reset(&pdev->dev, eswin_fan_control_remove, ctl); if (ret) diff --git a/drivers/iommu/eswin/eswin-win2030-sid.c b/drivers/iommu/eswin/eswin-win2030-sid.c index 24fc76fe7272..6d8602c47805 100644 --- a/drivers/iommu/eswin/eswin-win2030-sid.c +++ b/drivers/iommu/eswin/eswin-win2030-sid.c @@ -216,6 +216,53 @@ int win2030_aon_sid_cfg(struct device *dev) } EXPORT_SYMBOL(win2030_aon_sid_cfg); + +int win2030_dma_sid_cfg(struct device *dev) +{ + int ret; + struct regmap *regmap; + int hsp_mmu_dma_reg; + u32 rdwr_sid_ssid; + u32 sid; + struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); + + /* not behind smmu, use the default reset value(0x0) of the reg as streamID*/ + if (fwspec == NULL) { + dev_dbg(dev, "dev is not behind smmu, skip configuration of sid\n"); + return 0; + } + sid = fwspec->ids[0]; + + regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "eswin,hsp_sp_csr"); + if (IS_ERR(regmap)) { + dev_dbg(dev, "No hsp_sp_csr phandle specified\n"); + return 0; + } + + ret = of_property_read_u32_index(dev->of_node, "eswin,hsp_sp_csr", 1, + &hsp_mmu_dma_reg); + if (ret) { + dev_err(dev, "can't get dma sid cfg reg offset (%d)\n", ret); + return ret; + } + + /* make the reading sid the same as writing sid, ssid is fixed to zero */ + rdwr_sid_ssid = FIELD_PREP(AWSMMUSID, sid); + rdwr_sid_ssid |= FIELD_PREP(ARSMMUSID, sid); + rdwr_sid_ssid |= FIELD_PREP(AWSMMUSSID, 0); + rdwr_sid_ssid |= FIELD_PREP(ARSMMUSSID, 0); + regmap_write(regmap, hsp_mmu_dma_reg, rdwr_sid_ssid); + + ret = win2030_dynm_sid_enable(dev_to_node(dev)); + if (ret < 0) + dev_err(dev, "failed to config dma streamID(%d)!\n", sid); + else + dev_dbg(dev, "success to config dma streamID(%d)!\n", sid); + + return ret; +} +EXPORT_SYMBOL(win2030_dma_sid_cfg); + static int of_parse_syscon_nodes(struct device_node *np, int *nid_p) { #ifdef CONFIG_NUMA diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 4da24d757e1d..21672c33096c 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -16,7 +16,7 @@ obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o obj-$(CONFIG_PWM_CRC) += pwm-crc.o obj-$(CONFIG_PWM_CROS_EC) += pwm-cros-ec.o obj-$(CONFIG_PWM_DWC) += pwm-dwc.o -obj-$(CONFIG_PWM_ESWIN) += pwm-eswin.o +obj-$(CONFIG_PWM_ESWIN) += pwm-dwc-eswin.o obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o obj-$(CONFIG_PWM_HIBVT) += pwm-hibvt.o diff --git a/drivers/pwm/pwm-dwc-eswin.c b/drivers/pwm/pwm-dwc-eswin.c new file mode 100644 index 000000000000..62c2dfcef719 --- /dev/null +++ b/drivers/pwm/pwm-dwc-eswin.c @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DesignWare PWM Controller driver + * + * Copyright (C) 2018-2020 Intel Corporation + * + * Author: Felipe Balbi (Intel) + * Author: Jarkko Nikula + * Author: Raymond Tan + * + * Limitations: + * - The hardware cannot generate a 0 % or 100 % duty cycle. Both high and low + * periods are one or more input clock periods long. + * + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Author: xuxiang@eswincomputing.com + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define DWC_TIM_LD_CNT(n) ((n) * 0x14) +#define DWC_TIM_LD_CNT2(n) (((n) * 4) + 0xb0) +#define DWC_TIM_CUR_VAL(n) (((n) * 0x14) + 0x04) +#define DWC_TIM_CTRL(n) (((n) * 0x14) + 0x08) +#define DWC_TIM_EOI(n) (((n) * 0x14) + 0x0c) +#define DWC_TIM_INT_STS(n) (((n) * 0x14) + 0x10) + +#define DWC_TIMERS_INT_STS 0xa0 +#define DWC_TIMERS_EOI 0xa4 +#define DWC_TIMERS_RAW_INT_STS 0xa8 +#define DWC_TIMERS_COMP_VERSION 0xac + +#define DWC_TIMERS_TOTAL 8 +#define DWC_CLK_PERIOD_NS 10 + +/* Timer Control Register */ +#define DWC_TIM_CTRL_EN BIT(0) +#define DWC_TIM_CTRL_MODE BIT(1) +#define DWC_TIM_CTRL_MODE_FREE (0 << 1) +#define DWC_TIM_CTRL_MODE_USER (1 << 1) +#define DWC_TIM_CTRL_INT_MASK BIT(2) +#define DWC_TIM_CTRL_PWM BIT(3) + +struct dwc_pwm_ctx { + u32 cnt; + u32 cnt2; + u32 ctrl; +}; + +struct dwc_pwm { + struct pwm_chip chip; + void __iomem *base; + struct clk *clk; + struct reset_control *rst; + struct dwc_pwm_ctx ctx[DWC_TIMERS_TOTAL]; +}; +#define to_dwc_pwm(p) (container_of((p), struct dwc_pwm, chip)) + +static inline u32 dwc_pwm_readl(struct dwc_pwm *dwc, u32 offset) +{ + return readl(dwc->base + offset); +} + +static inline void dwc_pwm_writel(struct dwc_pwm *dwc, u32 value, u32 offset) +{ + writel(value, dwc->base + offset); +} + +static void __dwc_pwm_set_enable(struct dwc_pwm *dwc, int pwm, int enabled) +{ + u32 reg; + + reg = dwc_pwm_readl(dwc, DWC_TIM_CTRL(pwm)); + + if (enabled) + reg |= DWC_TIM_CTRL_EN; + else + reg &= ~DWC_TIM_CTRL_EN; + + dwc_pwm_writel(dwc, reg, DWC_TIM_CTRL(pwm)); +} + +static int __dwc_pwm_configure_timer(struct dwc_pwm *dwc, + struct pwm_device *pwm, + const struct pwm_state *state) +{ + u64 tmp; + u32 ctrl; + u32 high; + u32 low; + + /* + * Calculate width of low and high period in terms of input clock + * periods and check are the result within HW limits between 1 and + * 2^32 periods. + */ + tmp = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, DWC_CLK_PERIOD_NS); + if (tmp < 1 || tmp > (1ULL << 32)) + return -ERANGE; + low = tmp - 1; + + tmp = DIV_ROUND_CLOSEST_ULL(state->period - state->duty_cycle, + DWC_CLK_PERIOD_NS); + if (tmp < 1 || tmp > (1ULL << 32)) + return -ERANGE; + high = tmp - 1; + + /* + * Specification says timer usage flow is to disable timer, then + * program it followed by enable. It also says Load Count is loaded + * into timer after it is enabled - either after a disable or + * a reset. Based on measurements it happens also without disable + * whenever Load Count is updated. But follow the specification. + */ + __dwc_pwm_set_enable(dwc, pwm->hwpwm, false); + + /* + * Write Load Count and Load Count 2 registers. Former defines the + * width of low period and latter the width of high period in terms + * multiple of input clock periods: + * Width = ((Count + 1) * input clock period). + */ + dwc_pwm_writel(dwc, low, DWC_TIM_LD_CNT(pwm->hwpwm)); + dwc_pwm_writel(dwc, high, DWC_TIM_LD_CNT2(pwm->hwpwm)); + + /* + * Set user-defined mode, timer reloads from Load Count registers + * when it counts down to 0. + * Set PWM mode, it makes output to toggle and width of low and high + * periods are set by Load Count registers. + */ + ctrl = DWC_TIM_CTRL_MODE_USER | DWC_TIM_CTRL_PWM; + dwc_pwm_writel(dwc, ctrl, DWC_TIM_CTRL(pwm->hwpwm)); + + /* + * Enable timer. Output starts from low period. + */ + __dwc_pwm_set_enable(dwc, pwm->hwpwm, state->enabled); + + return 0; +} + +static int dwc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct dwc_pwm *dwc = to_dwc_pwm(chip); + + if (state->polarity != PWM_POLARITY_INVERSED) + return -EINVAL; + + if (state->enabled) { + if (!pwm->state.enabled) + pm_runtime_get_sync(chip->dev); + return __dwc_pwm_configure_timer(dwc, pwm, state); + } else { + if (pwm->state.enabled) { + __dwc_pwm_set_enable(dwc, pwm->hwpwm, false); + pm_runtime_put_sync(chip->dev); + } + } + + return 0; +} + +static int dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct dwc_pwm *dwc = to_dwc_pwm(chip); + u64 duty, period; + + pm_runtime_get_sync(chip->dev); + + state->enabled = !!(dwc_pwm_readl(dwc, + DWC_TIM_CTRL(pwm->hwpwm)) & DWC_TIM_CTRL_EN); + + duty = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(pwm->hwpwm)); + duty += 1; + duty *= DWC_CLK_PERIOD_NS; + state->duty_cycle = duty; + + period = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(pwm->hwpwm)); + period += 1; + period *= DWC_CLK_PERIOD_NS; + period += duty; + state->period = period; + + state->polarity = PWM_POLARITY_INVERSED; + + pm_runtime_put_sync(chip->dev); + + return 0; +} + +static const struct pwm_ops dwc_pwm_ops = { + .apply = dwc_pwm_apply, + .get_state = dwc_pwm_get_state, + .owner = THIS_MODULE, +}; + +static struct dwc_pwm *dwc_pwm_alloc(struct device *dev) +{ + struct dwc_pwm *dwc; + + dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL); + if (!dwc) + return NULL; + + dwc->chip.dev = dev; + dwc->chip.ops = &dwc_pwm_ops; + dwc->chip.npwm = DWC_TIMERS_TOTAL; + + dev_set_drvdata(dev, dwc); + return dwc; +} + +static int dwc_pwm_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct dwc_pwm *dwc; + int ret; + + dwc = dwc_pwm_alloc(dev); + if (!dwc) + return -ENOMEM; + + dwc->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(dwc->base)) + return PTR_ERR(dwc->base); + + dwc->clk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(dwc->clk)) + return PTR_ERR(dwc->clk); + + ret = clk_prepare_enable(dwc->clk); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable clock: %d\n", ret); + return ret; + } + + dwc->rst = devm_reset_control_get_optional(&pdev->dev, "rst"); + if (IS_ERR(dwc->rst)) + return PTR_ERR(dwc->rst); + + ret = reset_control_deassert(dwc->rst); + if (ret) { + dev_err(&pdev->dev, "failed to deasser reset: %d\n", ret); + return ret; + } + + + ret = devm_pwmchip_add(dev, &dwc->chip); + if (ret) + return ret; + + pm_runtime_put(dev); + pm_runtime_allow(dev); + + return 0; +} + +static int dwc_pwm_remove(struct platform_device *pdev) +{ + struct dwc_pwm *dwc = platform_get_drvdata(pdev); + pwmchip_remove(&dwc->chip); + clk_disable_unprepare(dwc->clk); + reset_control_assert(dwc->rst); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int dwc_pwm_suspend(struct device *dev) +{ + struct dwc_pwm *dwc = dev_get_drvdata(dev); + int i; + + for (i = 0; i < DWC_TIMERS_TOTAL; i++) { + if (dwc->chip.pwms[i].state.enabled) { + dev_err(dev, "PWM %u in use by consumer (%s)\n", + i, dwc->chip.pwms[i].label); + return -EBUSY; + } + dwc->ctx[i].cnt = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(i)); + dwc->ctx[i].cnt2 = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(i)); + dwc->ctx[i].ctrl = dwc_pwm_readl(dwc, DWC_TIM_CTRL(i)); + } + + return 0; +} + +static int dwc_pwm_resume(struct device *dev) +{ + struct dwc_pwm *dwc = dev_get_drvdata(dev); + int i; + + for (i = 0; i < DWC_TIMERS_TOTAL; i++) { + dwc_pwm_writel(dwc, dwc->ctx[i].cnt, DWC_TIM_LD_CNT(i)); + dwc_pwm_writel(dwc, dwc->ctx[i].cnt2, DWC_TIM_LD_CNT2(i)); + dwc_pwm_writel(dwc, dwc->ctx[i].ctrl, DWC_TIM_CTRL(i)); + } + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(dwc_pwm_pm_ops, dwc_pwm_suspend, dwc_pwm_resume); + +static const struct of_device_id dwc_pwm_id_table[] = { + { .compatible = "eswin,pwm-eswin", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, dwc_pwm_id_table); + +static struct platform_driver dwc_pwm_driver = { + .probe = dwc_pwm_probe, + .remove = dwc_pwm_remove, + .driver = { + .name = "dwc-pwm", + .pm = &dwc_pwm_pm_ops, + .of_match_table = of_match_ptr(dwc_pwm_id_table), + }, +}; + +module_platform_driver(dwc_pwm_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("xuxiang "); +MODULE_DESCRIPTION("DesignWare PWM Controller"); diff --git a/drivers/pwm/pwm-eswin.c b/drivers/pwm/pwm-eswin.c deleted file mode 100644 index 139474716da5..000000000000 --- a/drivers/pwm/pwm-eswin.c +++ /dev/null @@ -1,370 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * ESWIN pwm driver - * - * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. - * SPDX-License-Identifier: GPL-2.0 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Author: zhangchunyun@eswincomputing.com - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ESWIN_TIM_LD_CNT(n) ((n) * 0x14) -#define ESWIN_TIM_LD_CNT2(n) (((n) * 4) + 0xb0) -#define ESWIN_TIM_CUR_VAL(n) (((n) * 0x14) + 0x04) -#define ESWIN_TIM_CTRL(n) (((n) * 0x14) + 0x08) -#define ESWIN_TIM_EOI(n) (((n) * 0x14) + 0x0c) -#define ESWIN_TIM_INT_STS(n) (((n) * 0x14) + 0x10) - -#define ESWIN_TIMERS_INT_STS 0xa0 -#define ESWIN_TIMERS_EOI 0xa4 -#define ESWIN_TIMERS_RAW_INT_STS 0xa8 -#define ESWIN_TIMERS_COMP_VERSION 0xac - -#define ESWIN_TIMERS_TOTAL 8 -#define NSEC_TO_SEC 1000000000 - -/* Timer Control Register */ -#define ESWIN_TIM_CTRL_EN BIT(0) -#define ESWIN_TIM_CTRL_MODE BIT(1) -#define ESWIN_TIM_CTRL_MODE_FREE (0 << 1) -#define ESWIN_TIM_CTRL_MODE_USER (1 << 1) -#define ESWIN_TIM_CTRL_INT_MASK BIT(2) -#define ESWIN_TIM_CTRL_PWM BIT(3) - -struct eswin_pwm_ctx { - u32 cnt; - u32 cnt2; - u32 ctrl; -}; - -struct eswin_pwm { - struct pwm_chip chip; - void __iomem *base; - struct clk *clk; - struct clk *pclk; - struct eswin_pwm_ctx ctx[ESWIN_TIMERS_TOTAL]; - struct reset_control * pwm_rst; - u32 clk_period_ns; -}; - -#define to_eswin_pwm(p) (container_of((p), struct eswin_pwm, chip)) - -static inline u32 eswin_pwm_readl(struct eswin_pwm *eswin, u32 offset) -{ - return readl(eswin->base + offset); -} - -static inline void eswin_pwm_writel(struct eswin_pwm *eswin, u32 value, u32 offset) -{ - writel(value, eswin->base + offset); -} - -static void __eswin_pwm_set_enable(struct eswin_pwm *eswin, int pwm, int enabled) -{ - u32 reg; - - reg = eswin_pwm_readl(eswin, ESWIN_TIM_CTRL(pwm)); - - if (enabled) - reg |= ESWIN_TIM_CTRL_EN; - else - reg &= ~ESWIN_TIM_CTRL_EN; - - eswin_pwm_writel(eswin, reg, ESWIN_TIM_CTRL(pwm)); - reg = eswin_pwm_readl(eswin, ESWIN_TIM_CTRL(pwm)); -} - -static int __eswin_pwm_configure_timer(struct eswin_pwm *eswin, - struct pwm_device *pwm, - const struct pwm_state *state) -{ - u64 tmp; - u32 ctrl; - u32 high; - u32 low; - - /* - ¦* Calculate width of low and high period in terms of input clock - ¦* periods and check are the result within HW limits between 1 and - ¦* 2^32 periods. - ¦*/ - - tmp = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, eswin->clk_period_ns); - if (tmp < 1 || tmp > (1ULL << 32)) - return -ERANGE; - high = tmp - 1; - - tmp = DIV_ROUND_CLOSEST_ULL(state->period - state->duty_cycle, - eswin->clk_period_ns); - if (tmp < 1 || tmp > (1ULL << 32)) - return -ERANGE; - low = tmp - 1; - /* - ¦* Specification says timer usage flow is to disable timer, then - ¦* program it followed by enable. It also says Load Count is loaded - ¦* into timer after it is enabled - either after a disable or - ¦* a reset. Based on measurements it happens also without disable - ¦* whenever Load Count is updated. But follow the specification. - ¦*/ - __eswin_pwm_set_enable(eswin, pwm->hwpwm, false); - - /* - ¦* Write Load Count and Load Count 2 registers. Former defines the - ¦* width of low period and latter the width of high period in terms - ¦* multiple of input clock periods: - ¦* Width = ((Count + 1) * input clock period). - ¦*/ - eswin_pwm_writel(eswin, low, ESWIN_TIM_LD_CNT(pwm->hwpwm)); - eswin_pwm_writel(eswin, high, ESWIN_TIM_LD_CNT2(pwm->hwpwm)); - - /* - ¦* Set user-defined mode, timer reloads from Load Count registers - ¦* when it counts down to 0. - ¦* Set PWM mode, it makes output to toggle and width of low and high - ¦* periods are set by Load Count registers. - ¦*/ - ctrl = ESWIN_TIM_CTRL_MODE_USER | ESWIN_TIM_CTRL_PWM; - eswin_pwm_writel(eswin, ctrl, ESWIN_TIM_CTRL(pwm->hwpwm)); - - /* - ¦* Enable timer. Output starts from low period. - ¦*/ - __eswin_pwm_set_enable(eswin, pwm->hwpwm, state->enabled); - - return 0; -} - -static int eswin_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - const struct pwm_state *state) -{ - struct eswin_pwm *eswin = to_eswin_pwm(chip); - struct pwm_state curstate; - int ret = 0; - - ret = clk_enable(eswin->pclk); - - ret = clk_enable(eswin->clk); - - pwm_get_state(pwm, &curstate); - - __eswin_pwm_configure_timer(eswin, pwm, state); - - return 0; -} - -static int eswin_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) -{ - struct eswin_pwm *eswin = to_eswin_pwm(chip); - u64 duty, period; - - pm_runtime_get_sync(chip->dev); - - state->enabled = !!(eswin_pwm_readl(eswin, - ESWIN_TIM_CTRL(pwm->hwpwm)) & ESWIN_TIM_CTRL_EN); - - duty = eswin_pwm_readl(eswin, ESWIN_TIM_LD_CNT(pwm->hwpwm)); - duty += 1; - duty *= eswin->clk_period_ns; - state->duty_cycle = duty; - - period = eswin_pwm_readl(eswin, ESWIN_TIM_LD_CNT2(pwm->hwpwm)); - period += 1; - period *= eswin->clk_period_ns; - period += duty; - state->period = period; - - state->polarity = PWM_POLARITY_INVERSED; - - pm_runtime_put_sync(chip->dev); - - return 0; -} - - -static const struct pwm_ops eswin_pwm_ops = { - .apply = eswin_pwm_apply, - .get_state = eswin_pwm_get_state, - .owner = THIS_MODULE, -}; - -static const struct of_device_id eswin_pwm_dt_ids[] = { - { .compatible = "eswin,pwm-eswin", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, eswin_pwm_dt_ids); - -static int eswin_pwm_probe(struct platform_device *pdev) -{ - struct eswin_pwm *pc; - int ret, count; - struct resource *res; - int clk_rate; -/* unsigned long *conf, *conf1, *conf2; - unsigned int val, val1, val2; - - ret = of_property_read_u32_index(pdev->dev.of_node, "pinctrl-pwm", 0, &val); - if(ret){ - dev_err(&pdev->dev, "Can't get pwm pin0\n"); - return -1; - } - - ret = of_property_read_u32_index(pdev->dev.of_node, "pinctrl-pwm", 1, &val1); - if(ret){ - dev_err(&pdev->dev, "Can't get pwm pin1\n"); - return -1; - } - - ret = of_property_read_u32_index(pdev->dev.of_node, "pinctrl-pwm", 2, &val2); - if(ret){ - dev_err(&pdev->dev, "Can't get pwm pin2\n"); - return -1; - } - conf = (unsigned long *)(&val); - conf1 = (unsigned long *)(&val1); - conf2 = (unsigned long *)(&val2); - - eswin_pinconf_cfg_set(NULL,147, conf,32); - eswin_pinconf_cfg_set(NULL,116, conf1,32); - eswin_pinconf_cfg_set(NULL,117, conf2,32); -*/ - pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); - if (!pc) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - pc->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(pc->base)) - return PTR_ERR(pc->base); - - pc->clk = devm_clk_get(&pdev->dev, "pwm"); - if (IS_ERR(pc->clk)) { - pc->clk = devm_clk_get(&pdev->dev, "pclk"); - if (IS_ERR(pc->clk)) - return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk), - "Can't get PWM clk\n"); - } - - count = of_count_phandle_with_args(pdev->dev.of_node, - "clocks", "#clock-cells"); - if (count == 2) - pc->pclk = devm_clk_get(&pdev->dev, "pclk"); - else - pc->pclk = pc->clk; - - if (IS_ERR(pc->pclk)) { - ret = PTR_ERR(pc->pclk); - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "Can't get APB clk: %d\n", ret); - return ret; - } - - clk_rate = clk_get_rate(pc->pclk); - pc->clk_period_ns = DIV_ROUND_CLOSEST_ULL(NSEC_TO_SEC, clk_rate); - /* pwm reset init */ - pc->pwm_rst = devm_reset_control_get_optional(&pdev->dev, "pwmrst"); - if(IS_ERR_OR_NULL(pc->pwm_rst)) { - dev_err(&pdev->dev, "Failed to get pwmrst reset handle\n"); - return -EFAULT; - } - - ret = clk_prepare_enable(pc->clk); - if (ret) { - dev_err(&pdev->dev, "Can't prepare enable PWM clk: %d\n", ret); - return ret; - } - - ret = clk_prepare_enable(pc->pclk); - if (ret) { - dev_err(&pdev->dev, "Can't prepare enable APB clk: %d\n", ret); - goto err_clk; - } - - /* reset pwm */ - ret = reset_control_assert(pc->pwm_rst); - WARN_ON(0 != ret); - ret = reset_control_deassert(pc->pwm_rst); - WARN_ON(0 != ret); - - platform_set_drvdata(pdev, pc); - - pc->chip.dev = &pdev->dev; - pc->chip.ops = &eswin_pwm_ops; - pc->chip.npwm = 3; - - ret = pwmchip_add(&pc->chip); - if (ret < 0) { - dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); - goto err_pclk; - } - dev_err(&pdev->dev, "eswin pwm init success \n"); - - return 0; - -err_pclk: - clk_disable_unprepare(pc->pclk); -err_clk: - clk_disable_unprepare(pc->clk); - - return ret; -} - -static int eswin_pwm_remove(struct platform_device *pdev) -{ - struct eswin_pwm *pc = platform_get_drvdata(pdev); - - pwmchip_remove(&pc->chip); - - clk_disable_unprepare(pc->pclk); - clk_disable_unprepare(pc->clk); - - return 0; -} - -static struct platform_driver eswin_pwm_driver = { - .driver = { - .name = "eswin-pwm", - .of_match_table = eswin_pwm_dt_ids, - }, - .probe = eswin_pwm_probe, - .remove = eswin_pwm_remove, -}; -module_platform_driver(eswin_pwm_driver); - -MODULE_DESCRIPTION("eswin SoC PWM driver"); -MODULE_AUTHOR("zhangchunyun@eswincomputing.com"); -MODULE_LICENSE("GPL"); - diff --git a/include/linux/eswin-win2030-sid-cfg.h b/include/linux/eswin-win2030-sid-cfg.h index c52268d06f7d..98637b5eac8a 100644 --- a/include/linux/eswin-win2030-sid-cfg.h +++ b/include/linux/eswin-win2030-sid-cfg.h @@ -3,6 +3,7 @@ int win2030_dynm_sid_enable(int nid); int win2030_aon_sid_cfg(struct device *dev); +int win2030_dma_sid_cfg(struct device *dev); int win2030_tbu_power(struct device *dev, bool is_powerUp); int win2030_tbu_power_by_dev_and_node(struct device *dev, struct device_node *node, bool is_powerUp); -- 2.47.0