mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
Merge commit '33f4a54037590ce6bf13e3568e33685dbe752588'
* commit '33f4a54037590ce6bf13e3568e33685dbe752588': fiq_debugger: tty write to tty fifo ARM: dts: rockchip: rv1106 boards: Add sdmmc idle state support ARM: dts: rockchip: rv1126: Add sdmmc idle state support ARM: dts: rockchip: add idle state for sdmmc of rv1106-pinctrl ARM: dts: rockchip: add idle state for sdmmc of rv1126-pinctrl media: i2c: max96712: version 1.04.00 media: rockchip: vicap: fixes s_selection, support to set crop area media: rockchip: vicap: only enum outout formats that terminal sensor support to use media: rockchip: vicap: add security testing for output format arm64: dts: rockchip: rk3528-demo: Enable dfi arm64: dts: rockchip: rk3528-evb: Enable dfi arm64: dts: rockchip: rk3528: Add ddr related nodes PM / devfreq: rockchip_dmc: Add support for rk3528 dt-bindings: devfreq: rockchip_dmc: Add rk3528 support PM / devfreq: rockchip-dfi: Add support for rk3528 dfi dt-bindings: devfreq: rockchip_dfi: Add rk3528 support Change-Id: I57b0ee5b5bbbcbba0c40f447f4a866775d2743c7
This commit is contained in:
@@ -10,6 +10,7 @@ Required properties:
|
||||
- "rockchip,rk3328-dfi" - for RK3328 SoCs.
|
||||
- "rockchip,rk3368-dfi" - for RK3368 SoCs.
|
||||
- "rockchip,rk3399-dfi" - for RK3399 SoCs.
|
||||
- "rockchip,rk3528-dfi" - for RK3528 SoCs.
|
||||
- "rockchip,rk3562-dfi" - for RK3562 SoCs.
|
||||
- "rockchip,rk3568-dfi" - for RK3568 SoCs.
|
||||
- "rockchip,rv1126-dfi" - for RV1126 SoCs.
|
||||
|
||||
@@ -10,6 +10,7 @@ Required properties:
|
||||
- "rockchip,rk3308-dmc" - for RK3308 SoCs.
|
||||
- "rockchip,rk3328-dmc" - for RK3328 SoCs.
|
||||
- "rockchip,rk3399-dmc" - for RK3399 SoCs.
|
||||
- "rockchip,rk3528-dmc" - for RK3528 SoCs.
|
||||
- "rockchip,rk3562-dmc" - for RK3562 SoCs.
|
||||
- "rockchip,rk3568-dmc" - for RK3568 SoCs.
|
||||
- "rockchip,rk3588-dmc" - for RK3588 SoCs.
|
||||
|
||||
@@ -81,8 +81,9 @@
|
||||
cap-mmc-highspeed;
|
||||
cap-sd-highspeed;
|
||||
disable-wp;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-names = "normal", "idle";
|
||||
pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>;
|
||||
pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
@@ -286,8 +286,9 @@
|
||||
cap-sdio-irq;
|
||||
keep-power-in-suspend;
|
||||
non-removable;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-names = "normal", "idle";
|
||||
pinctrl-0 = <&sdmmc1m1_cmd &sdmmc1m1_clk &sdmmc1m1_bus4>;
|
||||
pinctrl-1 = <&sdmmc1m1_idle_pins>;
|
||||
no-prescan-powerup;
|
||||
post-power-on-delay-ms = <0>;
|
||||
status = "okay";
|
||||
|
||||
@@ -287,8 +287,9 @@
|
||||
cap-sdio-irq;
|
||||
keep-power-in-suspend;
|
||||
non-removable;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-names = "normal", "idle";
|
||||
pinctrl-0 = <&sdmmc1m1_cmd &sdmmc1m1_clk &sdmmc1m1_bus4>;
|
||||
pinctrl-1 = <&sdmmc1m1_idle_pins>;
|
||||
no-prescan-powerup;
|
||||
post-power-on-delay-ms = <0>;
|
||||
status = "okay";
|
||||
|
||||
@@ -288,8 +288,9 @@
|
||||
cap-mmc-highspeed;
|
||||
cap-sd-highspeed;
|
||||
disable-wp;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-names = "normal", "idle";
|
||||
pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>;
|
||||
pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
@@ -731,6 +731,17 @@
|
||||
/* sdmmc0_det */
|
||||
<3 RK_PA1 1 &pcfg_pull_up>;
|
||||
};
|
||||
|
||||
/omit-if-no-ref/
|
||||
sdmmc0_idle_pins: sdmmc0-idle-pins {
|
||||
rockchip,pins =
|
||||
<3 RK_PA2 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<3 RK_PA3 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_down>;
|
||||
};
|
||||
};
|
||||
|
||||
sdmmc1 {
|
||||
@@ -768,6 +779,17 @@
|
||||
<2 RK_PA3 1 &pcfg_pull_up_drv_level_2>;
|
||||
};
|
||||
|
||||
/omit-if-no-ref/
|
||||
sdmmc1m0_idle_pins: sdmmc1m0-idle-pins {
|
||||
rockchip,pins =
|
||||
<2 RK_PA0 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<2 RK_PA1 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<2 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<2 RK_PA5 RK_FUNC_GPIO &pcfg_pull_down>;
|
||||
};
|
||||
|
||||
/omit-if-no-ref/
|
||||
sdmmc1m1_bus4: sdmmc1m1-bus4 {
|
||||
rockchip,pins =
|
||||
@@ -794,6 +816,17 @@
|
||||
/* sdmmc1_cmd_m1 */
|
||||
<1 RK_PC3 5 &pcfg_pull_up_drv_level_2>;
|
||||
};
|
||||
|
||||
/omit-if-no-ref/
|
||||
sdmmc1m1_idle_pins: sdmmc1m1-idle-pins {
|
||||
rockchip,pins =
|
||||
<1 RK_PC0 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<1 RK_PC3 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<1 RK_PC4 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_down>;
|
||||
};
|
||||
};
|
||||
|
||||
spi0 {
|
||||
|
||||
@@ -61,8 +61,9 @@
|
||||
cap-mmc-highspeed;
|
||||
cap-sd-highspeed;
|
||||
disable-wp;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-names = "normal", "idle";
|
||||
pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>;
|
||||
pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>;
|
||||
vmmc-supply = <&vcc3v3_sd>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -150,8 +150,9 @@
|
||||
cap-mmc-highspeed;
|
||||
cap-sd-highspeed;
|
||||
disable-wp;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-names = "normal", "idle";
|
||||
pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>;
|
||||
pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>;
|
||||
sd-uhs-sdr12;
|
||||
sd-uhs-sdr25;
|
||||
sd-uhs-sdr50;
|
||||
|
||||
@@ -150,8 +150,9 @@
|
||||
cap-mmc-highspeed;
|
||||
cap-sd-highspeed;
|
||||
disable-wp;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-names = "normal", "idle";
|
||||
pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>;
|
||||
pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>;
|
||||
sd-uhs-sdr12;
|
||||
sd-uhs-sdr25;
|
||||
sd-uhs-sdr50;
|
||||
|
||||
@@ -140,8 +140,9 @@
|
||||
cap-mmc-highspeed;
|
||||
cap-sd-highspeed;
|
||||
disable-wp;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-names = "normal", "idle";
|
||||
pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>;
|
||||
pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>;
|
||||
sd-uhs-sdr12;
|
||||
sd-uhs-sdr25;
|
||||
sd-uhs-sdr50;
|
||||
|
||||
@@ -393,8 +393,9 @@
|
||||
cap-mmc-highspeed;
|
||||
cap-sd-highspeed;
|
||||
disable-wp;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-names = "normal", "idle";
|
||||
pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>;
|
||||
pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>;
|
||||
vmmc-supply = <&vcc3v3_sd>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -263,8 +263,9 @@
|
||||
cap-mmc-highspeed;
|
||||
cap-sd-highspeed;
|
||||
disable-wp;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-names = "normal", "idle";
|
||||
pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>;
|
||||
pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>;
|
||||
vmmc-supply = <&vcc3v3_sd>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -263,8 +263,9 @@
|
||||
cap-mmc-highspeed;
|
||||
cap-sd-highspeed;
|
||||
disable-wp;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-names = "normal", "idle";
|
||||
pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>;
|
||||
pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>;
|
||||
vmmc-supply = <&vcc3v3_sd>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -1220,6 +1220,17 @@
|
||||
/* sdmmc0_pwr */
|
||||
<0 RK_PC0 1 &pcfg_pull_none>;
|
||||
};
|
||||
|
||||
/omit-if-no-ref/
|
||||
sdmmc0_idle_pins: sdmmc0-idle-pins {
|
||||
rockchip,pins =
|
||||
<1 RK_PB0 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<1 RK_PB1 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<1 RK_PA5 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<1 RK_PA6 RK_FUNC_GPIO &pcfg_pull_down>,
|
||||
<1 RK_PA7 RK_FUNC_GPIO &pcfg_pull_down>;
|
||||
};
|
||||
};
|
||||
spi0 {
|
||||
/omit-if-no-ref/
|
||||
|
||||
@@ -2371,8 +2371,9 @@
|
||||
clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
|
||||
fifo-depth = <0x100>;
|
||||
max-frequency = <200000000>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-names = "normal", "idle";
|
||||
pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_det &sdmmc0_bus4>;
|
||||
pinctrl-1 = <&sdmmc0_idle_pins &sdmmc0_det>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
||||
@@ -258,6 +258,10 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&dfi {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&display_subsystem {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -292,6 +292,10 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&dfi {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&display_subsystem {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -366,9 +366,20 @@
|
||||
|
||||
dmc: dmc {
|
||||
compatible = "rockchip,rk3528-dmc";
|
||||
interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "complete";
|
||||
devfreq-events = <&dfi>;
|
||||
clocks = <&scmi_clk SCMI_CLK_DDR>;
|
||||
clock-names = "dmc_clk";
|
||||
operating-points-v2 = <&dmc_opp_table>;
|
||||
upthreshold = <40>;
|
||||
downdifferential = <20>;
|
||||
system-status-level = <
|
||||
/* system status freq level */
|
||||
SYS_STATUS_NORMAL DMC_FREQ_LEVEL_HIGH
|
||||
>;
|
||||
auto-min-freq = <324000>;
|
||||
auto-freq-en = <0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@@ -1544,6 +1555,13 @@
|
||||
};
|
||||
};
|
||||
|
||||
dfi: dfi@ff930000 {
|
||||
reg = <0x0 0xff930000 0x0 0x400>;
|
||||
compatible = "rockchip,rk3528-dfi";
|
||||
rockchip,grf = <&grf>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
spi0: spi@ff9c0000 {
|
||||
compatible = "rockchip,rk3066-spi";
|
||||
reg = <0x0 0xff9c0000 0x0 0x1000>;
|
||||
|
||||
@@ -52,6 +52,10 @@
|
||||
#define RK3368_DFI_EN (0x30003 << 5)
|
||||
#define RK3368_DFI_DIS (0x30000 << 5)
|
||||
|
||||
#define RK3528_PMUGRF_OFFSET 0x70000
|
||||
#define RK3528_PMUGRF_OS_REG18 0x248
|
||||
#define RK3528_PMUGRF_OS_REG19 0x24c
|
||||
|
||||
#define MAX_DMC_NUM_CH 4
|
||||
#define READ_DRAMTYPE_INFO(n) (((n) >> 13) & 0x7)
|
||||
#define READ_CH_INFO(n) (((n) >> 28) & 0x3)
|
||||
@@ -722,6 +726,41 @@ static __maybe_unused __init int rk3328_dfi_init(struct platform_device *pdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __maybe_unused __init int rk3528_dfi_init(struct platform_device *pdev,
|
||||
struct rockchip_dfi *data,
|
||||
struct devfreq_event_desc *desc)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node, *node;
|
||||
struct resource *res;
|
||||
u32 val_18, val_19;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
data->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(data->regs))
|
||||
return PTR_ERR(data->regs);
|
||||
|
||||
node = of_parse_phandle(np, "rockchip,grf", 0);
|
||||
if (node) {
|
||||
data->regmap_grf = syscon_node_to_regmap(node);
|
||||
if (IS_ERR(data->regmap_grf))
|
||||
return PTR_ERR(data->regmap_grf);
|
||||
}
|
||||
|
||||
regmap_read(data->regmap_grf, RK3528_PMUGRF_OFFSET + RK3528_PMUGRF_OS_REG18, &val_18);
|
||||
regmap_read(data->regmap_grf, RK3528_PMUGRF_OFFSET + RK3528_PMUGRF_OS_REG19, &val_19);
|
||||
if (READ_SYSREG_VERSION(val_19) >= 0x3)
|
||||
data->dram_type = READ_DRAMTYPE_INFO_V3(val_18, val_19);
|
||||
else
|
||||
data->dram_type = READ_DRAMTYPE_INFO(val_18);
|
||||
data->count_rate = 2;
|
||||
data->ch_msk = 1;
|
||||
data->clk = NULL;
|
||||
|
||||
desc->ops = &rockchip_dfi_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id rockchip_dfi_id_match[] = {
|
||||
#ifdef CONFIG_CPU_PX30
|
||||
{ .compatible = "rockchip,px30-dfi", .data = px30_dfi_init },
|
||||
@@ -744,6 +783,9 @@ static const struct of_device_id rockchip_dfi_id_match[] = {
|
||||
#ifdef CONFIG_CPU_RK3399
|
||||
{ .compatible = "rockchip,rk3399-dfi", .data = rockchip_dfi_init },
|
||||
#endif
|
||||
#ifdef CONFIG_CPU_RK3528
|
||||
{ .compatible = "rockchip,rk3528-dfi", .data = rk3528_dfi_init },
|
||||
#endif
|
||||
#ifdef CONFIG_CPU_RK3562
|
||||
{ .compatible = "rockchip,rk3562-dfi", .data = px30_dfi_init },
|
||||
#endif
|
||||
|
||||
@@ -1771,6 +1771,79 @@ static __maybe_unused int rk3399_dmc_init(struct platform_device *pdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __maybe_unused int rk3528_dmc_init(struct platform_device *pdev,
|
||||
struct rockchip_dmcfreq *dmcfreq)
|
||||
{
|
||||
struct arm_smccc_res res;
|
||||
int ret;
|
||||
int complt_irq;
|
||||
u32 complt_hwirq;
|
||||
struct irq_data *complt_irq_data;
|
||||
|
||||
res = sip_smc_dram(0, 0, ROCKCHIP_SIP_CONFIG_DRAM_GET_VERSION);
|
||||
dev_notice(&pdev->dev, "current ATF version 0x%lx\n", res.a1);
|
||||
if (res.a0 || res.a1 < 0x100) {
|
||||
dev_err(&pdev->dev, "trusted firmware need update to V1.00 and above.\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* first 4KB is used for interface parameters
|
||||
* after 4KB is dts parameters
|
||||
* request share memory size 4KB * 2
|
||||
*/
|
||||
res = sip_smc_request_share_mem(2, SHARE_PAGE_TYPE_DDR);
|
||||
if (res.a0 != 0) {
|
||||
dev_err(&pdev->dev, "no ATF memory for init\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
ddr_psci_param = (struct share_params *)res.a1;
|
||||
/* Clear ddr_psci_param, size is 4KB * 2 */
|
||||
memset_io(ddr_psci_param, 0x0, 4096 * 2);
|
||||
|
||||
wait_ctrl.dcf_en = 0;
|
||||
|
||||
init_waitqueue_head(&wait_ctrl.wait_wq);
|
||||
wait_ctrl.wait_en = 1;
|
||||
wait_ctrl.wait_time_out_ms = 17 * 5;
|
||||
|
||||
complt_irq = platform_get_irq_byname(pdev, "complete");
|
||||
if (complt_irq < 0) {
|
||||
dev_err(&pdev->dev, "no IRQ for complt_irq: %d\n", complt_irq);
|
||||
return complt_irq;
|
||||
}
|
||||
wait_ctrl.complt_irq = complt_irq;
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, complt_irq, wait_dcf_complete_irq,
|
||||
0, dev_name(&pdev->dev), &wait_ctrl);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "cannot request complt_irq\n");
|
||||
return ret;
|
||||
}
|
||||
disable_irq(complt_irq);
|
||||
|
||||
complt_irq_data = irq_get_irq_data(complt_irq);
|
||||
complt_hwirq = irqd_to_hwirq(complt_irq_data);
|
||||
ddr_psci_param->complt_hwirq = complt_hwirq;
|
||||
|
||||
res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, ROCKCHIP_SIP_CONFIG_DRAM_INIT);
|
||||
if (res.a0) {
|
||||
dev_err(&pdev->dev, "rockchip_sip_config_dram_init error:%lx\n", res.a0);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = rockchip_get_freq_info(dmcfreq);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "cannot get frequency info\n");
|
||||
return ret;
|
||||
}
|
||||
dmcfreq->is_set_rate_direct = true;
|
||||
|
||||
dmcfreq->set_auto_self_refresh = rockchip_ddr_set_auto_self_refresh;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __maybe_unused int rk3568_dmc_init(struct platform_device *pdev,
|
||||
struct rockchip_dmcfreq *dmcfreq)
|
||||
{
|
||||
@@ -2039,7 +2112,7 @@ static const struct of_device_id rockchip_dmcfreq_of_match[] = {
|
||||
{ .compatible = "rockchip,rk3399-dmc", .data = rk3399_dmc_init },
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_CPU_RK3528)
|
||||
{ .compatible = "rockchip,rk3528-dmc", .data = NULL },
|
||||
{ .compatible = "rockchip,rk3528-dmc", .data = rk3528_dmc_init },
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_CPU_RK3562)
|
||||
{ .compatible = "rockchip,rk3562-dmc", .data = rk3568_dmc_init },
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -345,8 +345,35 @@ static const struct cif_output_fmt out_fmts[] = {
|
||||
.raw_bpp = 10,
|
||||
.csi_fmt_val = CSI_WRDDR_TYPE_RAW10,
|
||||
.fmt_type = CIF_FMT_TYPE_RAW,
|
||||
}, {
|
||||
.fourcc = V4L2_PIX_FMT_SRGGB16,
|
||||
.cplanes = 1,
|
||||
.mplanes = 1,
|
||||
.bpp = { 16 },
|
||||
.raw_bpp = 16,
|
||||
.fmt_type = CIF_FMT_TYPE_RAW,
|
||||
}, {
|
||||
.fourcc = V4L2_PIX_FMT_SGRBG16,
|
||||
.cplanes = 1,
|
||||
.mplanes = 1,
|
||||
.bpp = { 16 },
|
||||
.raw_bpp = 16,
|
||||
.fmt_type = CIF_FMT_TYPE_RAW,
|
||||
}, {
|
||||
.fourcc = V4L2_PIX_FMT_SGBRG16,
|
||||
.cplanes = 1,
|
||||
.mplanes = 1,
|
||||
.bpp = { 16 },
|
||||
.raw_bpp = 16,
|
||||
.fmt_type = CIF_FMT_TYPE_RAW,
|
||||
}, {
|
||||
.fourcc = V4L2_PIX_FMT_SBGGR16,
|
||||
.cplanes = 1,
|
||||
.mplanes = 1,
|
||||
.bpp = { 16 },
|
||||
.raw_bpp = 16,
|
||||
.fmt_type = CIF_FMT_TYPE_RAW,
|
||||
}
|
||||
|
||||
/* TODO: We can support NV12M/NV21M/NV16M/NV61M too */
|
||||
};
|
||||
|
||||
@@ -524,6 +551,136 @@ static const struct cif_input_fmt in_fmts[] = {
|
||||
}
|
||||
};
|
||||
|
||||
static int rkcif_output_fmt_check(struct rkcif_stream *stream,
|
||||
const struct cif_output_fmt *output_fmt)
|
||||
{
|
||||
const struct cif_input_fmt *input_fmt = stream->cif_fmt_in;
|
||||
struct csi_channel_info *channel = &stream->cifdev->channels[stream->id];
|
||||
int ret = -EINVAL;
|
||||
|
||||
switch (input_fmt->mbus_code) {
|
||||
case MEDIA_BUS_FMT_YUYV8_2X8:
|
||||
case MEDIA_BUS_FMT_YVYU8_2X8:
|
||||
case MEDIA_BUS_FMT_UYVY8_2X8:
|
||||
case MEDIA_BUS_FMT_VYUY8_2X8:
|
||||
if (output_fmt->fourcc == V4L2_PIX_FMT_NV16 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_NV61 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_NV12 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_NV21 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_YUYV ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_YVYU ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_UYVY ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_VYUY)
|
||||
ret = 0;
|
||||
break;
|
||||
case MEDIA_BUS_FMT_SBGGR8_1X8:
|
||||
case MEDIA_BUS_FMT_SGBRG8_1X8:
|
||||
case MEDIA_BUS_FMT_SGRBG8_1X8:
|
||||
case MEDIA_BUS_FMT_SRGGB8_1X8:
|
||||
case MEDIA_BUS_FMT_Y8_1X8:
|
||||
if (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB8 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGRBG8 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGBRG8 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SBGGR8 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_GREY)
|
||||
ret = 0;
|
||||
break;
|
||||
case MEDIA_BUS_FMT_SBGGR10_1X10:
|
||||
case MEDIA_BUS_FMT_SGBRG10_1X10:
|
||||
case MEDIA_BUS_FMT_SGRBG10_1X10:
|
||||
case MEDIA_BUS_FMT_SRGGB10_1X10:
|
||||
case MEDIA_BUS_FMT_Y10_1X10:
|
||||
if (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB10 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGRBG10 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGBRG10 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SBGGR10 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_Y10)
|
||||
ret = 0;
|
||||
break;
|
||||
case MEDIA_BUS_FMT_SBGGR12_1X12:
|
||||
case MEDIA_BUS_FMT_SGBRG12_1X12:
|
||||
case MEDIA_BUS_FMT_SGRBG12_1X12:
|
||||
case MEDIA_BUS_FMT_SRGGB12_1X12:
|
||||
case MEDIA_BUS_FMT_Y12_1X12:
|
||||
if (output_fmt->fourcc == V4L2_PIX_FMT_SRGGB12 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGRBG12 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGBRG12 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SBGGR12 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_Y12)
|
||||
ret = 0;
|
||||
break;
|
||||
case MEDIA_BUS_FMT_RGB888_1X24:
|
||||
case MEDIA_BUS_FMT_BGR888_1X24:
|
||||
if (output_fmt->fourcc == V4L2_PIX_FMT_RGB24 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_BGR24)
|
||||
ret = 0;
|
||||
break;
|
||||
case MEDIA_BUS_FMT_RGB565_1X16:
|
||||
if (output_fmt->fourcc == V4L2_PIX_FMT_RGB565)
|
||||
ret = 0;
|
||||
break;
|
||||
case MEDIA_BUS_FMT_EBD_1X8:
|
||||
if (output_fmt->fourcc == V4l2_PIX_FMT_EBD8 ||
|
||||
(channel->data_bit == 8 &&
|
||||
(output_fmt->fourcc == V4L2_PIX_FMT_SRGGB8 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGRBG8 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGBRG8 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SBGGR8)) ||
|
||||
(channel->data_bit == 10 &&
|
||||
(output_fmt->fourcc == V4L2_PIX_FMT_SRGGB10 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGRBG10 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGBRG10 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SBGGR10)) ||
|
||||
(channel->data_bit == 12 &&
|
||||
(output_fmt->fourcc == V4L2_PIX_FMT_SRGGB12 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGRBG12 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGBRG12 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SBGGR12)) ||
|
||||
(channel->data_bit == 16 &&
|
||||
(output_fmt->fourcc == V4L2_PIX_FMT_SRGGB16 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGRBG16 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGBRG16 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SBGGR16)))
|
||||
ret = 0;
|
||||
break;
|
||||
case MEDIA_BUS_FMT_SPD_2X8:
|
||||
if (output_fmt->fourcc == V4l2_PIX_FMT_SPD16 ||
|
||||
(channel->data_bit == 8 &&
|
||||
(output_fmt->fourcc == V4L2_PIX_FMT_SRGGB8 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGRBG8 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGBRG8 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SBGGR8)) ||
|
||||
(channel->data_bit == 10 &&
|
||||
(output_fmt->fourcc == V4L2_PIX_FMT_SRGGB10 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGRBG10 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGBRG10 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SBGGR10)) ||
|
||||
(channel->data_bit == 12 &&
|
||||
(output_fmt->fourcc == V4L2_PIX_FMT_SRGGB12 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGRBG12 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGBRG12 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SBGGR12)) ||
|
||||
(channel->data_bit == 16 &&
|
||||
(output_fmt->fourcc == V4L2_PIX_FMT_SRGGB16 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGRBG16 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SGBRG16 ||
|
||||
output_fmt->fourcc == V4L2_PIX_FMT_SBGGR16)))
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (ret)
|
||||
v4l2_err(&stream->cifdev->v4l2_dev,
|
||||
"input mbus_code 0x%x, can't transform to %c%c%c%c\n",
|
||||
input_fmt->mbus_code,
|
||||
output_fmt->fourcc & 0xff,
|
||||
(output_fmt->fourcc >> 8) & 0xff,
|
||||
(output_fmt->fourcc >> 16) & 0xff,
|
||||
(output_fmt->fourcc >> 24) & 0xff);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rkcif_stop_dma_capture(struct rkcif_stream *stream);
|
||||
|
||||
struct rkcif_rx_buffer *to_cif_rx_buf(struct rkisp_rx_buf *dbufs)
|
||||
@@ -5742,6 +5899,10 @@ int rkcif_set_fmt(struct rkcif_stream *stream,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = rkcif_output_fmt_check(stream, fmt);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->terminal_sensor.sd) {
|
||||
ret = v4l2_subdev_call(dev->terminal_sensor.sd,
|
||||
core, ioctl,
|
||||
@@ -6164,12 +6325,42 @@ static int rkcif_enum_fmt_vid_cap_mplane(struct file *file, void *priv,
|
||||
struct v4l2_fmtdesc *f)
|
||||
{
|
||||
const struct cif_output_fmt *fmt = NULL;
|
||||
struct rkcif_stream *stream = video_drvdata(file);
|
||||
struct rkcif_device *dev = stream->cifdev;
|
||||
const struct cif_input_fmt *cif_fmt_in = NULL;
|
||||
struct v4l2_rect input_rect;
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
int fource_idx = 0;
|
||||
|
||||
if (f->index >= ARRAY_SIZE(out_fmts))
|
||||
return -EINVAL;
|
||||
|
||||
fmt = &out_fmts[f->index];
|
||||
f->pixelformat = fmt->fourcc;
|
||||
if (dev->terminal_sensor.sd) {
|
||||
cif_fmt_in = get_input_fmt(dev->terminal_sensor.sd,
|
||||
&input_rect, stream->id,
|
||||
&dev->channels[stream->id]);
|
||||
stream->cif_fmt_in = cif_fmt_in;
|
||||
} else {
|
||||
v4l2_err(&stream->cifdev->v4l2_dev,
|
||||
"terminal subdev does not exist\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (f->index != 0)
|
||||
fource_idx = stream->new_fource_idx;
|
||||
|
||||
for (i = fource_idx; i < ARRAY_SIZE(out_fmts); i++) {
|
||||
fmt = &out_fmts[i];
|
||||
ret = rkcif_output_fmt_check(stream, fmt);
|
||||
if (!ret) {
|
||||
f->pixelformat = fmt->fourcc;
|
||||
stream->new_fource_idx = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == ARRAY_SIZE(out_fmts))
|
||||
return -EINVAL;
|
||||
|
||||
switch (f->pixelformat) {
|
||||
case V4l2_PIX_FMT_EBD8:
|
||||
@@ -6263,6 +6454,9 @@ static int rkcif_s_selection(struct file *file, void *fh,
|
||||
struct rkcif_device *dev = stream->cifdev;
|
||||
struct v4l2_subdev *sensor_sd;
|
||||
struct v4l2_subdev_selection sd_sel;
|
||||
const struct v4l2_rect *rect = &s->r;
|
||||
struct v4l2_rect sensor_crop;
|
||||
struct v4l2_rect *raw_rect = &dev->terminal_sensor.raw_rect;
|
||||
u16 pad = 0;
|
||||
int ret = 0;
|
||||
|
||||
@@ -6271,18 +6465,69 @@ static int rkcif_s_selection(struct file *file, void *fh,
|
||||
goto err;
|
||||
}
|
||||
|
||||
sensor_sd = get_remote_sensor(stream, &pad);
|
||||
if (s->target == V4L2_SEL_TGT_CROP_BOUNDS) {
|
||||
sensor_sd = get_remote_sensor(stream, &pad);
|
||||
|
||||
sd_sel.r = s->r;
|
||||
sd_sel.pad = pad;
|
||||
sd_sel.target = s->target;
|
||||
sd_sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
|
||||
sd_sel.r = s->r;
|
||||
sd_sel.pad = pad;
|
||||
sd_sel.target = s->target;
|
||||
sd_sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
|
||||
|
||||
ret = v4l2_subdev_call(sensor_sd, pad, set_selection, NULL, &sd_sel);
|
||||
if (!ret) {
|
||||
s->r = sd_sel.r;
|
||||
v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "%s: pad:%d, which:%d, target:%d\n",
|
||||
__func__, pad, sd_sel.which, sd_sel.target);
|
||||
ret = v4l2_subdev_call(sensor_sd, pad, set_selection, NULL, &sd_sel);
|
||||
if (!ret) {
|
||||
s->r = sd_sel.r;
|
||||
v4l2_dbg(1, rkcif_debug, &dev->v4l2_dev, "%s: pad:%d, which:%d, target:%d\n",
|
||||
__func__, pad, sd_sel.which, sd_sel.target);
|
||||
}
|
||||
} else if (s->target == V4L2_SEL_TGT_CROP) {
|
||||
ret = rkcif_sanity_check_fmt(stream, rect);
|
||||
if (ret) {
|
||||
v4l2_err(&dev->v4l2_dev, "set crop failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (stream->crop_mask & CROP_SRC_SENSOR) {
|
||||
sensor_crop = stream->crop[CROP_SRC_SENSOR];
|
||||
if (rect->left + rect->width > sensor_crop.width ||
|
||||
rect->top + rect->height > sensor_crop.height) {
|
||||
v4l2_err(&dev->v4l2_dev,
|
||||
"crop size is bigger than sensor input:left:%d, top:%d, width:%d, height:%d\n",
|
||||
sensor_crop.left, sensor_crop.top,
|
||||
sensor_crop.width, sensor_crop.height);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
if (rect->left + rect->width > raw_rect->width ||
|
||||
rect->top + rect->height > raw_rect->height) {
|
||||
v4l2_err(&dev->v4l2_dev,
|
||||
"crop size is bigger than sensor raw input:left:%d, top:%d, width:%d, height:%d\n",
|
||||
raw_rect->left, raw_rect->top,
|
||||
raw_rect->width, raw_rect->height);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
stream->crop[CROP_SRC_USR] = *rect;
|
||||
stream->crop_enable = true;
|
||||
stream->crop_mask |= CROP_SRC_USR_MASK;
|
||||
stream->crop[CROP_SRC_ACT] = stream->crop[CROP_SRC_USR];
|
||||
if (stream->crop_mask & CROP_SRC_SENSOR) {
|
||||
sensor_crop = stream->crop[CROP_SRC_SENSOR];
|
||||
stream->crop[CROP_SRC_ACT].left = sensor_crop.left + stream->crop[CROP_SRC_USR].left;
|
||||
stream->crop[CROP_SRC_ACT].top = sensor_crop.top + stream->crop[CROP_SRC_USR].top;
|
||||
}
|
||||
|
||||
if (stream->state == RKCIF_STATE_STREAMING) {
|
||||
stream->crop_dyn_en = true;
|
||||
|
||||
v4l2_info(&dev->v4l2_dev, "enable dynamic crop, S_SELECTION(%ux%u@%u:%u) target: %d\n",
|
||||
rect->width, rect->height, rect->left, rect->top, s->target);
|
||||
} else {
|
||||
v4l2_info(&dev->v4l2_dev, "static crop, S_SELECTION(%ux%u@%u:%u) target: %d\n",
|
||||
rect->width, rect->height, rect->left, rect->top, s->target);
|
||||
}
|
||||
} else {
|
||||
goto err;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -535,6 +535,7 @@ struct rkcif_stream {
|
||||
struct list_head vb_done_list;
|
||||
int last_rx_buf_idx;
|
||||
int last_frame_idx;
|
||||
int new_fource_idx;
|
||||
bool stopping;
|
||||
bool crop_enable;
|
||||
bool crop_dyn_en;
|
||||
|
||||
@@ -1201,6 +1201,15 @@ static void fiq_tty_close(struct tty_struct *tty, struct file *filp)
|
||||
tty_port_close(tty->port, tty, filp);
|
||||
}
|
||||
|
||||
void fiq_tty_wake_up(struct platform_device *pdev)
|
||||
{
|
||||
struct fiq_debugger_state *state = platform_get_drvdata(pdev);
|
||||
|
||||
if (tty_port_initialized(&state->tty_port))
|
||||
tty_port_tty_wakeup(&state->tty_port);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fiq_tty_wake_up);
|
||||
|
||||
static int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
||||
{
|
||||
int i;
|
||||
@@ -1211,6 +1220,11 @@ static int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int c
|
||||
if (!state->console_enable)
|
||||
return count;
|
||||
|
||||
#ifdef CONFIG_RK_CONSOLE_THREAD
|
||||
if (state->pdata->tty_write)
|
||||
return state->pdata->tty_write(state->pdev, buf, count);
|
||||
#endif
|
||||
|
||||
fiq_debugger_uart_enable(state);
|
||||
#ifndef CONFIG_RK_CONSOLE_THREAD
|
||||
spin_lock_irq(&state->console_lock);
|
||||
@@ -1227,7 +1241,15 @@ static int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int c
|
||||
|
||||
static unsigned int fiq_tty_write_room(struct tty_struct *tty)
|
||||
{
|
||||
return 16;
|
||||
#ifdef CONFIG_RK_CONSOLE_THREAD
|
||||
int line = tty->index;
|
||||
struct fiq_debugger_state **states = tty->driver->driver_state;
|
||||
struct fiq_debugger_state *state = states[line];
|
||||
|
||||
if (state->pdata->write_room)
|
||||
return state->pdata->write_room(state->pdev);
|
||||
#endif
|
||||
return 2048;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
|
||||
@@ -63,6 +63,8 @@ struct fiq_debugger_pdata {
|
||||
#ifdef CONFIG_RK_CONSOLE_THREAD
|
||||
void (*console_write)(struct platform_device *pdev, const char *s,
|
||||
unsigned int count);
|
||||
int (*tty_write)(struct platform_device *pdev, const char *s, int count);
|
||||
int (*write_room)(struct platform_device *pdev);
|
||||
#endif
|
||||
#ifdef CONFIG_FIQ_DEBUGGER_TRUST_ZONE
|
||||
void (*switch_cpu)(struct platform_device *pdev, u32 cpu);
|
||||
@@ -75,4 +77,5 @@ void gic_set_irq_secure(struct irq_data *d);
|
||||
void gic_set_irq_priority(struct irq_data *d, u8 pri);
|
||||
#endif
|
||||
|
||||
void fiq_tty_wake_up(struct platform_device *pdev);
|
||||
#endif
|
||||
|
||||
@@ -229,23 +229,32 @@ static void debug_flush(struct platform_device *pdev)
|
||||
|
||||
#ifdef CONFIG_RK_CONSOLE_THREAD
|
||||
#define FIFO_SIZE SZ_64K
|
||||
#define LINE_MAX 1024
|
||||
#define TTY_FIFO_SIZE SZ_64K
|
||||
static DEFINE_KFIFO(fifo, unsigned char, FIFO_SIZE);
|
||||
static char console_buf[LINE_MAX]; /* avoid FRAME WARN */
|
||||
static DEFINE_KFIFO(tty_fifo, unsigned char, TTY_FIFO_SIZE);
|
||||
static bool console_thread_stop; /* write on console_write */
|
||||
static bool console_thread_running; /* write on console_thread */
|
||||
static unsigned int console_dropped_messages;
|
||||
|
||||
static int write_room(struct platform_device *pdev)
|
||||
{
|
||||
return (TTY_FIFO_SIZE - kfifo_len(&tty_fifo));
|
||||
}
|
||||
|
||||
static void console_putc(struct platform_device *pdev, unsigned int c)
|
||||
{
|
||||
struct rk_fiq_debugger *t;
|
||||
unsigned int count = 500;
|
||||
unsigned int count = 2; /* loop 2 times is enough */
|
||||
unsigned long us = 400; /* the time to send 60 byte for baudrate 1500000 */
|
||||
|
||||
t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
|
||||
|
||||
if (t->baudrate == 115200)
|
||||
us = 5160; /* the time to send 60 byte for baudrate 115200 */
|
||||
|
||||
while (!(rk_fiq_read(t, UART_USR) & UART_USR_TX_FIFO_NOT_FULL) &&
|
||||
count--)
|
||||
usleep_range(200, 210);
|
||||
usleep_range(us, us + us / 20);
|
||||
|
||||
rk_fiq_write(t, c, UART_TX);
|
||||
}
|
||||
@@ -253,12 +262,16 @@ static void console_putc(struct platform_device *pdev, unsigned int c)
|
||||
static void console_flush(struct platform_device *pdev)
|
||||
{
|
||||
struct rk_fiq_debugger *t;
|
||||
unsigned int count = 500;
|
||||
unsigned int count = 2; /* loop 2 times is enough */
|
||||
unsigned long us = 428; /* the time to send 64 byte for baudrate 1500000 */
|
||||
|
||||
t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
|
||||
|
||||
if (t->baudrate == 115200)
|
||||
us = 5500; /* the time to send 64 byte for baudrate 115200 */
|
||||
|
||||
while (!(rk_fiq_read_lsr(t) & UART_LSR_TEMT) && count--)
|
||||
usleep_range(200, 210);
|
||||
usleep_range(us, us + us / 20);
|
||||
}
|
||||
|
||||
static void console_put(struct platform_device *pdev,
|
||||
@@ -281,17 +294,47 @@ static void debug_put(struct platform_device *pdev,
|
||||
}
|
||||
}
|
||||
|
||||
static void wake_up_console_thread(struct task_struct *console_task)
|
||||
{
|
||||
/*
|
||||
* Avoid dead lock on console_task->pi_lock and console_lock
|
||||
* when call printk() in try_to_wake_up().
|
||||
*
|
||||
* cpu0 hold console_lock, then try lock pi_lock fail:
|
||||
* printk()->vprintk_emit()->console_unlock()->try_to_wake_up()
|
||||
* ->lock(pi_lock)->deadlock
|
||||
*
|
||||
* cpu1 hold pi_lock, then try lock console_lock fail:
|
||||
* console_thread()->console_put()->usleep_range()->run_hrtimer()
|
||||
* ->hrtimer_wakeup()->try_to_wake_up()[hold_pi_lock]->printk()
|
||||
* ->vprintk_emit()->console_trylock_spining()->cpu_relax()->deadlock
|
||||
*
|
||||
* if cpu0 does not hold console_lock, cpu1 also deadlock on pi_lock:
|
||||
* ...->hrtimer_wakeup()->try_to_wake_up()[hold_pi_lock]->printk()
|
||||
* ->vprintk_emit()->console_unlock()->try_to_wake_up()
|
||||
* ->lock(pi_lock)->deadlock
|
||||
*
|
||||
* so when console_task is running on usleep_range(), printk()
|
||||
* should not wakeup console_task to avoid lock(pi_lock) again,
|
||||
* as run_hrtimer() will wakeup console_task later.
|
||||
* console_thread_running==false guarantee that console_task
|
||||
* is not running on usleep_range().
|
||||
*/
|
||||
if (!READ_ONCE(console_thread_running))
|
||||
wake_up_process(console_task);
|
||||
}
|
||||
|
||||
static int console_thread(void *data)
|
||||
{
|
||||
struct platform_device *pdev = data;
|
||||
char *buf = console_buf;
|
||||
unsigned int len;
|
||||
char buf[64], c = 0;
|
||||
unsigned int len = 0, len_tty = 0;
|
||||
|
||||
while (1) {
|
||||
unsigned int dropped;
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (kfifo_is_empty(&fifo)) {
|
||||
if (kfifo_is_empty(&fifo) && kfifo_is_empty(&tty_fifo)) {
|
||||
smp_store_mb(console_thread_running, false);
|
||||
schedule();
|
||||
smp_store_mb(console_thread_running, true);
|
||||
@@ -299,18 +342,31 @@ static int console_thread(void *data)
|
||||
if (kthread_should_stop())
|
||||
break;
|
||||
set_current_state(TASK_RUNNING);
|
||||
while (!console_thread_stop) {
|
||||
len = kfifo_out(&fifo, buf, LINE_MAX);
|
||||
if (!len)
|
||||
break;
|
||||
console_put(pdev, buf, len);
|
||||
|
||||
while (!console_thread_stop && (!kfifo_is_empty(&fifo) || !kfifo_is_empty(&tty_fifo))) {
|
||||
while (kfifo_get(&fifo, &c)) {
|
||||
console_put(pdev, &c, 1);
|
||||
if (c == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
while (kfifo_get(&tty_fifo, &c)) {
|
||||
console_putc(pdev, c);
|
||||
len_tty++;
|
||||
if (c == '\n')
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (len_tty > 0)
|
||||
fiq_tty_wake_up(pdev);
|
||||
len_tty = 0;
|
||||
|
||||
dropped = console_dropped_messages;
|
||||
if (dropped && !console_thread_stop) {
|
||||
console_dropped_messages = 0;
|
||||
smp_wmb();
|
||||
len = snprintf(buf, LINE_MAX,
|
||||
"** %u console messages dropped **\n",
|
||||
len = sprintf(buf, "** %u console messages dropped **\n",
|
||||
dropped);
|
||||
console_put(pdev, buf, len);
|
||||
}
|
||||
@@ -346,43 +402,35 @@ static void console_write(struct platform_device *pdev, const char *s, unsigned
|
||||
} else if (count) {
|
||||
unsigned int ret = 0;
|
||||
|
||||
if (kfifo_len(&fifo) + count < FIFO_SIZE)
|
||||
if (kfifo_len(&fifo) + count <= FIFO_SIZE)
|
||||
ret = kfifo_in(&fifo, s, count);
|
||||
if (!ret) {
|
||||
console_dropped_messages++;
|
||||
smp_wmb();
|
||||
} else {
|
||||
/*
|
||||
* Avoid dead lock on console_task->pi_lock and console_lock
|
||||
* when call printk() in try_to_wake_up().
|
||||
*
|
||||
* cpu0 hold console_lock, then try lock pi_lock fail:
|
||||
* printk()->vprintk_emit()->console_unlock()->try_to_wake_up()
|
||||
* ->lock(pi_lock)->deadlock
|
||||
*
|
||||
* cpu1 hold pi_lock, then try lock console_lock fail:
|
||||
* console_thread()->console_put()->usleep_range()->run_hrtimer()
|
||||
* ->hrtimer_wakeup()->try_to_wake_up()[hold_pi_lock]->printk()
|
||||
* ->vprintk_emit()->console_trylock_spining()->cpu_relax()->deadlock
|
||||
*
|
||||
* if cpu0 does not hold console_lock, cpu1 also deadlock on pi_lock:
|
||||
* ...->hrtimer_wakeup()->try_to_wake_up()[hold_pi_lock]->printk()
|
||||
* ->vprintk_emit()->console_unlock()->try_to_wake_up()
|
||||
* ->lock(pi_lock)->deadlock
|
||||
*
|
||||
* so when console_task is running on usleep_range(), printk()
|
||||
* should not wakeup console_task to avoid lock(pi_lock) again,
|
||||
* as run_hrtimer() will wakeup console_task later.
|
||||
* console_thread_running==false guarantee that console_task
|
||||
* is not running on usleep_range().
|
||||
*/
|
||||
if (!READ_ONCE(console_thread_running))
|
||||
wake_up_process(t->console_task);
|
||||
wake_up_console_thread(t->console_task);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int tty_write(struct platform_device *pdev, const char *s, int count)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
struct rk_fiq_debugger *t;
|
||||
|
||||
t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
|
||||
|
||||
if (count > 0) {
|
||||
if (kfifo_len(&tty_fifo) + count <= TTY_FIFO_SIZE)
|
||||
ret = kfifo_in(&tty_fifo, s, count);
|
||||
|
||||
if (ret <= 0)
|
||||
return 0;
|
||||
wake_up_console_thread(t->console_task);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void fiq_enable(struct platform_device *pdev, unsigned int irq, bool on)
|
||||
{
|
||||
@@ -889,8 +937,11 @@ static void rk_serial_debug_init(void __iomem *base, phys_addr_t phy_base,
|
||||
|
||||
#ifdef CONFIG_RK_CONSOLE_THREAD
|
||||
t->console_task = kthread_run(console_thread, pdev, "kconsole");
|
||||
if (!IS_ERR(t->console_task))
|
||||
if (!IS_ERR(t->console_task)) {
|
||||
t->pdata.console_write = console_write;
|
||||
t->pdata.tty_write = tty_write;
|
||||
t->pdata.write_room = write_room;
|
||||
}
|
||||
#endif
|
||||
|
||||
pdev->name = "fiq_debugger";
|
||||
|
||||
Reference in New Issue
Block a user