--- /dev/null
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/riscv/starfive.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive JH7110 SoC-based boards
+
+maintainers:
+ - Michael Zhu <michael.zhu@starfivetech.com>
+ - Jianlong Huang <jianlong.huang@starfivetech.com>
+
+description:
+ StarFive JH7110 SoC-based boards
+
+properties:
+ $nodename:
+ const: '/'
+ compatible:
+ oneOf:
+ - items:
+ - const: starfive,jh7110
+ - const: starfive,jh7110-evb
+ - const: starfive,visionfive-v2
+
+additionalProperties: true
+
+...
T: git git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
F: *
F: */
+
+STARFIVE JH7110 EVB USB DEVICE SUPPORT
+M: Jianlong Huang <jianlong.huang@starfivetech.com>
+S: Maintained
+F: arch/riscv/boot/dts/starfive/jh7110-evb-usbdevice.dts
+
+STARFIVE JH7110 SOC BOARDS
+M: Jianlong Huang <jianlong.huang@starfivetech.com>
+S: Maintained
+F: Documentation/devicetree/bindings/riscv/starfive-jh7110.yaml
+
jh7110-evb-spi-uart2.dtb \
jh7110-evb-uart1-rgb2hdmi.dtb \
jh7110-evb-uart4-emmc-spdif.dtb \
- jh7110-evb-uart5-pwm-i2c-tdm.dtb
+ jh7110-evb-uart5-pwm-i2c-tdm.dtb\
+ jh7110-evb-usbdevice.dtb
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+/*
+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
+ * Copyright (C) 2022 Hal Feng <hal.feng@starfivetech.com>
+ */
+
+/dts-v1/;
+#include "jh7110-evb.dtsi"
+
+/ {
+ model = "StarFive JH7110 EVB";
+ compatible = "starfive,jh7110-evb", "starfive,jh7110";
+};
+
+/* default sd card */
+&sdio0 {
+ clock-frequency = <102400000>;
+ max-frequency = <200000000>;
+ card-detect-delay = <300>;
+ bus-width = <4>;
+ broken-cd;
+ cap-sd-highspeed;
+ post-power-on-delay-ms = <200>;
+ status = "okay";
+};
+
+&usbdrd30 {
+ dr_mode = "peripheral"; /*host or peripheral*/
+ status = "okay";
+};
+
+
+&pcie1 {
+ status = "okay";
+};
#address-cells = <2>;
#size-cells = <2>;
+ cluster0_opp: opp-table-0 {
+ compatible = "operating-points-v2";
+ opp-shared;
+ opp-375000000 {
+ opp-hz = /bits/ 64 <375000000>;
+ opp-microvolt = <880000>;
+ };
+ opp-500000000 {
+ opp-hz = /bits/ 64 <500000000>;
+ opp-microvolt = <880000>;
+ };
+ opp-625000000 {
+ opp-hz = /bits/ 64 <625000000>;
+ opp-microvolt = <880000>;
+ };
+ opp-750000000 {
+ opp-hz = /bits/ 64 <750000000>;
+ opp-microvolt = <880000>;
+ };
+ opp-875000000 {
+ opp-hz = /bits/ 64 <875000000>;
+ opp-microvolt = <880000>;
+ };
+ opp-1000000000 {
+ opp-hz = /bits/ 64 <1000000000>;
+ opp-microvolt = <900000>;
+ };
+ opp-1250000000 {
+ opp-hz = /bits/ 64 <1250000000>;
+ opp-microvolt = <950000>;
+ };
+ opp-1375000000 {
+ opp-hz = /bits/ 64 <1375000000>;
+ opp-microvolt = <1000000>;
+ };
+ opp-1500000000 {
+ opp-hz = /bits/ 64 <1500000000>;
+ opp-microvolt = <1100000>;
+ };
+ opp-1625000000 {
+ opp-hz = /bits/ 64 <1625000000>;
+ opp-microvolt = <1100000>;
+ };
+ opp-1750000000 {
+ opp-hz = /bits/ 64 <1750000000>;
+ opp-microvolt = <1200000>;
+ };
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
riscv,isa = "rv64imafdc";
tlb-split;
status = "okay";
+ operating-points-v2 = <&cluster0_opp>;
cpu1intctrl: interrupt-controller {
#interrupt-cells = <1>;
riscv,isa = "rv64imafdc";
tlb-split;
status = "okay";
+ operating-points-v2 = <&cluster0_opp>;
cpu2intctrl: interrupt-controller {
#interrupt-cells = <1>;
riscv,isa = "rv64imafdc";
tlb-split;
status = "okay";
+ operating-points-v2 = <&cluster0_opp>;
cpu3intctrl: interrupt-controller {
#interrupt-cells = <1>;
riscv,isa = "rv64imafdc";
tlb-split;
status = "okay";
+ operating-points-v2 = <&cluster0_opp>;
cpu4intctrl: interrupt-controller {
#interrupt-cells = <1>;
dsp@0 {
};
};
+
+ stf_cpufreq: starfive,stf-cpufreq {
+ compatible = "starfive,stf-cpufreq";
+ clocks = <&clkgen JH7110_PLL0_OUT>,
+ <&clkgen JH7110_CPU_ROOT>,
+ <&osc>;
+ clock-names = "pll0", "cpu_clk", "osc";
+ };
};
};
source "drivers/xrp/Kconfig"
+source "drivers/cpufreq/Kconfig"
+
endmenu
which are capable of changing the CPU's frequency dynamically.
endif
+
+if RISCV
+source "drivers/cpufreq/Kconfig.riscv"
+endif
endmenu
--- /dev/null
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# RISCV CPU Frequency scaling drivers
+#
+
+config RISCV_STARFIVE_CPUFREQ
+ bool "Starfive JH7110"
+ depends on SOC_STARFIVE
+ default y
+ help
+ This adds the CPUFreq driver for Starfive SoC.
+
+ If in doubt, say N.
+
+
obj-$(CONFIG_POWERNV_CPUFREQ) += powernv-cpufreq.o
##################################################################################
+# Riscv platform drivers
+obj-$(CONFIG_RISCV_STARFIVE_CPUFREQ) += starfive-cpufreq.o
+
+##################################################################################
# Other platform drivers
obj-$(CONFIG_BMIPS_CPUFREQ) += bmips-cpufreq.o
obj-$(CONFIG_IA64_ACPI_CPUFREQ) += ia64-acpi-cpufreq.o
{ .compatible = "qcom,apq8064", },
{ .compatible = "qcom,msm8974", },
{ .compatible = "qcom,msm8960", },
+ { .compatible = "starfive,jh7110", },
{ }
};
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2022 StarFive Technology Co., Ltd.
+ *
+ * Starfive CPUfreq Support
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <linux/module.h>
+
+#define VOLT_TOL (10000)
+
+struct stf_cpu_dvfs_info {
+ struct regulator *vddcpu;
+ struct clk *cpu_clk;
+ struct clk *pll0_clk;
+ struct clk *osc_clk;
+ unsigned long regulator_latency;
+ struct device *cpu_dev;
+ struct cpumask cpus;
+};
+
+static int stf_cpufreq_set_target_index(struct cpufreq_policy *policy,
+ unsigned int index)
+{
+ struct cpufreq_frequency_table *freq_table = policy->freq_table;
+ struct stf_cpu_dvfs_info *info = cpufreq_get_driver_data();
+ struct dev_pm_opp *opp;
+ unsigned long old_freq, new_freq;
+ int old_vdd, target_vdd, ret;
+
+ old_freq = clk_get_rate(info->cpu_clk);
+ old_vdd = regulator_get_voltage(info->vddcpu);
+ if (old_vdd < 0) {
+ pr_err("Invalid cpu regulator value: %d\n", old_vdd);
+ return old_vdd;
+ }
+
+ new_freq = freq_table[index].frequency * 1000;
+ opp = dev_pm_opp_find_freq_ceil(info->cpu_dev, &new_freq);
+ if (IS_ERR(opp)) {
+ pr_err("Failed to find OPP for %ld\n", new_freq);
+ return PTR_ERR(opp);
+ }
+ target_vdd = dev_pm_opp_get_voltage(opp);
+ dev_pm_opp_put(opp);
+
+
+ if (info->vddcpu && new_freq > old_freq) {
+ ret = regulator_set_voltage(info->vddcpu,
+ target_vdd, target_vdd + VOLT_TOL);
+ if (ret != 0) {
+ pr_err("Failed to set vddcpu for %ldkHz: %d\n",
+ new_freq, ret);
+ return ret;
+ }
+ }
+
+ if (clk_set_parent(policy->clk, info->osc_clk))
+ pr_err("cpu set parent osc failed\n");
+
+ ret = clk_set_rate(info->pll0_clk, new_freq);
+ if (ret < 0) {
+ pr_err("Failed to set rate %ldkHz: %d\n",
+ new_freq, ret);
+ }
+ if (clk_set_parent(policy->clk, info->pll0_clk))
+ pr_err("cpu set parent pll0 failed\n");
+
+ if (info->vddcpu && new_freq < old_freq) {
+ ret = regulator_set_voltage(info->vddcpu,
+ target_vdd, target_vdd + VOLT_TOL);
+ if (ret != 0) {
+ pr_err("Failed to set vddcpu for %ldkHz: %d\n",
+ new_freq, ret);
+ if (clk_set_rate(policy->clk, old_freq * 1000) < 0)
+ pr_err("Failed to restore original clock rate\n");
+
+ return ret;
+ }
+ }
+
+ pr_debug("Set actual frequency %lukHz\n",
+ clk_get_rate(policy->clk) / 1000);
+
+ return 0;
+}
+
+static int stf_cpufreq_driver_init(struct cpufreq_policy *policy)
+{
+ struct stf_cpu_dvfs_info *info = cpufreq_get_driver_data();
+ struct cpufreq_frequency_table *freq_table;
+ int ret;
+
+ ret = dev_pm_opp_init_cpufreq_table(info->cpu_dev, &freq_table);
+ if (ret) {
+ pr_err("Failed to init cpufreq table for cpu%d: %d\n",
+ policy->cpu, ret);
+ return ret;
+ }
+
+ cpumask_copy(policy->cpus, &info->cpus);
+ policy->freq_table = freq_table;
+ policy->driver_data = info;
+ policy->clk = info->cpu_clk;
+
+ return 0;
+}
+
+static int stf_cpu_dvfs_info_init(struct platform_device *pdev,
+ struct stf_cpu_dvfs_info *info)
+{
+ struct device *dev = &pdev->dev;
+ int ret;
+ static int retry = 3;
+
+ info->vddcpu = regulator_get_optional(&pdev->dev, "cpu_vdd_0p9");
+ if (IS_ERR(info->vddcpu)) {
+ if (PTR_ERR(info->vddcpu) == -EPROBE_DEFER)
+ dev_warn(&pdev->dev, "The cpu regulator is not ready, retry.\n");
+ else
+ dev_err(&pdev->dev, "Failed to get regulator for cpu\n");
+ if (retry-- > 0)
+ return -EPROBE_DEFER;
+ else
+ return PTR_ERR(info->vddcpu);
+ }
+
+ info->cpu_clk = devm_clk_get(dev, "cpu_clk");
+ if (IS_ERR(info->cpu_clk)) {
+ dev_err(&pdev->dev, "Unable to obtain cpu_clk: %ld\n",
+ PTR_ERR(info->cpu_clk));
+ return PTR_ERR(info->cpu_clk);
+ }
+ info->pll0_clk = devm_clk_get(dev, "pll0");
+ if (IS_ERR(info->pll0_clk)) {
+ dev_err(&pdev->dev, "Unable to obtain cpu_clk: %ld\n",
+ PTR_ERR(info->pll0_clk));
+ return PTR_ERR(info->pll0_clk);
+ }
+
+ info->osc_clk = devm_clk_get(dev, "osc");
+ if (IS_ERR(info->osc_clk)) {
+ dev_err(&pdev->dev, "Unable to obtain osc_clk: %ld\n",
+ PTR_ERR(info->osc_clk));
+ return PTR_ERR(info->osc_clk);
+ }
+
+ info->cpu_dev = get_cpu_device(1);
+ if (!info->cpu_dev) {
+ dev_err(&pdev->dev, "Failed to get cpu device\n");
+ return -ENODEV;
+ }
+ /* Get OPP-sharing information from "operating-points-v2" bindings */
+ ret = dev_pm_opp_of_get_sharing_cpus(info->cpu_dev, &info->cpus);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to get OPP-sharing information for cpu\n");
+ return -EINVAL;
+ }
+
+ ret = dev_pm_opp_of_cpumask_add_table(&info->cpus);
+ if (ret) {
+ pr_warn("no OPP table for cpu\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct cpufreq_driver stf_cpufreq_driver = {
+ .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
+ .verify = cpufreq_generic_frequency_table_verify,
+ .target_index = stf_cpufreq_set_target_index,
+ .get = cpufreq_generic_get,
+ .init = stf_cpufreq_driver_init,
+ .name = "stf-cpufreq",
+ .attr = cpufreq_generic_attr,
+};
+
+static int stf_cpufreq_probe(struct platform_device *pdev)
+{
+ struct stf_cpu_dvfs_info *info;
+ int ret;
+
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ ret = stf_cpu_dvfs_info_init(pdev, info);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to init stf cpu dvfs info\n");
+ return ret;
+ }
+
+ stf_cpufreq_driver.driver_data = info;
+ ret = cpufreq_register_driver(&stf_cpufreq_driver);
+ if (ret)
+ dev_err(&pdev->dev, "Failed to register stf cpufreq driver\n");
+
+ return ret;
+
+}
+
+static const struct of_device_id stf_cpufreq_match_table[] = {
+ { .compatible = "starfive,stf-cpufreq" },
+ {}
+};
+
+static struct platform_driver stf_cpufreq_plat_driver = {
+ .probe = stf_cpufreq_probe,
+ .driver = {
+ .name = "stf-cpufreq",
+ .of_match_table = stf_cpufreq_match_table,
+ },
+};
+
+static int __init stf_cpufreq_init(void)
+{
+ return platform_driver_register(&stf_cpufreq_plat_driver);
+}
+postcore_initcall(stf_cpufreq_init);
+
+MODULE_DESCRIPTION("STARFIVE CPUFREQ Driver");
+MODULE_AUTHOR("Mason Huuo <mason.huo@starfivetech.com>");
+MODULE_LICENSE("GPL v2");
+
mlen = total_len / sizeof(u32);// DIV_ROUND_UP(total_len, sizeof(u32));
buffer = (unsigned int *)ctx->buffer;
- for (loop = 0; loop < mlen; loop++, buffer++)
+ for (loop = 0; loop < mlen; loop++, buffer++) {
jh7110_sec_write(sdev, JH7110_SHA_SHAWDR, *buffer);
+ udelay(2);
+ }
if (total_len & 0x3) {
cl = (unsigned char *)buffer;
- for (loop = 0; loop < (total_len & 0x3); loop++, cl++)
+ for (loop = 0; loop < (total_len & 0x3); loop++, cl++) {
jh7110_sec_writeb(sdev, JH7110_SHA_SHAWDR, *cl);
+ udelay(2);
+ }
}
return 0;
};
static const struct pre_pll_config pre_pll_cfg_table[] = {
+ { 25175000, 25175000, 1, 100, 2, 3, 3, 12, 3, 3, 4, 0, 0},
{ 25200000, 25200000, 1, 100, 2, 3, 3, 12, 3, 3, 4, 0, 0},
{ 27000000, 27000000, 1, 90, 3, 2, 2, 10, 3, 3, 4, 0, 0},
{ 27000000, 33750000, 1, 90, 1, 3, 3, 10, 3, 3, 4, 0, 0},
rate = (rate / 1000) * 1000;
for (; cfg->pixclock != 0; cfg++)
- if (cfg->tmdsclock == rate)
+ if (cfg->tmdsclock == rate && cfg->pixclock == rate)
break;
if (cfg->pixclock == 0)
update_swizzle(drm_fb->format->format, fb);
update_watermark(plane_state->watermark, fb);
+ starfive_flush_dcache(fb->y_address, fb->height * fb->y_stride);
+ if (fb->u_address)
+ starfive_flush_dcache(fb->u_address, fb->height * fb->u_stride);
+ if (fb->v_address)
+ starfive_flush_dcache(fb->v_address, fb->height * fb->v_stride);
+
plane_state->status.tile_mode = fb->tile_mode;
}
for (i = 0; i < dc_info->panel_num; i++)
vs_crtc_handle_vblank(&dc->crtc[i]->base, dc_hw_check_underflow(&dc->hw));
- starfive_flush_dcache(dc->hw.plane[0].fb.y_address,
- dc->hw.plane[0].fb.width * dc->hw.plane[0].fb.height*4);
- starfive_flush_dcache(dc->hw.plane[1].fb.y_address,
- dc->hw.plane[1].fb.width * dc->hw.plane[1].fb.height*4);
- starfive_flush_dcache(dc->hw.plane[2].fb.y_address,
- dc->hw.plane[2].fb.width * dc->hw.plane[2].fb.height*4);
- starfive_flush_dcache(dc->hw.plane[3].fb.y_address,
- dc->hw.plane[3].fb.width * dc->hw.plane[3].fb.height*4);
- starfive_flush_dcache(dc->hw.plane[4].fb.y_address,
- dc->hw.plane[4].fb.width * dc->hw.plane[4].fb.height*4);
- starfive_flush_dcache(dc->hw.plane[5].fb.y_address,
- dc->hw.plane[5].fb.width * dc->hw.plane[5].fb.height*4);
- starfive_flush_dcache(dc->hw.plane[6].fb.y_address,
- dc->hw.plane[6].fb.width * dc->hw.plane[6].fb.height*4);
- starfive_flush_dcache(dc->hw.plane[7].fb.y_address,
- dc->hw.plane[7].fb.width * dc->hw.plane[7].fb.height*4);
-
return IRQ_HANDLED;
}
#define RDMA_LINK (0xA2)
#define RDMA_SINT (0xA3)
#define RDMA_END (0xAF)
-
+#define ENABLE_SS0_SS1
enum _STF_ISP_IOCTL {
STF_ISP_IOCTL_LOAD_FW = BASE_VIDIOC_PRIVATE + 1,
//strlcpy(vdev->name, name, sizeof(vdev->name));
strscpy(vdev->name, name, sizeof(vdev->name));
- ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+ ret = video_register_device(vdev, VFL_TYPE_VIDEO, video->id);
if (ret < 0) {
st_err(ST_VIDEO,
"Failed to register video device: %d\n",
char *sub_name = get_line_subdevname(i);
int is_mp;
+#ifdef STF_CAMSS_SKIP_ITI
+ if ((stf_vin_map_isp_line(i) == STF_ISP_LINE_SRC_ITIW) ||
+ (stf_vin_map_isp_line(i) == STF_ISP_LINE_SRC_ITIR))
+ continue;
+#endif
is_mp = (stf_vin_map_isp_line(i) == STF_ISP_LINE_SRC) ? true : false;
is_mp = false;
sd = &vin_dev->line[i].subdev;
goto err_link;
}
+#ifndef STF_CAMSS_SKIP_ITI
ret = media_create_pad_link(
&isp_dev->subdev.entity,
STF_ISP_PAD_SRC_ITIW,
ret);
goto err_link;
}
+#endif
ret = media_create_pad_link(
&isp_dev->subdev.entity,
#define STF_PAD_SRC 1
#define STF_PADS_NUM 2
+#define STF_CAMSS_SKIP_ITI
+
enum port_num {
DVP_SENSOR_PORT_NUMBER = 0,
CSI2RX_SENSOR_PORT_NUMBER