Merge branch 'rcar-3.5.1/dts-rcar-gen3.rc2' into v4.9/rcar-3.5.2.pt3
* rcar-3.5.1/dts-rcar-gen3.rc2: (80 commits)
arm64: dts: r8a7795-salvator-xs: Add Media Clock Recovery Handler device node
arm64: dts: r8a7795-salvator-xs: Add ADSP support
arm64: dts: r8a7795-salvator-xs: Add VSPM I/F driver support
arm64: dts: r8a7795-salvator-xs: Add MMNGRBUF driver support
arm64: dts: r8a7795-salvator-xs: Add MMNGR driver support
arm64: dts: r8a7795-salvator-xs: Add cpu-supply property in a57_0 node
arm64: dts: r8a7795-salvator-xs: Add regulator for DVFS
arm64: dts: r8a7795-salvator-xs: Add I2C for DVFS device support
arm64: dts: r8a7795-salvator-xs: Enable EXTALR clock
arm64: dts: r8a7795-salvator-xs: Add RCLK watchdog timer support
arm64: dts: r8a7795-salvator-xs: Add SATA device support
arm64: dts: r8a7795-salvator-xs: Add PCIe device support
arm64: dts: r8a7795-salvator-xs: Enable HS400 for SDHI2
arm64: dts: r8a7795-salvator-xs: Enable HS200 for SDHI2
arm64: dts: r8a7795-salvator-xs: Add SDHI2 device support as MMC interface
arm64: dts: r8a7795-salvator-xs: Enable UHS-I SDR-104 for SDHI0 and SDHI3
arm64: dts: r8a7795-salvator-xs: Enable UHS for SDHI0 and SDHI3
arm64: dts: r8a7795-salvator-xs: Add SDHI0 and SDHI3 device supports
arm64: dts: r8a7795-salvator-xs: Add sound MIX support
arm64: dts: r8a7795-salvator-xs: Add sound CTU support
arm64: dts: r8a7795-salvator-xs: Add AUDIO-CLKOUTn synchronous with L/R clock
arm64: dts: r8a7795-salvator-xs: Add ak4613 In/Out pin as single-end
arm64: dts: r8a7795-salvator-xs: Add CS2000 as AUDIO_CLK_B
arm64: dts: r8a7795-salvator-xs: Add Sound DVC support
arm64: dts: r8a7795-salvator-xs: Add Sound SRC support
arm64: dts: r8a7795-salvator-xs: Add Sound SSI support
arm64: dts: r8a7795-salvator-xs: Add ADV7482 video decoder devices support
arm64: dts: r8a7795-salvator-xs: Add CSI2 device support
arm64: dts: r8a7795-salvator-xs: Add VIN device support
arm64: dts: r8a7795-salvator-xs: Add PWM device support
...
diff --git a/Documentation/devicetree/bindings/cpufreq/avs/rcar-avs.txt b/Documentation/devicetree/bindings/cpufreq/avs/rcar-avs.txt
new file mode 100644
index 0000000..1fd80e7
--- /dev/null
+++ b/Documentation/devicetree/bindings/cpufreq/avs/rcar-avs.txt
@@ -0,0 +1,26 @@
+R-Car AVS driver
+
+It is a simple driver that checks AVS (Adaptive Voltage Scaling) value of
+chip. It helps to cpufreq select the best opp table (appropriate table with
+avs value) to apply for the chip at runtime.
+
+Required properties:
+ - reg: address and offset for registers of AVS.
+
+Optional properties:
+ - None
+
+Examples:
+ - Below is device tree definition for R-Car H3 and M3:
+
+ For H3:
+ avs_sensor: avs {
+ compatible = "renesas,r8a7795-avs", "renesas,rcar-gen3-avs";
+ reg = <0 0xe60a013c 0 0x04>;
+ };
+
+ For M3:
+ avs_sensor: avs {
+ compatible = "renesas,r8a7796-avs", "renesas,rcar-gen3-avs";
+ reg = <0 0xe60a013c 0 0x04>;
+ };
diff --git a/drivers/clk/clk-cs2000-cp.c b/drivers/clk/clk-cs2000-cp.c
index 0a04b05..3fca052 100644
--- a/drivers/clk/clk-cs2000-cp.c
+++ b/drivers/clk/clk-cs2000-cp.c
@@ -59,6 +59,10 @@
struct i2c_client *client;
struct clk *clk_in;
struct clk *ref_clk;
+
+ /* suspend/resume */
+ unsigned long saved_rate;
+ unsigned long saved_parent_rate;
};
static const struct of_device_id cs2000_of_match[] = {
@@ -286,6 +290,9 @@
if (ret < 0)
return ret;
+ priv->saved_rate = rate;
+ priv->saved_parent_rate = parent_rate;
+
return 0;
}
@@ -489,42 +496,24 @@
return ret;
}
-#ifdef CONFIG_PM_SLEEP
-static int cs2000_suspend(struct device *dev)
-{
- /* Empty function for now */
- return 0;
-}
-
static int cs2000_resume(struct device *dev)
{
struct cs2000_priv *priv = dev_get_drvdata(dev);
- int rate;
- int ret;
+ int ch = 0; /* it uses ch0 only at this point */
- /* Setting is referred from cs2000_clk_register */
- rate = clk_get_rate(priv->ref_clk);
- ret = __cs2000_set_rate(priv, 0, rate, rate);
-
- if (ret < 0)
- return ret;
-
- return 0;
+ return __cs2000_set_rate(priv, ch,
+ priv->saved_rate,
+ priv->saved_parent_rate);
}
static const struct dev_pm_ops cs2000_pm_ops = {
- .suspend = cs2000_suspend,
- .resume_early = cs2000_resume,
+ .resume_early = cs2000_resume,
};
-#define DEV_PM_OPS (&cs2000_pm_ops)
-#else
-#define DEV_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
static struct i2c_driver cs2000_driver = {
.driver = {
.name = "cs2000-cp",
- .pm = DEV_PM_OPS,
+ .pm = &cs2000_pm_ops,
.of_match_table = cs2000_of_match,
},
.probe = cs2000_probe,
diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c
index 41a1a79..e0a7233 100644
--- a/drivers/clk/renesas/r8a7795-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c
@@ -1,6 +1,7 @@
/*
* r8a7795 Clock Pulse Generator / Module Standby and Software Reset
*
+ * Copyright (C) 2017 Renesas Electronics Corp.
* Copyright (C) 2015 Glider bvba
*
* Based on clk-rcar-gen3.c
@@ -136,7 +137,6 @@
DEF_MOD("msiof2", 209, R8A7795_CLK_MSO),
DEF_MOD("msiof1", 210, R8A7795_CLK_MSO),
DEF_MOD("msiof0", 211, R8A7795_CLK_MSO),
- DEF_MOD("mfis", 213, R8A7795_CLK_S3D2),
DEF_MOD("sys-dmac2", 217, R8A7795_CLK_S0D3),
DEF_MOD("sys-dmac1", 218, R8A7795_CLK_S0D3),
DEF_MOD("sys-dmac0", 219, R8A7795_CLK_S0D3),
@@ -242,6 +242,7 @@
DEF_MOD("can-if0", 916, R8A7795_CLK_S3D4),
DEF_MOD("i2c6", 918, R8A7795_CLK_S3D2),
DEF_MOD("i2c5", 919, R8A7795_CLK_S3D2),
+ DEF_MOD("adg", 922, R8A7795_CLK_S0D1),
DEF_MOD("i2c-dvfs", 926, R8A7795_CLK_CP),
DEF_MOD("i2c4", 927, R8A7795_CLK_S3D2),
DEF_MOD("i2c3", 928, R8A7795_CLK_S3D2),
diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c
index 8c96083..0fbb024 100644
--- a/drivers/clk/renesas/r8a7796-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c
@@ -1,6 +1,7 @@
/*
* r8a7796 Clock Pulse Generator / Module Standby and Software Reset
*
+ * Copyright (C) 2017 Renesas Electronics Corp.
* Copyright (C) 2016 Glider bvba
*
* Based on r8a7795-cpg-mssr.c
@@ -132,7 +133,6 @@
DEF_MOD("msiof2", 209, R8A7796_CLK_MSO),
DEF_MOD("msiof1", 210, R8A7796_CLK_MSO),
DEF_MOD("msiof0", 211, R8A7796_CLK_MSO),
- DEF_MOD("mfis", 213, R8A7796_CLK_S0D6),
DEF_MOD("sys-dmac2", 217, R8A7796_CLK_S0D3),
DEF_MOD("sys-dmac1", 218, R8A7796_CLK_S0D3),
DEF_MOD("sys-dmac0", 219, R8A7796_CLK_S0D3),
@@ -216,6 +216,7 @@
DEF_MOD("can-if0", 916, R8A7796_CLK_S3D4),
DEF_MOD("i2c6", 918, R8A7796_CLK_S0D6),
DEF_MOD("i2c5", 919, R8A7796_CLK_S0D6),
+ DEF_MOD("adg", 922, R8A7796_CLK_S0D1),
DEF_MOD("i2c-dvfs", 926, R8A7796_CLK_CP),
DEF_MOD("i2c4", 927, R8A7796_CLK_S0D6),
DEF_MOD("i2c3", 928, R8A7796_CLK_S0D6),
diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c
index 31246ab..f49046e 100644
--- a/drivers/clk/renesas/rcar-gen3-cpg.c
+++ b/drivers/clk/renesas/rcar-gen3-cpg.c
@@ -1,6 +1,7 @@
/*
* R-Car Gen3 Clock Pulse Generator
*
+ * Copyright (C) 2017 Renesas Electronics Corp.
* Copyright (C) 2015-2016 Glider bvba
*
* Based on clk-rcar-gen3.c
@@ -494,12 +495,12 @@
* sd_srcfc sd_fc div
* stp_hck stp_ck (div) (div) = sd_srcfc x sd_fc
*-------------------------------------------------------------------
- * 0 0 1 (2) 0 (2) 4 : SDR104 / HS400 / HS200
+ * 0 0 1 (2) 0 (-) 2 : HS400
+ * 0 0 0 (1) 1 (4) 4 : SDR104 / HS200
* 0 0 1 (2) 1 (4) 8 : SDR50
* 1 0 2 (4) 1 (4) 16 : HS / SDR25
* 1 0 3 (8) 1 (4) 32 : NS / SDR12
* 0 0 0 (1) 0 (2) 2 : (no case)
- * 0 0 0 (1) 1 (4) 4 : (no case)
* 1 0 2 (4) 0 (2) 8 : (no case)
* 1 0 3 (8) 0 (2) 16 : (no case)
* 1 0 4 (16) 0 (2) 32 : (no case)
@@ -507,12 +508,12 @@
*/
static const struct sd_div_table cpg_sd_div_table[] = {
/* CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) */
- CPG_SD_DIV_TABLE_DATA(0, 0, 1, 0, 4),
+ CPG_SD_DIV_TABLE_DATA(0, 0, 1, 0, 2),
+ CPG_SD_DIV_TABLE_DATA(0, 0, 0, 1, 4),
CPG_SD_DIV_TABLE_DATA(0, 0, 1, 1, 8),
CPG_SD_DIV_TABLE_DATA(1, 0, 2, 1, 16),
CPG_SD_DIV_TABLE_DATA(1, 0, 3, 1, 32),
CPG_SD_DIV_TABLE_DATA(0, 0, 0, 0, 2),
- CPG_SD_DIV_TABLE_DATA(0, 0, 0, 1, 4),
CPG_SD_DIV_TABLE_DATA(1, 0, 2, 0, 8),
CPG_SD_DIV_TABLE_DATA(1, 0, 3, 0, 16),
CPG_SD_DIV_TABLE_DATA(1, 0, 4, 0, 32),
diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c
index 1c0609d..494e4e8 100644
--- a/drivers/clk/renesas/renesas-cpg-mssr.c
+++ b/drivers/clk/renesas/renesas-cpg-mssr.c
@@ -462,8 +462,6 @@
switch (clkspec->args[0]) {
case CPG_CORE:
- if (!pd->num_core_pm_clks)
- return true;
for (i = 0; i < pd->num_core_pm_clks; i++)
if (clkspec->args[1] == pd->core_pm_clks[i])
return true;
@@ -485,7 +483,6 @@
struct clk *clk;
int i = 0;
int error;
- bool had_clk = false;
if (!pd) {
dev_dbg(dev, "CPG/MSSR clock domain not yet available\n");
@@ -494,40 +491,40 @@
while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i,
&clkspec)) {
- i++;
- if (!cpg_mssr_is_pm_clk(&clkspec, pd))
- continue;
+ if (cpg_mssr_is_pm_clk(&clkspec, pd))
+ goto found;
- if (!had_clk) {
- error = pm_clk_create(dev);
- if (error) {
- dev_err(dev, "pm_clk_create failed %d\n",
- error);
- return error;
- }
- had_clk = true;
- }
-
- clk = of_clk_get_from_provider(&clkspec);
of_node_put(clkspec.np);
-
- if (IS_ERR(clk))
- goto fail_destroy;
-
- error = pm_clk_add_clk(dev, clk);
- if (error) {
- dev_err(dev, "pm_clk_add_clk %pC failed %d\n",
- clk, error);
- goto fail_put;
- }
+ i++;
}
return 0;
-fail_put:
- clk_put(clk);
+found:
+ clk = of_clk_get_from_provider(&clkspec);
+ of_node_put(clkspec.np);
+
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ error = pm_clk_create(dev);
+ if (error) {
+ dev_err(dev, "pm_clk_create failed %d\n", error);
+ goto fail_put;
+ }
+
+ error = pm_clk_add_clk(dev, clk);
+ if (error) {
+ dev_err(dev, "pm_clk_add_clk %pC failed %d\n", clk, error);
+ goto fail_destroy;
+ }
+
+ return 0;
+
fail_destroy:
pm_clk_destroy(dev);
+fail_put:
+ clk_put(clk);
return error;
}
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
index e9d79d7..f0849cc 100644
--- a/drivers/dma/sh/rcar-dmac.c
+++ b/drivers/dma/sh/rcar-dmac.c
@@ -1647,6 +1647,13 @@
spin_lock(&dmac->channels[i].lock);
pm_runtime_get_sync(dev);
+
+ if (rcar_dmac_chan_is_busy(&dmac->channels[i])) {
+ pm_runtime_put(dev);
+ spin_unlock(&dmac->channels[i].lock);
+ return -EBUSY;
+ }
+
rcar_dmac_chan_halt(&dmac->channels[i]);
pm_runtime_put(dev);
spin_unlock(&dmac->channels[i].lock);
diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c
index 52bc399..c574d15 100644
--- a/drivers/dma/sh/usb-dmac.c
+++ b/drivers/dma/sh/usb-dmac.c
@@ -1,7 +1,7 @@
/*
* Renesas USB DMA Controller Driver
*
- * Copyright (C) 2015 Renesas Electronics Corporation
+ * Copyright (C) 2015-2017 Renesas Electronics Corporation
*
* based on rcar-dmac.c
* Copyright (C) 2014 Renesas Electronics Inc.
@@ -117,7 +117,7 @@
#define USB_DMASWR 0x0008
#define USB_DMASWR_SWR (1 << 0)
#define USB_DMAOR 0x0060
-#define USB_DMAOR_AE (1 << 2)
+#define USB_DMAOR_AE (1 << 1)
#define USB_DMAOR_DME (1 << 0)
#define USB_DMASAR 0x0000
@@ -685,6 +685,10 @@
for (i = 0; i < dmac->n_channels; ++i) {
if (!dmac->channels[i].iomem)
break;
+
+ if (usb_dmac_chan_is_busy(&dmac->channels[i]))
+ return -EBUSY;
+
usb_dmac_chan_halt(&dmac->channels[i]);
}
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 2b776ec..19a8c58 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -1,7 +1,7 @@
/*
* DesignWare High-Definition Multimedia Interface (HDMI) driver
*
- * Copyright (C) 2015 Renesas Electronics Corporation
+ * Copyright (C) 2015-2017 Renesas Electronics Corporation
* Copyright (C) 2013-2015 Mentor Graphics Inc.
* Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
* Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
@@ -878,7 +878,12 @@
static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
unsigned char addr)
{
- hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
+ if (hdmi->dev_type == RCAR_HDMI)
+ hdmi_writeb(hdmi, HDMI_IH_I2CMPHY_STAT0_I2CMPHYDONE |
+ HDMI_IH_I2CMPHY_STAT0_I2CMPHYERROR,
+ HDMI_IH_I2CMPHY_STAT0);
+ else
+ hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
hdmi_writeb(hdmi, (unsigned char)(data >> 8),
HDMI_PHY_I2CM_DATAO_1_ADDR);
@@ -1051,15 +1056,14 @@
hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
- hdmi_phy_i2c_write(hdmi, phy_config->term,
- 0x19); /* TXTERM */
- hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr,
- 0x09); /* CKSYMTXCTRL */
- hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr,
- 0x0e); /* VLEVCTRL */
/* REMOVE CLK TERM */
hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
}
+
+ hdmi_phy_i2c_write(hdmi, phy_config->term, 0x19); /* TXTERM */
+ hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr, 0x09); /* CKSYMTXCTRL */
+ hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr, 0x0e); /* VLEVCTRL */
+
dw_hdmi_phy_enable_powerdown(hdmi, false);
/* toggle TMDS enable */
@@ -1384,7 +1388,13 @@
u8 val;
/* TMDS software reset */
- hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
+ if (hdmi->dev_type == RCAR_HDMI)
+ hdmi_writeb(hdmi, (HDMI_MC_SWRSTZ_TMDSSWRST_MASK &
+ (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ),
+ HDMI_MC_SWRSTZ);
+ else
+ hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ,
+ HDMI_MC_SWRSTZ);
val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
if (hdmi->dev_type == IMX6DL_HDMI) {
@@ -1503,6 +1513,52 @@
return 0;
}
+static void initialize_hdmi_rcar_ih_mutes(struct dw_hdmi *hdmi)
+{
+ u8 ih_mute;
+ /*
+ * Boot up defaults are:
+ * HDMI_IH_MUTE = 0x03 (disabled)
+ * HDMI_IH_MUTE_* = 0x00 (enabled)
+ *
+ * Disable top level interrupt bits in HDMI block
+ */
+ ih_mute = hdmi_readb(hdmi, HDMI_IH_MUTE) |
+ HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
+ HDMI_IH_MUTE_MUTE_ALL_INTERRUPT;
+
+ hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
+
+ /* by default mask all interrupts */
+ hdmi_writeb(hdmi, 0xff, HDMI_VP_MASK);
+ hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK0);
+ hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK1);
+ hdmi_writeb(hdmi, 0x03, HDMI_FC_MASK2);
+ hdmi_writeb(hdmi, 0xf3, HDMI_PHY_MASK0);
+ hdmi_writeb(hdmi, 0x0c, HDMI_PHY_I2CM_INT_ADDR);
+ hdmi_writeb(hdmi, 0xcc, HDMI_PHY_I2CM_CTLINT_ADDR);
+ hdmi_writeb(hdmi, 0x0c, HDMI_AUD_INT);
+ hdmi_writeb(hdmi, 0xff, HDMI_A_APIINTMSK);
+ hdmi_writeb(hdmi, 0x7f, HDMI_CEC_MASK);
+ hdmi_writeb(hdmi, 0x44, HDMI_I2CM_INT);
+ hdmi_writeb(hdmi, 0x44, HDMI_I2CM_CTLINT);
+
+ /* Disable interrupts in the IH_MUTE_* registers */
+ hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT0);
+ hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT1);
+ hdmi_writeb(hdmi, 0x03, HDMI_IH_MUTE_FC_STAT2);
+ hdmi_writeb(hdmi, 0x1f, HDMI_IH_MUTE_AS_STAT0);
+ hdmi_writeb(hdmi, 0x3f, HDMI_IH_MUTE_PHY_STAT0);
+ hdmi_writeb(hdmi, 0x0f, HDMI_IH_MUTE_I2CM_STAT0);
+ hdmi_writeb(hdmi, 0x7f, HDMI_IH_MUTE_CEC_STAT0);
+ hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_VP_STAT0);
+ hdmi_writeb(hdmi, 0x03, HDMI_IH_MUTE_I2CMPHY_STAT0);
+
+ /* Enable top level interrupt bits in HDMI block */
+ ih_mute &= ~(HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
+ HDMI_IH_MUTE_MUTE_ALL_INTERRUPT);
+ hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
+}
static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi)
{
@@ -1639,7 +1695,7 @@
dw_hdmi_update_phy_mask(hdmi);
if (hdmi->dev_type == RCAR_HDMI) {
- hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+ hdmi_writeb(hdmi, 0x3f, HDMI_IH_MUTE_PHY_STAT0);
hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE,
HDMI_PHY_POL0);
}
@@ -1655,19 +1711,21 @@
if (hdmi->dev_type == RCAR_HDMI) {
/* Reinitialization for resume */
- initialize_hdmi_ih_mutes(hdmi);
+ initialize_hdmi_rcar_ih_mutes(hdmi);
hdmi_init_clk_regenerator(hdmi);
hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE,
HDMI_PHY_POL0);
hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD |
HDMI_IH_PHY_STAT0_RX_SENSE,
HDMI_IH_PHY_STAT0);
- hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD |
- HDMI_IH_PHY_STAT0_RX_SENSE),
+ hdmi_writeb(hdmi, (HDMI_IH_MUTE_PHY_STAT0_MASK &
+ ~(HDMI_IH_PHY_STAT0_HPD |
+ HDMI_IH_PHY_STAT0_RX_SENSE)),
HDMI_IH_MUTE_PHY_STAT0);
dw_hdmi_fb_registered(hdmi);
- hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD |
- HDMI_IH_PHY_STAT0_RX_SENSE),
+ hdmi_writeb(hdmi, (HDMI_IH_MUTE_PHY_STAT0_MASK &
+ ~(HDMI_IH_PHY_STAT0_HPD |
+ HDMI_IH_PHY_STAT0_RX_SENSE)),
HDMI_IH_MUTE_PHY_STAT0);
dw_hdmi_i2c_init(hdmi);
}
@@ -1821,7 +1879,10 @@
intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
if (intr_stat) {
- hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+ if (hdmi->dev_type == RCAR_HDMI)
+ hdmi_writeb(hdmi, 0x3f, HDMI_IH_MUTE_PHY_STAT0);
+ else
+ hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
return IRQ_WAKE_THREAD;
}
@@ -1892,8 +1953,14 @@
}
hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
- hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
- HDMI_IH_MUTE_PHY_STAT0);
+ if (hdmi->dev_type == RCAR_HDMI)
+ hdmi_writeb(hdmi, (HDMI_IH_MUTE_PHY_STAT0_MASK &
+ ~(HDMI_IH_PHY_STAT0_HPD |
+ HDMI_IH_PHY_STAT0_RX_SENSE)),
+ HDMI_IH_MUTE_PHY_STAT0);
+ else
+ hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD |
+ HDMI_IH_PHY_STAT0_RX_SENSE), HDMI_IH_MUTE_PHY_STAT0);
return IRQ_HANDLED;
}
@@ -1943,6 +2010,7 @@
const struct dw_hdmi_plat_data *plat_data)
{
struct drm_device *drm = data;
+ struct device *dev_master;
struct device_node *np = dev->of_node;
struct platform_device_info pdevinfo;
struct device_node *ddc_node;
@@ -1964,7 +2032,11 @@
hdmi->encoder = encoder;
hdmi->disabled = true;
hdmi->rxsense = true;
- hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE);
+ if (hdmi->dev_type == RCAR_HDMI)
+ hdmi->phy_mask = (u8)~(BIT(3) | BIT(2) | HDMI_PHY_HPD |
+ HDMI_PHY_RX_SENSE);
+ else
+ hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE);
mutex_init(&hdmi->mutex);
mutex_init(&hdmi->audio_mutex);
@@ -2004,7 +2076,12 @@
dev_dbg(hdmi->dev, "no ddc property found\n");
}
- hdmi->regs = devm_ioremap_resource(dev, iores);
+ if (hdmi->dev_type == RCAR_HDMI)
+ dev_master = master;
+ else
+ dev_master = dev;
+
+ hdmi->regs = devm_ioremap_resource(dev_master, iores);
if (IS_ERR(hdmi->regs))
return PTR_ERR(hdmi->regs);
@@ -2040,9 +2117,12 @@
hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
- initialize_hdmi_ih_mutes(hdmi);
+ if (hdmi->dev_type == RCAR_HDMI)
+ initialize_hdmi_rcar_ih_mutes(hdmi);
+ else
+ initialize_hdmi_ih_mutes(hdmi);
- ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq,
+ ret = devm_request_threaded_irq(dev_master, irq, dw_hdmi_hardirq,
dw_hdmi_irq, IRQF_SHARED,
dev_name(dev), hdmi);
if (ret)
@@ -2080,8 +2160,14 @@
goto err_iahb;
/* Unmute interrupts */
- hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
- HDMI_IH_MUTE_PHY_STAT0);
+ if (hdmi->dev_type == RCAR_HDMI)
+ hdmi_writeb(hdmi, (HDMI_IH_MUTE_PHY_STAT0_MASK &
+ ~(HDMI_IH_PHY_STAT0_HPD |
+ HDMI_IH_PHY_STAT0_RX_SENSE)),
+ HDMI_IH_MUTE_PHY_STAT0);
+ else
+ hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD |
+ HDMI_IH_PHY_STAT0_RX_SENSE), HDMI_IH_MUTE_PHY_STAT0);
memset(&pdevinfo, 0, sizeof(pdevinfo));
pdevinfo.parent = dev;
@@ -2133,7 +2219,10 @@
platform_device_unregister(hdmi->audio);
/* Disable all interrupts */
- hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+ if (hdmi->dev_type == RCAR_HDMI)
+ hdmi_writeb(hdmi, 0x3f, HDMI_IH_MUTE_PHY_STAT0);
+ else
+ hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
hdmi->connector.funcs->destroy(&hdmi->connector);
hdmi->encoder->funcs->destroy(hdmi->encoder);
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h
index 6aadc84..00ac86a 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.h
+++ b/drivers/gpu/drm/bridge/dw-hdmi.h
@@ -566,6 +566,10 @@
HDMI_IH_PHY_STAT0_TX_PHY_LOCK = 0x2,
HDMI_IH_PHY_STAT0_HPD = 0x1,
+/* IH_I2CMPHY_STAT0 field values */
+ HDMI_IH_I2CMPHY_STAT0_I2CMPHYDONE = 0x2,
+ HDMI_IH_I2CMPHY_STAT0_I2CMPHYERROR = 0x1,
+
/* IH_I2CM_STAT0 and IH_MUTE_I2CM_STAT0 field values */
HDMI_IH_I2CM_STAT0_DONE = 0x2,
HDMI_IH_I2CM_STAT0_ERROR = 0x1,
@@ -595,6 +599,9 @@
HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = 0x02,
HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01,
+/* IH_MUTE_PHY_STAT0 field values */
+ HDMI_IH_MUTE_PHY_STAT0_MASK = 0x3f,
+
/* IH_MUTE field values */
HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT = 0x2,
HDMI_IH_MUTE_MUTE_ALL_INTERRUPT = 0x1,
@@ -950,6 +957,7 @@
/* MC_SWRSTZ field values */
HDMI_MC_SWRSTZ_TMDSSWRST_REQ = 0x02,
+ HDMI_MC_SWRSTZ_TMDSSWRST_MASK = 0xdf, /* R-Car only */
/* MC_FLOWCTRL field values */
HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_MASK = 0x1,
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
index cd79c39..ef3e87f 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
@@ -1,7 +1,7 @@
/*
* R-Car Display Unit HDMI Encoder
*
- * Copyright (C) 2014-2015 Renesas Electronics Corporation
+ * Copyright (C) 2014-2017 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
@@ -174,22 +174,25 @@
},
}
};
+
static const struct dw_hdmi_curr_ctrl rcar_du_hdmienc_cur_ctr[] = {
/* pixelclk bpp8 bpp10 bpp12 */
{
- 35500000, { 0x0344, 0x0000, 0x0000 },
+ 35500000, { 0x0283, 0x0000, 0x0000 },
}, {
44900000, { 0x0285, 0x0000, 0x0000 },
}, {
- 71000000, { 0x1184, 0x0000, 0x0000 },
+ 71000000, { 0x1183, 0x0000, 0x0000 },
}, {
- 90000000, { 0x1144, 0x0000, 0x0000 },
+ 90000000, { 0x1142, 0x0000, 0x0000 },
}, {
- 140250000, { 0x20c4, 0x0000, 0x0000 },
+ 140250000, { 0x20c0, 0x0000, 0x0000 },
}, {
- 182750000, { 0x2084, 0x0000, 0x0000 },
+ 182750000, { 0x2080, 0x0000, 0x0000 },
}, {
- 297000000, { 0x0084, 0x0000, 0x0000 },
+ 281250000, { 0x3040, 0x0000, 0x0000 },
+ }, {
+ 297000000, { 0x3041, 0x0000, 0x0000 },
}, {
~0UL, { 0x0000, 0x0000, 0x0000 },
}
@@ -198,21 +201,21 @@
static const struct dw_hdmi_multi_div rcar_du_hdmienc_multi_div[] = {
/* pixelclk bpp8 bpp10 bpp12 */
{
- 35500000, { 0x0328, 0x0000, 0x0000 },
+ 35500000, { 0x0628, 0x0000, 0x0000 },
}, {
- 44900000, { 0x0128, 0x0000, 0x0000 },
+ 44900000, { 0x0228, 0x0000, 0x0000 },
}, {
- 71000000, { 0x0314, 0x0000, 0x0000 },
+ 71000000, { 0x0614, 0x0000, 0x0000 },
}, {
- 90000000, { 0x0114, 0x0000, 0x0000 },
+ 90000000, { 0x0214, 0x0000, 0x0000 },
}, {
- 140250000, { 0x030a, 0x0000, 0x0000 },
+ 140250000, { 0x060a, 0x0000, 0x0000 },
}, {
- 182750000, { 0x010a, 0x0000, 0x0000 },
+ 182750000, { 0x020a, 0x0000, 0x0000 },
}, {
- 281250000, { 0x0305, 0x0000, 0x0000 },
+ 281250000, { 0x0605, 0x0000, 0x0000 },
}, {
- 297000000, { 0x0105, 0x0000, 0x0000 },
+ 297000000, { 0x0405, 0x0000, 0x0000 },
}, {
~0UL, { 0x0000, 0x0000, 0x0000 },
}
@@ -220,9 +223,8 @@
static const struct dw_hdmi_phy_config rcar_du_hdmienc_phy_config[] = {
/*pixelclk symbol term vlev*/
- { 74250000, 0x8009, 0x0004, 0x0272},
- { 148500000, 0x802b, 0x0004, 0x028d},
- { 297000000, 0x8039, 0x0005, 0x028d},
+ { 165000000, 0x0c88, 0x0007, 0x000c},
+ { 297000000, 0x03c8, 0x0004, 0x000c},
{ ~0UL, 0x0000, 0x0000, 0x0000}
};
@@ -340,8 +342,8 @@
}
if (dw_hdmi_use)
- ret = dw_hdmi_bind(hdmienc->dev, NULL, rcdu->ddev, encoder,
- iores, irq, plat_data);
+ ret = dw_hdmi_bind(hdmienc->dev, rcdu->dev, rcdu->ddev,
+ encoder, iores, irq, plat_data);
if (bridge) {
ret = drm_bridge_attach(rcdu->ddev, bridge);
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
index 3c019d1..2ce9277 100644
--- a/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
+++ b/drivers/gpu/drm/rcar-du/rcar_lvds_regs.h
@@ -1,7 +1,7 @@
/*
* rcar_lvds_regs.h -- R-Car LVDS Interface Registers Definitions
*
- * Copyright (C) 2013-2016 Renesas Electronics Corporation
+ * Copyright (C) 2013-2017 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
@@ -27,9 +27,9 @@
#define LVDCR1 0x0004
#define LVDCR1_CKSEL (1 << 15) /* Gen2 only */
#define LVDCR1_CHSTBY_GEN2(n) (3 << (2 + (n) * 2)) /* Gen2 only */
-#define LVDCR1_CHSTBY_GEN3(n) (1 << (2 + (n) * 2)) /* Gen3 only */
+#define LVDCR1_CHSTBY_GEN3(n) (3 << (2 + (n) * 2)) /* Gen3 only */
#define LVDCR1_CLKSTBY_GEN2 (3 << 0) /* Gen2 only */
-#define LVDCR1_CLKSTBY_GEN3 (1 << 0) /* Gen3 only */
+#define LVDCR1_CLKSTBY_GEN3 (3 << 0) /* Gen3 only */
#define LVDPLLCR 0x0008
#define LVDPLLCR_CEEN (1 << 14)
diff --git a/drivers/hwspinlock/rcar_hwspinlock.c b/drivers/hwspinlock/rcar_hwspinlock.c
index 35ba8c1..b92db1b 100644
--- a/drivers/hwspinlock/rcar_hwspinlock.c
+++ b/drivers/hwspinlock/rcar_hwspinlock.c
@@ -1,7 +1,7 @@
/*
* rcar_hwspinlock.c
*
- * Copyright (C) 2016 Renesas Electronics Corporation
+ * Copyright (C) 2016-2017 Renesas Electronics Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@@ -13,7 +13,6 @@
* GNU General Public License for more details.
*/
#include <linux/hwspinlock.h>
-#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
@@ -60,18 +59,6 @@
struct hwspinlock_device *bank;
struct hwspinlock *lock;
struct resource *res = NULL;
- struct clk *clock;
-
- /* enable MFIS clock */
- clock = of_clk_get(pdev->dev.of_node, 0);
- if (!clock) {
- dev_err(&pdev->dev, "Failed to get clock.\n");
- ret = PTR_ERR(clock);
- goto out;
- }
- clk_prepare_enable(clock);
-
- pm_runtime_enable(&pdev->dev);
/* map MFIS register */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -80,7 +67,7 @@
if (IS_ERR(addr)) {
dev_err(&pdev->dev, "Failed to remap MFIS Lock register.\n");
ret = PTR_ERR(addr);
- goto clk_disable;
+ goto out;
}
/* create hwspinlock control info */
@@ -90,7 +77,7 @@
if (!bank) {
dev_err(&pdev->dev, "Failed to allocate memory.\n");
ret = PTR_ERR(bank);
- goto clk_disable;
+ goto out;
}
for (idx = 0; idx < RCAR_HWSPINLOCK_NUM; idx++) {
@@ -99,15 +86,13 @@
}
platform_set_drvdata(pdev, bank);
+ pm_runtime_enable(&pdev->dev);
+
/* register hwspinlock */
ret = hwspin_lock_register(bank, &pdev->dev, &rcar_hwspinlock_ops,
0, RCAR_HWSPINLOCK_NUM);
- if (!ret)
- goto out;
-
-clk_disable:
- if (clock)
- clk_disable_unprepare(clock);
+ if (ret)
+ pm_runtime_disable(&pdev->dev);
out:
return ret;
@@ -116,7 +101,6 @@
static int rcar_hwspinlock_remove(struct platform_device *pdev)
{
int ret;
- struct clk *clock = NULL;
ret = hwspin_lock_unregister(platform_get_drvdata(pdev));
if (ret) {
@@ -125,9 +109,6 @@
}
pm_runtime_disable(&pdev->dev);
- clock = of_clk_get(pdev->dev.of_node, 0);
- if (clock)
- clk_disable_unprepare(clock);
return 0;
}
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index b4dde6a..4989496 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -141,6 +141,7 @@
struct dma_chan *dma_rx;
struct scatterlist sg;
enum dma_data_direction dma_direction;
+ int suspended;
};
#define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent)
@@ -919,6 +920,9 @@
int i, ret;
long time_left;
+ if (priv->suspended)
+ return -EBUSY;
+
pm_runtime_get_sync(dev);
ret = rcar_i2c_bus_barrier(priv);
@@ -1129,9 +1133,11 @@
static int rcar_i2c_suspend(struct device *dev)
{
int ret = 0;
-#ifdef CONFIG_RCAR_DDR_BACKUP
struct platform_device *pdev = to_platform_device(dev);
+ struct rcar_i2c_priv *priv = platform_get_drvdata(pdev);
+ priv->suspended = 1;
+#ifdef CONFIG_RCAR_DDR_BACKUP
pm_runtime_get_sync(dev);
ret = rcar_i2c_save_regs(pdev);
pm_runtime_put(dev);
@@ -1142,19 +1148,20 @@
static int rcar_i2c_resume(struct device *dev)
{
int ret = 0;
-#ifdef CONFIG_RCAR_DDR_BACKUP
struct platform_device *pdev = to_platform_device(dev);
+ struct rcar_i2c_priv *priv = platform_get_drvdata(pdev);
+#ifdef CONFIG_RCAR_DDR_BACKUP
pm_runtime_get_sync(dev);
ret = rcar_i2c_restore_regs(pdev);
pm_runtime_put(dev);
#endif /* CONFIG_RCAR_DDR_BACKUP */
+ priv->suspended = 0;
return ret;
}
static const struct dev_pm_ops rcar_i2c_pm_ops = {
- .suspend = rcar_i2c_suspend,
- .resume_early = rcar_i2c_resume,
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(rcar_i2c_suspend,rcar_i2c_resume)
};
#define DEV_PM_OPS (&rcar_i2c_pm_ops)
diff --git a/drivers/media/i2c/adv7482.c b/drivers/media/i2c/adv7482.c
index 6e5dddb..f59d0ca 100644
--- a/drivers/media/i2c/adv7482.c
+++ b/drivers/media/i2c/adv7482.c
@@ -2,7 +2,7 @@
* drivers/media/i2c/adv7482.c
* This file is Analog Devices ADV7482 HDMI receiver driver.
*
- * Copyright (C) 2015-2016 Renesas Electronics Corporation
+ * Copyright (C) 2015-2017 Renesas Electronics Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@@ -2349,41 +2349,63 @@
struct adv7482_link_config link_config;
int ret;
- ret = adv7482_write_register(client, ADV7482_I2C_IO,
- ADV7482_IO_PWR_MAN_REG, ADV7482_IO_PWR_ON);
- if (ret < 0)
- return ret;
-
ret = adv7482_parse_dt(dev->of_node, &link_config);
if (ret)
return ret;
- /* Initializes ADV7482 to its default values */
- ret = adv7482_write_registers(client, link_config.regs);
+ /* SW reset ADV7482 to its default values */
+ if (link_config.sw_reset) {
+ ret = adv7482_write_registers(client, adv7482_sw_reset);
- /* Power down */
- ret = adv7482_write_registers(client, link_config.power_down);
+ /* check rd_info */
+ {
+ u8 msb;
+ u8 lsb;
+
+ ret = adv7482_read_register(client, ADV7482_I2C_IO,
+ ADV7482_IO_RD_INFO1_REG, &lsb);
+ if (ret < 0)
+ return ret;
+
+ ret = adv7482_read_register(client, ADV7482_I2C_IO,
+ ADV7482_IO_RD_INFO2_REG, &msb);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ if (link_config.hdmi_in) {
+ ret = adv7482_write_registers(client,
+ adv7482_init_txa_4lane);
+ /* Power down */
+ ret = adv7482_write_registers(client,
+ adv7482_power_down_txa_4lane);
+ }
+
+ /* Initializes ADV7482 to its default values */
+ if (link_config.sdp_in) {
+ ret = adv7482_write_registers(client,
+ adv7482_init_txb_1lane);
+ /* Power down */
+ ret = adv7482_write_registers(client,
+ adv7482_power_down_txb_1lane);
+ }
if (link_config.sdp_in && link_config.hdmi_in) {
/* Power up hdmi rx */
ret = adv7482_write_registers(client,
adv7482_power_up_hdmi_rx);
- if (ret < 0)
- return ret;
-
/* Enable csi4 and sci1 */
ret = adv7482_write_registers(client,
adv7482_enable_csi4_csi1);
- if (ret < 0)
- return ret;
}
return ret;
}
-static SIMPLE_DEV_PM_OPS(adv7482_pm_ops, adv7482_suspend, adv7482_resume);
-#define ADV7482_PM_OPS (&adv7482_pm_ops)
-
+const struct dev_pm_ops adv7482_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(adv7482_suspend, adv7482_resume)
+};
#else
#define ADV7482_PM_OPS NULL
#endif
@@ -2399,7 +2421,7 @@
static struct i2c_driver adv7482_driver = {
.driver = {
.name = DRIVER_NAME,
- .pm = ADV7482_PM_OPS,
+ .pm = &adv7482_pm_ops,
.of_match_table = adv7482_of_ids,
},
.probe = adv7482_probe,
diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c
index 05d5485..287917c 100644
--- a/drivers/media/platform/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/rcar-vin/rcar-core.c
@@ -1,7 +1,7 @@
/*
* Driver for Renesas R-Car VIN
*
- * Copyright (C) 2016 Renesas Electronics Corp.
+ * Copyright (C) 2016-2017 Renesas Electronics Corp.
* Copyright (C) 2011-2013 Renesas Solutions Corp.
* Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
* Copyright (C) 2008 Magnus Damm
@@ -838,6 +838,9 @@
struct rvin_dev *vin = notifier_to_vin(notifier);
unsigned int i;
+ if (!subdev->dev)
+ return;
+
mutex_lock(&vin->group->lock);
for (i = 0; i < RVIN_CSI_MAX; i++) {
struct device_node *del = subdev->dev->of_node;
@@ -1445,12 +1448,12 @@
vin->dev = &pdev->dev;
- if (soc_device_match(r8a7795es1))
- vin->info = &rcar_info_r8a7795_es1x;
-
vin->info = match->data;
vin->last_input = NULL;
+ if (soc_device_match(r8a7795es1))
+ vin->info = &rcar_info_r8a7795_es1x;
+
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (mem == NULL)
return -EINVAL;
@@ -1495,11 +1498,11 @@
rvin_v4l2_remove(vin);
+ v4l2_async_notifier_unregister(&vin->notifier);
+
if (vin->group)
rvin_group_delete(vin);
- v4l2_async_notifier_unregister(&vin->notifier);
-
rvin_dma_remove(vin);
return 0;
@@ -1509,23 +1512,38 @@
static int rcar_vin_suspend(struct device *dev)
{
struct rvin_dev *vin = dev_get_drvdata(dev);
+ int ret;
if ((vin->info->chip == RCAR_GEN3) &&
((vin->index == 0) || (vin->index == 4)))
vin->chsel = rvin_get_chsel(vin);
- return 0;
+ if (vin->state != STALLED)
+ return 0;
+
+ ret = rvin_suspend_stop_streaming(vin);
+
+ pm_runtime_put(vin->dev);
+
+ return ret;
}
static int rcar_vin_resume(struct device *dev)
{
struct rvin_dev *vin = dev_get_drvdata(dev);
+ int ret;
if ((vin->info->chip == RCAR_GEN3) &&
((vin->index == 0) || (vin->index == 4)))
rvin_set_chsel(vin, vin->chsel);
- return 0;
+ if (vin->state != STALLED)
+ return 0;
+
+ pm_runtime_get_sync(vin->dev);
+ ret = rvin_resume_start_streaming(vin);
+
+ return ret;
}
static SIMPLE_DEV_PM_OPS(rcar_vin_pm_ops,
diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c
index 7440cfc..529e845 100644
--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
@@ -1,7 +1,7 @@
/*
* Driver for Renesas R-Car MIPI CSI-2
*
- * Copyright (C) 2016 Renesas Electronics Corp.
+ * Copyright (C) 2016-2017 Renesas Electronics Corp.
*
* 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
@@ -13,6 +13,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/sys_soc.h>
@@ -98,50 +99,90 @@
/* PHY Test Interface Clear bits */
#define PHTC_TESTCLR (1 << 0)
-/* PHY Frequency Control bits */
-#define PHYPLL_HSFREQRANGE_80MBPS (0x00 << 16)
-#define PHYPLL_HSFREQRANGE_90MBPS (0x10 << 16)
-#define PHYPLL_HSFREQRANGE_100MBPS (0x20 << 16)
-#define PHYPLL_HSFREQRANGE_110MBPS (0x30 << 16)
-#define PHYPLL_HSFREQRANGE_120MBPS (0x01 << 16)
-#define PHYPLL_HSFREQRANGE_130MBPS (0x11 << 16)
-#define PHYPLL_HSFREQRANGE_140MBPS (0x21 << 16)
-#define PHYPLL_HSFREQRANGE_150MBPS (0x31 << 16)
-#define PHYPLL_HSFREQRANGE_160MBPS (0x02 << 16)
-#define PHYPLL_HSFREQRANGE_170MBPS (0x12 << 16)
-#define PHYPLL_HSFREQRANGE_180MBPS (0x22 << 16)
-#define PHYPLL_HSFREQRANGE_190MBPS (0x32 << 16)
-#define PHYPLL_HSFREQRANGE_205MBPS (0x03 << 16)
-#define PHYPLL_HSFREQRANGE_220MBPS (0x13 << 16)
-#define PHYPLL_HSFREQRANGE_235MBPS (0x23 << 16)
-#define PHYPLL_HSFREQRANGE_250MBPS (0x33 << 16)
-#define PHYPLL_HSFREQRANGE_275MBPS (0x04 << 16)
-#define PHYPLL_HSFREQRANGE_300MBPS (0x14 << 16)
-#define PHYPLL_HSFREQRANGE_325MBPS (0x05 << 16)
-#define PHYPLL_HSFREQRANGE_350MBPS (0x15 << 16)
-#define PHYPLL_HSFREQRANGE_400MBPS (0x25 << 16)
-#define PHYPLL_HSFREQRANGE_450MBPS (0x06 << 16)
-#define PHYPLL_HSFREQRANGE_500MBPS (0x16 << 16)
-#define PHYPLL_HSFREQRANGE_550MBPS (0x07 << 16)
-#define PHYPLL_HSFREQRANGE_600MBPS (0x17 << 16)
-#define PHYPLL_HSFREQRANGE_650MBPS (0x08 << 16)
-#define PHYPLL_HSFREQRANGE_700MBPS (0x18 << 16)
-#define PHYPLL_HSFREQRANGE_750MBPS (0x09 << 16)
-#define PHYPLL_HSFREQRANGE_800MBPS (0x19 << 16)
-#define PHYPLL_HSFREQRANGE_850MBPS (0x29 << 16)
-#define PHYPLL_HSFREQRANGE_900MBPS (0x39 << 16)
-#define PHYPLL_HSFREQRANGE_950MBPS (0x0A << 16)
-#define PHYPLL_HSFREQRANGE_1000MBPS (0x1A << 16)
-#define PHYPLL_HSFREQRANGE_1050MBPS (0x2A << 16)
-#define PHYPLL_HSFREQRANGE_1100MBPS (0x3A << 16)
-#define PHYPLL_HSFREQRANGE_1150MBPS (0x0B << 16)
-#define PHYPLL_HSFREQRANGE_1200MBPS (0x1B << 16)
-#define PHYPLL_HSFREQRANGE_1250MBPS (0x2B << 16)
-#define PHYPLL_HSFREQRANGE_1300MBPS (0x3B << 16)
-#define PHYPLL_HSFREQRANGE_1350MBPS (0x0C << 16)
-#define PHYPLL_HSFREQRANGE_1400MBPS (0x1C << 16)
-#define PHYPLL_HSFREQRANGE_1450MBPS (0x2C << 16)
-#define PHYPLL_HSFREQRANGE_1500MBPS (0x3C << 16)
+/* PHY Frequency Control */
+#define CSI2_FRE_NUM 43
+
+enum fre_range {
+ BPS_80M,
+ BPS_90M,
+ BPS_100M,
+ BPS_110M,
+ BPS_120M,
+ BPS_130M,
+ BPS_140M,
+ BPS_150M,
+ BPS_160M,
+ BPS_170M,
+ BPS_180M,
+ BPS_190M,
+ BPS_205M,
+ BPS_220M,
+ BPS_235M,
+ BPS_250M,
+ BPS_275M,
+ BPS_300M,
+ BPS_325M,
+ BPS_350M,
+ BPS_400M,
+ BPS_450M,
+ BPS_500M,
+ BPS_550M,
+ BPS_600M,
+ BPS_650M,
+ BPS_700M,
+ BPS_750M,
+ BPS_800M,
+ BPS_850M,
+ BPS_900M,
+ BPS_950M,
+ BPS_1000M,
+ BPS_1050M,
+ BPS_1100M,
+ BPS_1150M,
+ BPS_1200M,
+ BPS_1250M,
+ BPS_1300M,
+ BPS_1350M,
+ BPS_1400M,
+ BPS_1450M,
+ BPS_1500M,
+};
+
+struct rcar_csi2_info {
+ int fre_range[CSI2_FRE_NUM];
+};
+
+static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = {
+ .fre_range = {
+ (0x00 << 16), (0x10 << 16), (0x20 << 16), (0x30 << 16),
+ (0x01 << 16), (0x11 << 16), (0x21 << 16), (0x31 << 16),
+ (0x02 << 16), (0x12 << 16), (0x22 << 16), (0x32 << 16),
+ (0x03 << 16), (0x13 << 16), (0x23 << 16), (0x33 << 16),
+ (0x04 << 16), (0x14 << 16), (0x25 << 16), (0x35 << 16),
+ (0x05 << 16), (0x26 << 16), (0x36 << 16), (0x37 << 16),
+ (0x07 << 16), (0x18 << 16), (0x28 << 16), (0x39 << 16),
+ (0x09 << 16), (0x19 << 16), (0x29 << 16), (0x3a << 16),
+ (0x0a << 16), (0x1a << 16), (0x2a << 16), (0x3b << 16),
+ (0x0b << 16), (0x1b << 16), (0x2b << 16), (0x3c << 16),
+ (0x0c << 16), (0x1c << 16), (0x2c << 16),
+ },
+};
+
+static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = {
+ .fre_range = {
+ (0x00 << 16), (0x10 << 16), (0x20 << 16), (0x30 << 16),
+ (0x01 << 16), (0x11 << 16), (0x21 << 16), (0x31 << 16),
+ (0x02 << 16), (0x12 << 16), (0x22 << 16), (0x32 << 16),
+ (0x03 << 16), (0x13 << 16), (0x23 << 16), (0x33 << 16),
+ (0x04 << 16), (0x14 << 16), (0x05 << 16), (0x15 << 16),
+ (0x25 << 16), (0x06 << 16), (0x16 << 16), (0x07 << 16),
+ (0x17 << 16), (0x08 << 16), (0x18 << 16), (0x09 << 16),
+ (0x19 << 16), (0x29 << 16), (0x39 << 16), (0x0a << 16),
+ (0x1a << 16), (0x2a << 16), (0x3a << 16), (0x0b << 16),
+ (0x1b << 16), (0x2b << 16), (0x3b << 16), (0x0c << 16),
+ (0x1c << 16), (0x2c << 16), (0x3c << 16),
+ },
+};
enum rcar_csi2_pads {
RCAR_CSI2_SINK,
@@ -159,6 +200,7 @@
struct device *dev;
void __iomem *base;
spinlock_t lock;
+ const struct rcar_csi2_info *info;
unsigned short lanes;
unsigned char swap[4];
@@ -286,7 +328,7 @@
case 1:
fld = FLD_FLD_NUM(1) | FLD_FLD_EN;
phycnt = PHYCNT_ENABLECLK | PHYCNT_ENABLE_0;
- phypll = PHYPLL_HSFREQRANGE_400MBPS;
+ phypll = priv->info->fre_range[BPS_205M];
break;
case 4:
fld = FLD_FLD_NUM(2) | FLD_FLD_EN4 | FLD_FLD_EN3 |
@@ -297,18 +339,17 @@
/* Calculate MBPS per lane, assume 32 bits per pixel at 60Hz */
pixels = (priv->mf.width * priv->mf.height);
if (pixels <= 640 * 480)
- phypll = PHYPLL_HSFREQRANGE_100MBPS;
+ phypll = priv->info->fre_range[BPS_100M];
else if (pixels <= 720 * 576)
- phypll = PHYPLL_HSFREQRANGE_190MBPS;
+ phypll = priv->info->fre_range[BPS_190M];
else if (pixels <= 1280 * 720)
- phypll = PHYPLL_HSFREQRANGE_450MBPS;
+ phypll = priv->info->fre_range[BPS_450M];
else if (pixels <= 1920 * 1080) {
if (priv->mf.field == V4L2_FIELD_NONE)
- phypll = PHYPLL_HSFREQRANGE_900MBPS;
+ phypll = priv->info->fre_range[BPS_900M];
else
- phypll = PHYPLL_HSFREQRANGE_450MBPS;
- }
- else
+ phypll = priv->info->fre_range[BPS_450M];
+ } else
goto error;
break;
@@ -316,6 +357,8 @@
goto error;
}
+ csi_dbg(priv, "PHYPLL:0x%x\n", phypll);
+
/* Init */
iowrite32(TREF_TREF, priv->base + TREF_REG);
rcar_csi2_reset(priv);
@@ -330,20 +373,20 @@
priv->base + LSWAP_REG);
if (!soc_device_match(r8a7795es1x) && !soc_device_match(r8a7796)) {
- /* Set PHY Test Interface Write Register for external
- * reference resistor is unnecessary in R-Car H3(WS2.0)
- */
- iowrite32(0x012701e2, priv->base + PHTW_REG);
+ /* Set PHY Test Interface Write Register in R-Car H3(ES2.0) */
+ iowrite32(0x01cc01e2, priv->base + PHTW_REG);
iowrite32(0x010101e3, priv->base + PHTW_REG);
iowrite32(0x010101e4, priv->base + PHTW_REG);
iowrite32(0x01100104, priv->base + PHTW_REG);
+ iowrite32(0x01030100, priv->base + PHTW_REG);
+ iowrite32(0x01800107, priv->base + PHTW_REG);
}
/* Start */
iowrite32(phypll, priv->base + PHYPLL_REG);
- /* Set CSI0CLK Frequency Configuration Preset Register for external
- * reference resistor is unnecessary in R-Car H3(WS2.0)
+ /* Set CSI0CLK Frequency Configuration Preset Register
+ * in R-Car H3(ES2.0)
*/
if (!soc_device_match(r8a7795es1x) && !soc_device_match(r8a7796))
iowrite32(CSI0CLKFREQRANGE(32), priv->base + CSI0CLKFCPR_REG);
@@ -450,9 +493,14 @@
*/
static const struct of_device_id rcar_csi2_of_table[] = {
- { .compatible = "renesas,r8a7795-csi2" },
- { .compatible = "renesas,r8a7796-csi2" },
- { .compatible = "renesas,rcar-gen3-csi2" },
+ {
+ .compatible = "renesas,r8a7795-csi2",
+ .data = &rcar_csi2_info_r8a7795,
+ },
+ {
+ .compatible = "renesas,r8a7796-csi2",
+ .data = &rcar_csi2_info_r8a7796,
+ },
{ },
};
MODULE_DEVICE_TABLE(of, rcar_csi2_of_table);
@@ -550,6 +598,7 @@
static int rcar_csi2_probe(struct platform_device *pdev)
{
struct rcar_csi2 *priv;
+ const struct of_device_id *match;
unsigned int i;
int ret;
u32 vc_num;
@@ -558,6 +607,14 @@
if (!priv)
return -ENOMEM;
+ match = of_match_device(of_match_ptr(rcar_csi2_of_table), &pdev->dev);
+ if (!match)
+ return -ENODEV;
+ priv->info = match->data;
+
+ /* HSFREQRANGE bit information of H3(ES1.x) and M3(WS1.0) are same. */
+ if (soc_device_match(r8a7795es1x))
+ priv->info = &rcar_csi2_info_r8a7796;
priv->dev = &pdev->dev;
spin_lock_init(&priv->lock);
@@ -577,7 +634,6 @@
vc_num = priv->vc_num;
platform_set_drvdata(pdev, priv);
-retry:
priv->subdev.owner = THIS_MODULE;
priv->subdev.dev = &pdev->dev;
v4l2_subdev_init(&priv->subdev, &rcar_csi2_subdev_ops);
@@ -602,10 +658,6 @@
if (ret < 0)
return ret;
- vc_num--;
- if (vc_num > 0)
- goto retry;
-
pm_runtime_enable(&pdev->dev);
csi_info(priv, "%d lanes found. virtual channel number %d use\n",
@@ -625,11 +677,34 @@
return 0;
}
+static int rcar_csi2_suspend(struct device *dev)
+{
+ struct rcar_csi2 *priv = dev_get_drvdata(dev);
+
+ pm_runtime_put_sync(priv->dev);
+
+ return 0;
+}
+
+static int rcar_csi2_resume(struct device *dev)
+{
+ struct rcar_csi2 *priv = dev_get_drvdata(dev);
+
+ pm_runtime_get_sync(priv->dev);
+
+ return 0;
+}
+
+const struct dev_pm_ops rcar_csi2_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(rcar_csi2_suspend, rcar_csi2_resume)
+};
+
static struct platform_driver __refdata rcar_csi2_pdrv = {
.remove = rcar_csi2_remove,
.probe = rcar_csi2_probe,
.driver = {
.name = "rcar-csi2",
+ .pm = &rcar_csi2_pm_ops,
.of_match_table = of_match_ptr(rcar_csi2_of_table),
},
};
diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
index 3e7fb7d..667b162 100644
--- a/drivers/media/platform/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/rcar-vin/rcar-dma.c
@@ -1,7 +1,7 @@
/*
* Driver for Renesas R-Car VIN
*
- * Copyright (C) 2016 Renesas Electronics Corp.
+ * Copyright (C) 2016-2017 Renesas Electronics Corp.
* Copyright (C) 2011-2013 Renesas Solutions Corp.
* Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
* Copyright (C) 2008 Magnus Damm
@@ -1249,9 +1249,12 @@
* If capture is stalled add buffer to HW and restart
* capturing if HW is ready to continue.
*/
- if (vin->state == STALLED)
- if (rvin_fill_hw(vin))
+ if (vin->state == STALLED) {
+ if (rvin_fill_hw(vin)) {
rvin_capture_on(vin);
+ vin->state = RUNNING;
+ }
+ }
spin_unlock_irqrestore(&vin->qlock, flags);
}
@@ -1416,6 +1419,66 @@
rvin_disable_interrupts(vin);
}
+int rvin_resume_start_streaming(struct rvin_dev *vin)
+{
+ unsigned long flags;
+ int ret;
+
+ ret = __rvin_start_streaming(vin);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(&vin->qlock, flags);
+
+ vin->sequence = 0;
+
+ rvin_crop_scale_comp(vin);
+ ret = rvin_setup(vin);
+
+ /* Return all buffers if something went wrong */
+ if (ret) {
+ return_all_buffers(vin, VB2_BUF_STATE_QUEUED);
+ __rvin_stop_streaming(vin);
+ }
+
+ spin_unlock_irqrestore(&vin->qlock, flags);
+
+ return ret;
+}
+
+int rvin_suspend_stop_streaming(struct rvin_dev *vin)
+{
+ unsigned long flags;
+ struct v4l2_subdev *source, *bridge = NULL;
+
+ /* Release all active buffers */
+ spin_lock_irqsave(&vin->qlock, flags);
+ return_all_buffers(vin, VB2_BUF_STATE_ERROR);
+ spin_unlock_irqrestore(&vin->qlock, flags);
+
+ __rvin_stop_streaming(vin);
+ source = vin_to_source(vin);
+ if (!source)
+ return -EINVAL;
+
+ if (vin_have_bridge(vin)) {
+ bridge = vin_to_bridge(vin);
+
+ if (!bridge)
+ return -EINVAL;
+
+ mutex_lock(&vin->group->lock);
+ bridge->entity.stream_count = 0;
+ source->entity.stream_count = 0;
+ mutex_unlock(&vin->group->lock);
+ }
+
+ /* disable interrupts */
+ rvin_disable_interrupts(vin);
+
+ return 0;
+}
+
static const struct vb2_ops rvin_qops = {
.queue_setup = rvin_queue_setup,
.buf_prepare = rvin_buffer_prepare,
diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c
index a0ad84c..ade1f8b 100644
--- a/drivers/media/platform/rcar-vin/rcar-v4l2.c
+++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c
@@ -1,7 +1,7 @@
/*
* Driver for Renesas R-Car VIN
*
- * Copyright (C) 2016 Renesas Electronics Corp.
+ * Copyright (C) 2016-2017 Renesas Electronics Corp.
* Copyright (C) 2011-2013 Renesas Solutions Corp.
* Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
* Copyright (C) 2008 Magnus Damm
@@ -530,10 +530,17 @@
{
struct rvin_dev *vin = video_drvdata(file);
struct v4l2_subdev *sd = vin_to_source(vin);
+ struct rvin_source_fmt source;
if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
+ __rvin_try_format_source(vin, V4L2_SUBDEV_FORMAT_TRY,
+ &vin->format, &source);
+
+ vin->source.width = source.width;
+ vin->source.height = source.height;
+
return v4l2_subdev_call(sd, video, g_pixelaspect, &crop->pixelaspect);
}
diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h
index d85d0ab..1f9a8dd 100644
--- a/drivers/media/platform/rcar-vin/rcar-vin.h
+++ b/drivers/media/platform/rcar-vin/rcar-vin.h
@@ -1,7 +1,7 @@
/*
* Driver for Renesas R-Car VIN
*
- * Copyright (C) 2016 Renesas Electronics Corp.
+ * Copyright (C) 2016-2017 Renesas Electronics Corp.
* Copyright (C) 2011-2013 Renesas Solutions Corp.
* Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
* Copyright (C) 2008 Magnus Damm
@@ -274,4 +274,7 @@
int rvin_set_chsel(struct rvin_dev *vin, u8 chsel);
int rvin_get_chsel(struct rvin_dev *vin);
+int rvin_resume_start_streaming(struct rvin_dev *vin);
+int rvin_suspend_stop_streaming(struct rvin_dev *vin);
+
#endif
diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h
index 665772f..8a95c7f 100644
--- a/drivers/media/platform/vsp1/vsp1.h
+++ b/drivers/media/platform/vsp1/vsp1.h
@@ -114,7 +114,7 @@
};
int vsp1_gen3_vspdl_check(struct vsp1_device *vsp1);
-int vsp1_device_get(struct vsp1_device *vsp1);
+int vsp1_device_get(struct vsp1_device *vsp1, unsigned int index);
void vsp1_device_put(struct vsp1_device *vsp1);
void vsp1_underrun_workaround(struct vsp1_device *vsp1, bool reset);
diff --git a/drivers/media/platform/vsp1/vsp1_brs.c b/drivers/media/platform/vsp1/vsp1_brs.c
index e9811a7..6a4079f 100644
--- a/drivers/media/platform/vsp1/vsp1_brs.c
+++ b/drivers/media/platform/vsp1/vsp1_brs.c
@@ -1,7 +1,7 @@
/*
* vsp1_brs.c -- R-Car VSP1 Blend ROP Sub Unit
*
- * Copyright (C) 2016 Renesas Electronics Corporation
+ * Copyright (C) 2016-2017 Renesas Electronics Corporation
*
* This file is based on the drivers/media/platform/vsp1/vsp1_bru.c
*
@@ -112,23 +112,27 @@
unsigned int pad, struct v4l2_mbus_framefmt *fmt)
{
struct v4l2_mbus_framefmt *format;
+ struct vsp1_device *vsp1 = brs->entity.vsp1;
+ int brs_base;
- switch (pad) {
- case BRS_PAD_SINK(0):
+ brs_base = vsp1->info->rpf_count - vsp1->num_brs_inputs;
+
+ if (!pad)
+ goto not_set_code;
+
+ if (pad == brs_base) {
/* Default to YUV if the requested format is not supported. */
if (fmt->code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
fmt->code != MEDIA_BUS_FMT_AYUV8_1X32)
fmt->code = MEDIA_BUS_FMT_AYUV8_1X32;
- break;
-
- default:
+ } else {
/* The BRS can't perform format conversion. */
format = vsp1_entity_get_pad_format(&brs->entity, config,
- BRS_PAD_SINK(0));
+ BRS_PAD_SINK(brs_base));
fmt->code = format->code;
- break;
}
+not_set_code:
fmt->width = clamp(fmt->width, BRS_MIN_SIZE, BRS_MAX_SIZE);
fmt->height = clamp(fmt->height, BRS_MIN_SIZE, BRS_MAX_SIZE);
fmt->field = V4L2_FIELD_NONE;
@@ -140,9 +144,11 @@
struct v4l2_subdev_format *fmt)
{
struct vsp1_brs *brs = to_brs(subdev);
+ struct vsp1_device *vsp1 = brs->entity.vsp1;
struct v4l2_subdev_pad_config *config;
struct v4l2_mbus_framefmt *format;
int ret = 0;
+ int brs_base;
mutex_lock(&brs->entity.lock);
@@ -168,11 +174,13 @@
compose->height = format->height;
}
+ brs_base = vsp1->info->rpf_count - vsp1->num_brs_inputs;
+
/* Propagate the format code to all pads */
- if (fmt->pad == BRS_PAD_SINK(0)) {
+ if (fmt->pad == BRS_PAD_SINK(brs_base)) {
unsigned int i;
- for (i = 0; i <= brs->entity.source_pad; ++i) {
+ for (i = brs_base; i <= brs->entity.source_pad; ++i) {
format = vsp1_entity_get_pad_format(&brs->entity,
config, i);
format->code = fmt->format.code;
@@ -290,9 +298,14 @@
enum vsp1_entity_params params)
{
struct vsp1_brs *brs = to_brs(&entity->subdev);
+ struct vsp1_device *vsp1 = brs->entity.vsp1;
struct v4l2_mbus_framefmt *format;
unsigned int flags;
unsigned int i;
+ unsigned int reg_offset = 3; /* for use from RPF3 */
+ unsigned int brs_base;
+
+ brs_base = vsp1->info->rpf_count - vsp1->num_brs_inputs;
if (params != VSP1_ENTITY_PARAMS_INIT)
return;
@@ -303,18 +316,27 @@
if (pipe->vmute_flag) {
vsp1_brs_write(brs, dl, VI6_BRS_INCTRL, 0);
vsp1_brs_write(brs, dl, VI6_BRS_VIRRPF_SIZE,
- (format->width << VI6_BRS_VIRRPF_SIZE_HSIZE_SHIFT) |
- (format->height << VI6_BRS_VIRRPF_SIZE_VSIZE_SHIFT));
+ (format->width << VI6_BRS_VIRRPF_SIZE_HSIZE_SHIFT) |
+ (format->height << VI6_BRS_VIRRPF_SIZE_VSIZE_SHIFT));
vsp1_brs_write(brs, dl, VI6_BRS_VIRRPF_LOC, 0);
vsp1_brs_write(brs, dl, VI6_BRS_VIRRPF_COL, (0xFF << 24));
- for (i = 0; i < brs->entity.source_pad; ++i) {
- vsp1_brs_write(brs, dl, VI6_BRS_BLD(i),
- VI6_BRS_BLD_CCMDX_255_SRC_A |
- VI6_BRS_BLD_CCMDY_SRC_A |
- VI6_BRS_BLD_ACMDX_255_SRC_A |
- VI6_BRS_BLD_ACMDY_COEFY |
- VI6_BRS_BLD_COEFY_MASK);
+ for (i = brs_base; i < brs->entity.source_pad; ++i) {
+ u32 ctrl = 0;
+
+ if (i == brs_base)
+ ctrl |= VI6_BRS_CTRL_DSTSEL_VRPF;
+
+ ctrl |= VI6_BRS_CTRL_SRCSEL_BRSIN(i - reg_offset);
+ vsp1_brs_write(brs, dl, VI6_BRS_CTRL(i - reg_offset),
+ ctrl);
+
+ vsp1_brs_write(brs, dl, VI6_BRS_BLD(i - reg_offset),
+ VI6_BRS_BLD_CCMDX_255_SRC_A |
+ VI6_BRS_BLD_CCMDY_SRC_A |
+ VI6_BRS_BLD_ACMDX_255_SRC_A |
+ VI6_BRS_BLD_ACMDY_COEFY |
+ VI6_BRS_BLD_COEFY_MASK);
}
return;
@@ -345,7 +367,7 @@
vsp1_brs_write(brs, dl, VI6_BRS_VIRRPF_COL, brs->bgcolor |
(0xff << VI6_BRS_VIRRPF_COL_A_SHIFT));
- for (i = 0; i < brs->entity.source_pad; ++i) {
+ for (i = reg_offset; i < brs->entity.source_pad; ++i) {
bool premultiplied = false;
u32 ctrl = 0;
@@ -367,18 +389,12 @@
/* Select the virtual RPF as the Blend/ROP unit A DST input to
* serve as a background color.
*/
- if (i == 0)
+ if (i == brs_base)
ctrl |= VI6_BRS_CTRL_DSTSEL_VRPF;
- /* Route BRS inputs 0 to 3 as SRC inputs to Blend/ROP units A to
- * D in that order. The Blend/ROP unit B SRC is hardwired to the
- * ROP unit output, the corresponding register bits must be set
- * to 0.
- */
- if (i != 1)
- ctrl |= VI6_BRS_CTRL_SRCSEL_BRSIN(i);
+ ctrl |= VI6_BRS_CTRL_SRCSEL_BRSIN(i - reg_offset);
- vsp1_brs_write(brs, dl, VI6_BRS_CTRL(i), ctrl);
+ vsp1_brs_write(brs, dl, VI6_BRS_CTRL(i - reg_offset), ctrl);
/* Harcode the blending formula to
*
@@ -392,7 +408,7 @@
*
* otherwise.
*/
- vsp1_brs_write(brs, dl, VI6_BRS_BLD(i),
+ vsp1_brs_write(brs, dl, VI6_BRS_BLD(i - reg_offset),
VI6_BRS_BLD_CCMDX_255_SRC_A |
(premultiplied ? VI6_BRS_BLD_CCMDY_COEFY :
VI6_BRS_BLD_CCMDY_SRC_A) |
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index 988f2b7..019ae2b 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -1,7 +1,7 @@
/*
* vsp1_dl.h -- R-Car VSP1 Display List
*
- * Copyright (C) 2015-2016 Renesas Corporation
+ * Copyright (C) 2015-2017 Renesas Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
@@ -583,11 +583,16 @@
return 0;
}
-static void vsp1_dl_list_fill_header(struct vsp1_dl_list *dl, bool is_last)
+static void vsp1_dl_list_fill_header(struct vsp1_dl_list *dl, bool is_last,
+ unsigned int lif_index)
{
struct vsp1_dl_header_list *hdr = dl->header->lists;
struct vsp1_dl_body *dlb;
+ struct vsp1_device *vsp1 = dl->dlm->vsp1;
unsigned int num_lists = 0;
+ unsigned int init_bru_num, end_bru_num;
+ unsigned int init_brs_num, end_brs_num;
+ unsigned int i, rpf_update = 0;
/*
* Fill the header with the display list bodies addresses and sizes. The
@@ -609,6 +614,28 @@
dl->header->num_lists = num_lists;
+ if (vsp1_gen3_vspdl_check(vsp1)) {
+ if (!vsp1->brs || !vsp1->lif[1])
+ return;
+
+ init_bru_num = 0;
+ init_brs_num = vsp1->info->rpf_count - vsp1->num_brs_inputs;
+ end_bru_num = vsp1->info->rpf_count - vsp1->num_brs_inputs;
+ end_brs_num = vsp1->info->rpf_count;
+ } else {
+ init_bru_num = 0;
+ init_brs_num = 0;
+ end_bru_num = vsp1->info->rpf_count;
+ end_brs_num = 0;
+ }
+
+ if (lif_index == 1) {
+ for (i = init_brs_num; i < end_brs_num; ++i)
+ rpf_update |= (0x01 << (16 + i));
+ } else {
+ for (i = init_bru_num; i < end_bru_num; ++i)
+ rpf_update |= (0x01 << (16 + i));
+ }
/*
* If this display list's chain is not empty, we are on a list, where
* the next item in the list is the display list entity which should be
@@ -638,7 +665,7 @@
/* Set opecode */
dl->ext_body->ext_dl_cmd[0] = 0x00000003;
/* RPF[0]-[4] address is updated */
- dl->ext_body->ext_dl_cmd[1] = 0x001f0001;
+ dl->ext_body->ext_dl_cmd[1] = 0x00000001 | rpf_update;
/* Set pointer of source/destination address */
dl->ext_body->ext_dl_data[0] = dl->ext_addr_dma;
@@ -648,7 +675,7 @@
}
}
-void vsp1_dl_list_commit(struct vsp1_dl_list *dl)
+void vsp1_dl_list_commit(struct vsp1_dl_list *dl, unsigned int lif_index)
{
struct vsp1_dl_manager *dlm = dl->dlm;
struct vsp1_device *vsp1 = dlm->vsp1;
@@ -666,12 +693,13 @@
*/
/* Fill the header for the head and chained display lists. */
- vsp1_dl_list_fill_header(dl, list_empty(&dl->chain));
+ vsp1_dl_list_fill_header(dl, list_empty(&dl->chain),
+ lif_index);
list_for_each_entry(dl_child, &dl->chain, chain) {
bool last = list_is_last(&dl_child->chain, &dl->chain);
- vsp1_dl_list_fill_header(dl_child, last);
+ vsp1_dl_list_fill_header(dl_child, last, lif_index);
}
/*
@@ -802,8 +830,7 @@
void vsp1_dlm_setup(struct vsp1_device *vsp1, unsigned int lif_index)
{
u32 ctrl = (256 << VI6_DL_CTRL_AR_WAIT_SHIFT)
- | VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0
- | VI6_DL_CTRL_DLE;
+ | VI6_DL_CTRL_DLE(lif_index);
if ((vsp1->info->header_mode) && (vsp1->auto_fld_mode)) {
vsp1_write(vsp1, VI6_DL_EXT_CTRL(lif_index),
@@ -817,8 +844,9 @@
if ((vsp1->drm) && (!vsp1->info->header_mode))
ctrl |= VI6_DL_CTRL_CFM0 | VI6_DL_CTRL_NH0;
- vsp1_write(vsp1, VI6_DL_CTRL, ctrl);
- vsp1_write(vsp1, VI6_DL_SWAP(lif_index), VI6_DL_SWAP_LWS);
+ vsp1_write(vsp1, VI6_DL_CTRL, (vsp1_read(vsp1, VI6_DL_CTRL) | ctrl));
+ vsp1_write(vsp1, VI6_DL_SWAP(lif_index), VI6_DL_SWAP_LWS |
+ (lif_index == 1 ? VI6_DL_SWAP_IND : 0));
}
void vsp1_dlm_reset(struct vsp1_dl_manager *dlm)
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h
index 39c084a..9b38139 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.h
+++ b/drivers/media/platform/vsp1/vsp1_dl.h
@@ -1,7 +1,7 @@
/*
* vsp1_dl.h -- R-Car VSP1 Display List
*
- * Copyright (C) 2015-2016 Renesas Corporation
+ * Copyright (C) 2015-2017 Renesas Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
@@ -34,7 +34,7 @@
void vsp1_dl_set_addr_auto_fld(struct vsp1_dl_list *dl, struct vsp1_rwpf *rpf);
void vsp1_dl_list_put(struct vsp1_dl_list *dl);
void vsp1_dl_list_write(struct vsp1_dl_list *dl, u32 reg, u32 data);
-void vsp1_dl_list_commit(struct vsp1_dl_list *dl);
+void vsp1_dl_list_commit(struct vsp1_dl_list *dl, unsigned int lif_index);
struct vsp1_dl_body *vsp1_dl_fragment_alloc(struct vsp1_device *vsp1,
unsigned int num_entries);
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index 1d46636..f9e0ef8 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -1,7 +1,7 @@
/*
* vsp1_drm.c -- R-Car VSP1 DRM API
*
- * Copyright (C) 2015-2016 Renesas Electronics Corporation
+ * Copyright (C) 2015-2017 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
@@ -283,7 +283,7 @@
* as there's no plane configured yet, so we can't start processing
* buffers.
*/
- ret = vsp1_device_get(vsp1);
+ ret = vsp1_device_get(vsp1, lif_index);
if (ret < 0)
return ret;
@@ -310,7 +310,7 @@
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
struct vsp1_pipeline *pipe = &vsp1->drm->pipe[lif_index];
- vsp1->drm->num_inputs = pipe->num_inputs;
+ vsp1->drm->num_inputs[lif_index] = pipe->num_inputs;
/* Prepare the display list. */
pipe->dl = vsp1_dl_list_get(pipe->output->dlm);
@@ -604,13 +604,14 @@
continue;
}
- vsp1->bru->inputs[i].rpf = rpf;
if ((lif_index == 1) && (vsp1->brs)) {
vsp1->brs->inputs[i].rpf = rpf;
- rpf->brs_input = 2;
+ rpf->brs_input = i;
brs_use = true;
+ } else {
+ vsp1->bru->inputs[i].rpf = rpf;
+ rpf->bru_input = i;
}
- rpf->bru_input = i;
rpf->entity.sink_pad = i;
dev_dbg(vsp1->dev, "%s: connecting RPF.%u to %s:%u\n",
@@ -656,18 +657,18 @@
}
}
- vsp1_dl_list_commit(pipe->dl);
+ vsp1_dl_list_commit(pipe->dl, lif_index);
pipe->dl = NULL;
/* Start or stop the pipeline if needed. */
- if (!vsp1->drm->num_inputs && pipe->num_inputs) {
+ if (!vsp1->drm->num_inputs[lif_index] && pipe->num_inputs) {
vsp1_write(vsp1, VI6_DISP_IRQ_STA(lif_index), 0);
vsp1_write(vsp1, VI6_DISP_IRQ_ENB(lif_index),
VI6_DISP_IRQ_ENB_DSTE);
spin_lock_irqsave(&pipe->irqlock, flags);
vsp1_pipeline_run(pipe);
spin_unlock_irqrestore(&pipe->irqlock, flags);
- } else if (vsp1->drm->num_inputs && !pipe->num_inputs) {
+ } else if (vsp1->drm->num_inputs[lif_index] && !pipe->num_inputs) {
vsp1_write(vsp1, VI6_DISP_IRQ_ENB(lif_index), 0);
vsp1_pipeline_stop(pipe);
}
@@ -703,9 +704,15 @@
struct vsp1_pipeline *pipe = &vsp1->drm->pipe[lif_index];
struct vsp1_rwpf *wpf = pipe->output;
const struct vsp1_format_info *fmtinfo;
- struct vsp1_rwpf *rpf = pipe->inputs[0];
+ struct vsp1_rwpf *rpf;
unsigned long flags;
int i;
+ u32 rpf_num = 0;
+
+ if (pipe->brs)
+ rpf_num = vsp1->info->rpf_count - vsp1->num_brs_inputs;
+
+ rpf = pipe->inputs[rpf_num];
fmtinfo = vsp1_get_format_info(vsp1, pixelformat);
if (!fmtinfo) {
@@ -739,11 +746,10 @@
void vsp1_du_wait_wb(struct device *dev, u32 count, unsigned int lif_index)
{
- int ret;
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
struct vsp1_pipeline *pipe = &vsp1->drm->pipe[lif_index];
- ret = wait_event_interruptible(pipe->event_wait,
+ wait_event_interruptible(pipe->event_wait,
(pipe->output->write_back == count));
}
EXPORT_SYMBOL_GPL(vsp1_du_wait_wb);
diff --git a/drivers/media/platform/vsp1/vsp1_drm.h b/drivers/media/platform/vsp1/vsp1_drm.h
index 1bcee33..8ad4f44 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.h
+++ b/drivers/media/platform/vsp1/vsp1_drm.h
@@ -1,7 +1,7 @@
/*
* vsp1_drm.h -- R-Car VSP1 DRM/KMS Interface
*
- * Copyright (C) 2015-2016 Renesas Electronics Corporation
+ * Copyright (C) 2015-2017 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
@@ -26,7 +26,7 @@
*/
struct vsp1_drm {
struct vsp1_pipeline pipe[VSP1_MAX_LIF];
- unsigned int num_inputs;
+ unsigned int num_inputs[VSP1_MAX_LIF];
struct {
bool enabled;
struct v4l2_rect crop;
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index 4286d9f..8f04573 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -78,7 +78,6 @@
va_end(args);
}
-#define SRCR7_REG 0xe61501cc
#define FCPVD0_REG 0xfea27000
#define FCPVD1_REG 0xfea2f000
#define FCPVD2_REG 0xfea37000
@@ -679,17 +678,15 @@
return 0;
}
-static int vsp1_device_init(struct vsp1_device *vsp1)
+static int vsp1_device_init(struct vsp1_device *vsp1, unsigned int index)
{
unsigned int i;
int ret;
/* Reset any channel that might be running. */
- for (i = 0; i < vsp1->info->wpf_count; ++i) {
- ret = vsp1_reset_wpf(vsp1, i);
- if (ret < 0)
- return ret;
- }
+ ret = vsp1_reset_wpf(vsp1, index);
+ if (ret < 0)
+ return ret;
vsp1_write(vsp1, VI6_CLK_DCSWT, (8 << VI6_CLK_DCSWT_CSTPW_SHIFT) |
(8 << VI6_CLK_DCSWT_CSTRW_SHIFT));
@@ -713,12 +710,7 @@
vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, (7 << VI6_DPR_SMPPT_TGW_SHIFT) |
(VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT));
- for (i = 0; i < vsp1->info->wpf_count; ++i) {
- if ((i == 1) && (!vsp1_gen3_vspdl_check(vsp1)))
- break;
-
- vsp1_dlm_setup(vsp1, i);
- }
+ vsp1_dlm_setup(vsp1, index);
return 0;
}
@@ -730,7 +722,7 @@
*
* Return 0 on success or a negative error code otherwise.
*/
-int vsp1_device_get(struct vsp1_device *vsp1)
+int vsp1_device_get(struct vsp1_device *vsp1, unsigned int index)
{
int ret = 0;
@@ -743,7 +735,7 @@
return ret;
if (vsp1->info) {
- ret = vsp1_device_init(vsp1);
+ ret = vsp1_device_init(vsp1, index);
if (ret < 0)
return ret;
}
@@ -1007,10 +999,17 @@
static int vsp1_remove(struct platform_device *pdev)
{
struct vsp1_device *vsp1 = platform_get_drvdata(pdev);
+ u32 i, lif_num = 1;
- vsp1_device_put(vsp1);
+ if (vsp1_gen3_vspdl_check(vsp1))
+ lif_num = 2;
+
vsp1_destroy_entities(vsp1);
- rcar_fcp_put(vsp1->fcp);
+
+ for (i = 0; i < lif_num; i++) {
+ vsp1_device_put(vsp1);
+ rcar_fcp_put(vsp1->fcp);
+ }
pm_runtime_disable(&pdev->dev);
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index 69bcf7e..b442d14 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -1,7 +1,7 @@
/*
* vsp1_lif.c -- R-Car VSP1 LCD Controller Interface
*
- * Copyright (C) 2013-2016 Renesas Electronics Corporation
+ * Copyright (C) 2013-2017 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
@@ -134,8 +134,9 @@
{
const struct v4l2_mbus_framefmt *format;
struct vsp1_lif *lif = to_lif(&entity->subdev);
+ struct vsp1_device *vsp1 = entity->vsp1;
unsigned int hbth = 0;
- unsigned int obth = 3000;
+ unsigned int obth;
unsigned int lbth = 0;
if (params != VSP1_ENTITY_PARAMS_INIT)
@@ -144,7 +145,10 @@
format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config,
LIF_PAD_SOURCE);
- obth = min(obth, (format->width + 1) / 2 * format->height - 4);
+ if (vsp1_gen3_vspdl_check(vsp1))
+ obth = 1500;
+ else
+ obth = 3000;
vsp1_lif_write(lif, dl, VI6_LIF_CSBTH(lif->entity.index),
(hbth << VI6_LIF_CSBTH_HBTH_SHIFT) |
diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h
index 7dcbd63..ec7e107 100644
--- a/drivers/media/platform/vsp1/vsp1_regs.h
+++ b/drivers/media/platform/vsp1/vsp1_regs.h
@@ -1,7 +1,7 @@
/*
* vsp1_regs.h -- R-Car VSP1 Registers Definitions
*
- * Copyright (C) 2013-2016 Renesas Electronics Corporation
+ * Copyright (C) 2013-2017 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
@@ -86,16 +86,14 @@
#define VI6_DL_CTRL 0x0100
#define VI6_DL_CTRL_AR_WAIT_MASK (0xffff << 16)
#define VI6_DL_CTRL_AR_WAIT_SHIFT 16
-#define VI6_DL_CTRL_DC2 (1 << 12)
-#define VI6_DL_CTRL_DC1 (1 << 8)
-#define VI6_DL_CTRL_DC0 (1 << 4)
#define VI6_DL_CTRL_CFM0 (1 << 2)
#define VI6_DL_CTRL_NH0 (1 << 1)
-#define VI6_DL_CTRL_DLE (1 << 0)
+#define VI6_DL_CTRL_DLE(n) (1 << (4 * n))
#define VI6_DL_HDR_ADDR(n) (0x0104 + (n) * 4)
#define VI6_DL_SWAP(n) (0x0114 + (n) * 56)
+#define VI6_DL_SWAP_IND (1 << 31)
#define VI6_DL_SWAP_LWS (1 << 2)
#define VI6_DL_SWAP_WDS (1 << 1)
#define VI6_DL_SWAP_BTS (1 << 0)
@@ -264,6 +262,10 @@
#define VI6_WPF_SRCRPF_VIRACT_SUB (1 << 28)
#define VI6_WPF_SRCRPF_VIRACT_MST (2 << 28)
#define VI6_WPF_SRCRPF_VIRACT_MASK (3 << 28)
+#define VI6_WPF_SRCRPF_VIRACT2_DIS (0 << 24)
+#define VI6_WPF_SRCRPF_VIRACT2_SUB (1 << 24)
+#define VI6_WPF_SRCRPF_VIRACT2_MST (2 << 24)
+#define VI6_WPF_SRCRPF_VIRACT2_MASK (3 << 24)
#define VI6_WPF_SRCRPF_RPF_ACT_DIS(n) (0 << ((n) * 2))
#define VI6_WPF_SRCRPF_RPF_ACT_SUB(n) (1 << ((n) * 2))
#define VI6_WPF_SRCRPF_RPF_ACT_MST(n) (2 << ((n) * 2))
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index a12d6f9..483dc91 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -1,7 +1,7 @@
/*
* vsp1_rpf.c -- R-Car VSP1 Read Pixel Formatter
*
- * Copyright (C) 2013-2016 Renesas Electronics Corporation
+ * Copyright (C) 2013-2017 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
@@ -64,9 +64,25 @@
u32 alph_sel = 0;
u32 i;
u32 crop_width, crop_height, crop_x, crop_y;
+ unsigned int sta_rpf = 0, end_rpf = 0;
+
+ if (vsp1_gen3_vspdl_check(vsp1)) {
+ if (pipe->brs) {
+ sta_rpf = vsp1->info->rpf_count -
+ vsp1->num_brs_inputs;
+ end_rpf = vsp1->info->rpf_count;
+ } else if (pipe->bru) {
+ sta_rpf = 0;
+ end_rpf = vsp1->info->rpf_count -
+ vsp1->num_brs_inputs;
+ }
+ } else {
+ sta_rpf = 0;
+ end_rpf = vsp1->info->rpf_count;
+ }
if (pipe->vmute_flag) {
- for (i = 0; i < vsp1->info->rpf_count; ++i)
+ for (i = sta_rpf; i < end_rpf; ++i)
vsp1_rpf_write(rpf, dl, VI6_DPR_RPF_ROUTE(i),
VI6_DPR_NODE_UNUSED);
return;
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index f4ada40..ecca021 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -1,7 +1,7 @@
/*
* vsp1_video.c -- R-Car VSP1 Video Node
*
- * Copyright (C) 2013-2016 Renesas Electronics Corporation
+ * Copyright (C) 2013-2017 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
@@ -413,7 +413,7 @@
}
/* Complete, and commit the head display list. */
- vsp1_dl_list_commit(pipe->dl);
+ vsp1_dl_list_commit(pipe->dl, 0);
pipe->dl = NULL;
vsp1_pipeline_run(pipe);
@@ -1216,7 +1216,7 @@
file->private_data = vfh;
- ret = vsp1_device_get(video->vsp1);
+ ret = vsp1_device_get(video->vsp1, 0);
if (ret < 0) {
v4l2_fh_del(vfh);
kfree(vfh);
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index d41eed9..f490ae4 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -1,7 +1,7 @@
/*
* vsp1_wpf.c -- R-Car VSP1 Write Pixel Formatter
*
- * Copyright (C) 2013-2016 Renesas Electronics Corporation
+ * Copyright (C) 2013-2017 Renesas Electronics Corporation
*
* Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*
@@ -189,16 +189,16 @@
bool writeback = pipe->lif && wpf->mem.addr[0];
if (pipe->vmute_flag) {
- vsp1_wpf_write(wpf, dl, VI6_WPF_SRCRPF +
- (0x100 * wpf->entity.index),
- VI6_WPF_SRCRPF_VIRACT_MST);
- vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP +
- (0x100 * wpf->entity.index), 0);
- vsp1_wpf_write(wpf, dl, VI6_WPF_VSZCLIP +
- (0x100 * wpf->entity.index), 0);
- vsp1_wpf_write(wpf, dl, VI6_DPR_WPF_FPORCH(wpf->entity.index),
- VI6_DPR_WPF_FPORCH_FP_WPFN);
-
+ if (pipe->bru)
+ vsp1_wpf_write(wpf, dl, VI6_WPF_SRCRPF,
+ VI6_WPF_SRCRPF_VIRACT_MST);
+ else if (pipe->brs)
+ vsp1_wpf_write(wpf, dl, VI6_WPF_SRCRPF,
+ VI6_WPF_SRCRPF_VIRACT2_MST);
+ vsp1_wpf_write(wpf, dl, VI6_WPF_HSZCLIP, 0);
+ vsp1_wpf_write(wpf, dl, VI6_WPF_VSZCLIP, 0);
+ vsp1_dl_list_write(dl, VI6_DPR_WPF_FPORCH(wpf->entity.index),
+ VI6_DPR_WPF_FPORCH_FP_WPFN);
return;
}
@@ -386,12 +386,29 @@
if (pipe->bru || pipe->num_inputs > 1)
srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST;
+ /* When using multiple BRS module, layer is allocated as follows.
+ * When one BRS is used, RPF4 is master layer.
+ * When two BRS is used, RPF3 is master layer and RPF4 is sub layer.
+ */
+ if (pipe->brs) {
+ if (vsp1->num_brs_inputs == 1)
+ srcrpf = VI6_WPF_SRCRPF_VIRACT2_MST |
+ VI6_WPF_SRCRPF_RPF_ACT_MST(4);
+ else if (pipe->num_inputs > 1)
+ srcrpf = VI6_WPF_SRCRPF_VIRACT2_MST |
+ VI6_WPF_SRCRPF_RPF_ACT_MST(3) |
+ VI6_WPF_SRCRPF_RPF_ACT_SUB(4);
+ else if (pipe->num_inputs == 1)
+ srcrpf = VI6_WPF_SRCRPF_VIRACT2_MST |
+ VI6_WPF_SRCRPF_RPF_ACT_MST(3);
+ }
+
vsp1_wpf_write(wpf, dl, VI6_WPF_SRCRPF, srcrpf);
/* Enable interrupts */
vsp1_dl_list_write(dl, VI6_WPF_IRQ_STA(wpf->entity.index), 0);
vsp1_dl_list_write(dl, VI6_WPF_IRQ_ENB(wpf->entity.index),
- VI6_WFP_IRQ_ENB_FREE | VI6_WFP_IRQ_ENB_UNDE);
+ VI6_WFP_IRQ_ENB_DFEE | VI6_WFP_IRQ_ENB_UNDE);
}
static const struct vsp1_entity_operations wpf_entity_ops = {
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 643ce2f..83aabfe 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -1,8 +1,8 @@
/*
* SuperH Mobile SDHI
*
- * Copyright (C) 2016 Renesas Electronics Corporation
* Copyright (C) 2016 Sang Engineering, Wolfram Sang
+ * Copyright (C) 2015-2017 Renesas Electronics Corporation
* Copyright (C) 2009 Magnus Damm
*
* This program is free software; you can redistribute it and/or modify
@@ -110,8 +110,7 @@
static const struct sh_mobile_sdhi_of_data of_rcar_gen3_compatible = {
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
- TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2 |
- TMIO_MMC_CLK_NO_SLEEP,
+ TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
MMC_CAP_CMD23,
.bus_shift = 2,
@@ -349,33 +348,30 @@
priv = host_to_priv(host);
- /* set sampling clock selection range */
- sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL,
- 0x8 << SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT);
-
/* Initialize SCC */
sd_ctrl_write32_as_16_and_16(host, CTL_STATUS, 0x0);
- sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL,
- SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN |
- sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL));
-
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+ /* set sampling clock selection range */
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL,
+ SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN |
+ 0x8 << SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT);
+
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL,
SH_MOBILE_SDHI_SCC_CKSEL_DTSEL |
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL));
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
-
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, host->scc_tappos);
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
/* Read TAPNUM */
return (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL) >>
SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) &
@@ -416,17 +412,46 @@
SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) |
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2));
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, host->tap_set/2);
+
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
}
+static void sh_mobile_sdhi_reset_hs400_mode(struct mmc_host *mmc)
+{
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+ struct sh_mobile_sdhi *priv = host_to_priv(host);
+
+ if (!(host->mmc->caps2 & MMC_CAP2_HS200_1_8V_SDR) &&
+ !(host->mmc->caps2 & (MMC_CAP2_HS400_1_8V |
+ MMC_CAP2_HS200_1_8V_SDR)))
+ return;
+
+ if (!priv->scc_ctl)
+ return;
+
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+ /* Reset HS400 mode */
+ sd_ctrl_write16(host, CTL_SDIF_MODE, ~0x0001 &
+ sd_ctrl_read16(host, CTL_SDIF_MODE));
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2,
+ ~(SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN |
+ SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) &
+ sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2));
+
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+}
+
#define SH_MOBILE_SDHI_MAX_TAP 3
static int sh_mobile_sdhi_select_tuning(struct tmio_mmc_host *host)
{
struct sh_mobile_sdhi *priv = host_to_priv(host);
unsigned long tap_cnt; /* counter of tuning success */
- unsigned long tap_set; /* tap position */
unsigned long tap_start;/* start position of tuning success */
unsigned long tap_end; /* end position of tuning success */
unsigned long ntap; /* temporary counter of tuning success */
@@ -511,12 +536,12 @@
select = true;
if (select)
- tap_set = (tap_start + tap_end) / 2 % host->tap_num;
+ host->tap_set = (tap_start + tap_end) / 2 % host->tap_num;
else
return -EIO;
/* Set SCC */
- sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, tap_set);
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, host->tap_set);
/* Enable auto re-tuning */
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
@@ -733,6 +758,7 @@
host->hw_reset = sh_mobile_sdhi_hw_reset;
host->prepare_hs400_tuning =
sh_mobile_sdhi_prepare_hs400_tuning;
+ host->reset_hs400_mode = sh_mobile_sdhi_reset_hs400_mode;
}
/* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */
@@ -850,13 +876,11 @@
}
static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
tmio_mmc_host_runtime_resume,
NULL)
-#ifdef CONFIG_PM_SLEEP
- .suspend_late = tmio_mmc_host_suspend,
- .resume_early = tmio_mmc_host_resume,
-#endif
};
static struct platform_driver sh_mobile_sdhi_driver = {
diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
index 17ac517..e897e7f 100644
--- a/drivers/mmc/host/tmio_mmc.c
+++ b/drivers/mmc/host/tmio_mmc.c
@@ -30,7 +30,7 @@
const struct mfd_cell *cell = mfd_get_cell(pdev);
int ret;
- ret = tmio_mmc_host_suspend(dev);
+ ret = pm_runtime_force_suspend(dev);
/* Tell MFD core it can disable us now.*/
if (!ret && cell->disable)
@@ -50,7 +50,7 @@
ret = cell->resume(pdev);
if (!ret)
- ret = tmio_mmc_host_resume(dev);
+ ret = pm_runtime_force_resume(dev);
return ret;
}
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 4c37076..a707292 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -2,7 +2,7 @@
* linux/drivers/mmc/host/tmio_mmc.h
*
* Copyright (C) 2016 Sang Engineering, Wolfram Sang
- * Copyright (C) 2015-16 Renesas Electronics Corporation
+ * Copyright (C) 2015-2017 Renesas Electronics Corporation
* Copyright (C) 2007 Ian Molton
* Copyright (C) 2004 Ian Molton
*
@@ -101,6 +101,9 @@
TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT)
#define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD)
+#define TMIO_TRANSTATE_DEND 0x00000001
+#define TMIO_TRANSTATE_AEND 0x00000002
+
struct tmio_mmc_data;
struct tmio_mmc_host;
@@ -141,6 +144,7 @@
struct tasklet_struct dma_issue;
struct scatterlist bounce_sg;
u8 *bounce_buf;
+ u32 dma_tranend1;
/* Track lost interrupts */
struct delayed_work delayed_reset_work;
@@ -149,6 +153,7 @@
/* Cache */
u32 sdcard_irq_mask;
u32 sdio_irq_mask;
+ u32 dma_irq_mask;
unsigned int clk_cache;
spinlock_t lock; /* protect host private data */
@@ -159,6 +164,9 @@
u32 scc_tappos;
struct completion completion;
+ spinlock_t trans_lock;
+ unsigned int trans_state;
+
/* Mandatory callback */
int (*clk_enable)(struct tmio_mmc_host *host);
@@ -184,7 +192,9 @@
/* Tuning values: 1 for success, 0 for failure */
DECLARE_BITMAP(taps, BITS_PER_BYTE * sizeof(long));
unsigned int tap_num;
+ unsigned long tap_set;
void (*prepare_hs400_tuning)(struct mmc_host *mmc, struct mmc_ios *ios);
+ void (*reset_hs400_mode)(struct mmc_host *mmc);
/* Sampling data comparison: 1 for match. 0 for mismatch */
DECLARE_BITMAP(smpcmp, BITS_PER_BYTE * sizeof(long));
@@ -198,6 +208,9 @@
void tmio_mmc_host_remove(struct tmio_mmc_host *host);
void tmio_mmc_do_data_irq(struct tmio_mmc_host *host);
+void tmio_set_transtate(struct tmio_mmc_host *host, unsigned int state);
+void tmio_clear_transtate(struct tmio_mmc_host *host);
+
void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
irqreturn_t tmio_mmc_irq(int irq, void *devid);
@@ -248,16 +261,21 @@
}
#endif
+#if (defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)) \
+ && defined(CONFIG_ARM64)
+bool __tmio_mmc_dma_irq(struct tmio_mmc_host *host);
+#else
+static inline bool __tmio_mmc_dma_irq(struct tmio_mmc_host *host)
+{
+ return false;
+}
+#endif
+
#ifdef CONFIG_PM
int tmio_mmc_host_runtime_suspend(struct device *dev);
int tmio_mmc_host_runtime_resume(struct device *dev);
#endif
-#ifdef CONFIG_PM_SLEEP
-int tmio_mmc_host_suspend(struct device *dev);
-int tmio_mmc_host_resume(struct device *dev);
-#endif
-
static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr)
{
return readw(host->ctl + (addr << host->bus_shift));
diff --git a/drivers/mmc/host/tmio_mmc_dma_gen3.c b/drivers/mmc/host/tmio_mmc_dma_gen3.c
index b289dfa..0af3d3c 100644
--- a/drivers/mmc/host/tmio_mmc_dma_gen3.c
+++ b/drivers/mmc/host/tmio_mmc_dma_gen3.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/mmc/tmio_mmc_dma_gen3.c
*
- * Copyright (C) 2015 Renesas Electronics Corporation
+ * Copyright (C) 2015-2017 Renesas Electronics Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,6 +18,7 @@
#include <linux/mmc/host.h>
#include <linux/pagemap.h>
#include <linux/scatterlist.h>
+#include <linux/sys_soc.h>
#include "tmio_mmc.h"
@@ -46,13 +47,24 @@
/* DM_CM_INFO1 and DM_CM_INFO1_MASK */
#define INFO1_CLEAR 0
-#define INFO1_DTRANEND1 BIT(17)
+#define INFO1_DTRANEND1_BIT20 BIT(20)
+#define INFO1_DTRANEND1_BIT17 BIT(17)
#define INFO1_DTRANEND0 BIT(16)
/* DM_CM_INFO2 and DM_CM_INFO2_MASK */
#define INFO2_DTRANERR1 BIT(17)
#define INFO2_DTRANERR0 BIT(16)
+static const struct soc_device_attribute r8a7795es1x[] = {
+ { .soc_id = "r8a7795", .revision = "ES1.*" },
+ { },
+};
+
+static const struct soc_device_attribute r8a7796es10[] = {
+ { .soc_id = "r8a7796", .revision = "ES1.0" },
+ { },
+};
+
/*
* Specification of this driver:
* - host->chan_{rx,tx} will be used as a flag of enabling/disabling the dma
@@ -65,6 +77,11 @@
writeq(val, host->ctl + addr);
}
+static u32 tmio_dm_read(struct tmio_mmc_host *host, int addr)
+{
+ return readl(host->ctl + addr);
+}
+
void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
{
if (!host->chan_tx || !host->chan_rx)
@@ -73,8 +90,11 @@
if (!enable)
tmio_dm_write(host, DM_CM_INFO1, INFO1_CLEAR);
- if (host->dma->enable)
+ if (host->dma->enable) {
+ host->dma_irq_mask = ~(host->dma_tranend1 | INFO1_DTRANEND0);
host->dma->enable(host, enable);
+ tmio_dm_write(host, DM_CM_INFO1_MASK, host->dma_irq_mask);
+ }
}
void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
@@ -131,6 +151,7 @@
return;
}
+ tmio_clear_transtate(host);
tmio_mmc_enable_dma(host, true);
/* disable PIO irqs to avoid "PIO IRQ in DMA mode!" */
@@ -175,6 +196,27 @@
}
#endif
+bool __tmio_mmc_dma_irq(struct tmio_mmc_host *host)
+{
+ unsigned int ireg, status;
+
+ status = tmio_dm_read(host, DM_CM_INFO1);
+ ireg = status & ~host->dma_irq_mask;
+
+ if (ireg & INFO1_DTRANEND0) {
+ tmio_dm_write(host, DM_CM_INFO1, ireg & ~INFO1_DTRANEND0);
+ tmio_set_transtate(host, TMIO_TRANSTATE_DEND);
+ return true;
+ }
+
+ if (ireg & host->dma_tranend1) {
+ tmio_dm_write(host, DM_CM_INFO1, ireg & ~host->dma_tranend1);
+ tmio_set_transtate(host, TMIO_TRANSTATE_DEND);
+ return true;
+ }
+ return false;
+}
+
void tmio_mmc_request_dma(struct tmio_mmc_host *host,
struct tmio_mmc_data *pdata)
{
@@ -182,6 +224,11 @@
/* Each value is set to non-zero to assume "enabling" each DMA */
host->chan_rx = host->chan_tx = (void *)0xdeadbeaf;
+ if (soc_device_match(r8a7795es1x) || soc_device_match(r8a7796es10))
+ host->dma_tranend1 = INFO1_DTRANEND1_BIT17;
+ else /* ES 2.0 */
+ host->dma_tranend1 = INFO1_DTRANEND1_BIT20;
+
tasklet_init(&host->dma_complete, tmio_mmc_complete_tasklet_fn,
(unsigned long)host);
tasklet_init(&host->dma_issue, tmio_mmc_issue_tasklet_fn,
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index ec14cd9..4b99701 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -1,8 +1,8 @@
/*
* linux/drivers/mmc/host/tmio_mmc_pio.c
*
- * Copyright (C) 2016 Renesas Electronics Corporation
* Copyright (C) 2016 Sang Engineering, Wolfram Sang
+ * Copyright (C) 2015-2017 Renesas Electronics Corporation
* Copyright (C) 2011 Guennadi Liakhovetski
* Copyright (C) 2007 Ian Molton
* Copyright (C) 2004 Ian Molton
@@ -65,6 +65,32 @@
sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, host->sdcard_irq_mask);
}
+void tmio_set_transtate(struct tmio_mmc_host *host, unsigned int state)
+{
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&host->trans_lock, flags);
+ host->trans_state |= state;
+
+ if (host->trans_state == (TMIO_TRANSTATE_DEND | TMIO_TRANSTATE_AEND)) {
+ spin_unlock_irqrestore(&host->trans_lock, flags);
+ tasklet_schedule(&host->dma_complete);
+ } else {
+ spin_unlock_irqrestore(&host->trans_lock, flags);
+ }
+}
+
+void tmio_clear_transtate(struct tmio_mmc_host *host)
+{
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&host->trans_lock, flags);
+
+ host->trans_state = 0;
+
+ spin_unlock_irqrestore(&host->trans_lock, flags);
+}
+
static void tmio_mmc_ack_mmc_irqs(struct tmio_mmc_host *host, u32 i)
{
sd_ctrl_write32_as_16_and_16(host, CTL_STATUS, ~i);
@@ -161,9 +187,8 @@
msleep(host->pdata->flags & TMIO_MMC_MIN_RCAR2 ? 1 : 10);
if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) {
- sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, CLK_CTL_SCLKEN);
- if (!(host->pdata->flags & TMIO_MMC_CLK_NO_SLEEP))
- msleep(10);
+ sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100);
+ msleep(10);
}
}
@@ -171,8 +196,7 @@
{
if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) {
sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000);
- if (!(host->pdata->flags & TMIO_MMC_CLK_NO_SLEEP))
- msleep(10);
+ msleep(10);
}
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
@@ -189,6 +213,13 @@
tmio_mmc_clk_stop(host);
return;
}
+ /*
+ * Both HS400 and HS200/SD104 set 200MHz, but HS400 sets 400MHz
+ * to distinguish the CPG settings.
+ */
+ if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400 &&
+ new_clock == 200000000)
+ new_clock = 400000000;
if (host->clk_update)
clock = host->clk_update(host, new_clock) / 512;
@@ -562,6 +593,17 @@
if (!data)
goto out;
+ /* The response of automatic CMD12 is stored */
+ if (host->pdata->flags & TMIO_MMC_MIN_RCAR2) {
+ if ((sd_ctrl_read16(host, CTL_SD_CMD) &
+ (TRANSFER_MULTI | NO_CMD12_ISSUE)) == TRANSFER_MULTI) {
+ if (data->stop) {
+ data->stop->resp[0] =
+ sd_ctrl_read16_and_16_as_32(host,
+ CTL_RESPONSE);
+ }
+ }
+ }
if (stat & TMIO_STAT_CRCFAIL || stat & TMIO_STAT_STOPBIT_ERR ||
stat & TMIO_STAT_TXUNDERRUN)
data->error = -EILSEQ;
@@ -587,11 +629,17 @@
if (done) {
tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND);
- tasklet_schedule(&host->dma_complete);
+ if (!data->error)
+ tmio_set_transtate(host, TMIO_TRANSTATE_AEND);
+ else
+ tasklet_schedule(&host->dma_complete);
}
} else if (host->chan_rx && (data->flags & MMC_DATA_READ) && !host->force_pio) {
tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND);
- tasklet_schedule(&host->dma_complete);
+ if (!data->error)
+ tmio_set_transtate(host, TMIO_TRANSTATE_AEND);
+ else
+ tasklet_schedule(&host->dma_complete);
} else {
tmio_mmc_do_data_irq(host);
tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_READOP | TMIO_MASK_WRITEOP);
@@ -641,7 +689,7 @@
* we will ultimatley finish the request in the data_end handler.
* If theres no data or we encountered an error, finish now.
*/
- if (host->data && (!cmd->error || cmd->error == -EILSEQ)) {
+ if (host->data && !cmd->error) {
if (host->data->flags & MMC_DATA_READ) {
if (host->force_pio || !host->chan_rx)
tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_READOP);
@@ -751,6 +799,8 @@
return IRQ_HANDLED;
if (__tmio_mmc_sdcard_irq(host, ireg, status))
return IRQ_HANDLED;
+ if (__tmio_mmc_dma_irq(host))
+ return IRQ_HANDLED;
tmio_mmc_sdio_irq(irq, devid);
@@ -1009,10 +1059,10 @@
struct device *dev = &host->pdev->dev;
unsigned long flags;
- /* HS400 Register setting */
- if (ios->timing == MMC_TIMING_MMC_HS400)
- if (host->prepare_hs400_tuning)
- host->prepare_hs400_tuning(mmc, ios);
+ /* reset HS400 mode */
+ if (!(ios->timing == MMC_TIMING_MMC_HS400))
+ if (host->reset_hs400_mode)
+ host->reset_hs400_mode(mmc);
mutex_lock(&host->ios_lock);
@@ -1063,6 +1113,12 @@
"%s.%d: IOS interrupted: clk %u, mode %u",
current->comm, task_pid_nr(current),
ios->clock, ios->power_mode);
+
+ /* HS400 Register setting */
+ if (ios->timing == MMC_TIMING_MMC_HS400)
+ if (host->prepare_hs400_tuning)
+ host->prepare_hs400_tuning(mmc, ios);
+
host->mrq = NULL;
host->clk_cache = ios->clock;
@@ -1275,6 +1331,9 @@
spin_lock_init(&_host->lock);
mutex_init(&_host->ios_lock);
+ spin_lock_init(&_host->trans_lock);
+ _host->trans_state = 0;
+
/* Init delayed work for request timeouts */
INIT_DELAYED_WORK(&_host->delayed_reset_work, tmio_mmc_reset_work);
INIT_WORK(&_host->done, tmio_mmc_done_work);
@@ -1376,23 +1435,4 @@
EXPORT_SYMBOL(tmio_mmc_host_runtime_resume);
#endif
-#ifdef CONFIG_PM_SLEEP
-int tmio_mmc_host_suspend(struct device *dev)
-{
- struct mmc_host *mmc = dev_get_drvdata(dev);
-
- tmio_mmc_hw_reset(mmc);
-
- return 0;
-}
-EXPORT_SYMBOL(tmio_mmc_host_suspend);
-
-int tmio_mmc_host_resume(struct device *dev)
-{
- /* Empty for now */
- return 0;
-}
-EXPORT_SYMBOL(tmio_mmc_host_resume);
-#endif /* CONFIG_PM_SLEEP */
-
MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h
index 9a8dd874..7d35379 100644
--- a/drivers/net/ethernet/renesas/ravb.h
+++ b/drivers/net/ethernet/renesas/ravb.h
@@ -1,6 +1,6 @@
/* Renesas Ethernet AVB device driver
*
- * Copyright (C) 2014-2015 Renesas Electronics Corporation
+ * Copyright (C) 2014-2017 Renesas Electronics Corporation
* Copyright (C) 2015 Renesas Solutions Corp.
* Copyright (C) 2015-2016 Cogent Embedded, Inc. <source@cogentembedded.com>
*
@@ -1140,7 +1140,7 @@
u32 set);
int ravb_wait(struct net_device *ndev, enum ravb_reg reg, u32 mask, u32 value);
-void ravb_ptp_interrupt(struct net_device *ndev);
+irqreturn_t ravb_ptp_interrupt(struct net_device *ndev);
void ravb_ptp_init(struct net_device *ndev, struct platform_device *pdev);
void ravb_ptp_stop(struct net_device *ndev);
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 7150f0b..3177789 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -1,6 +1,6 @@
/* Renesas Ethernet AVB device driver
*
- * Copyright (C) 2014-2015 Renesas Electronics Corporation
+ * Copyright (C) 2014-2017 Renesas Electronics Corporation
* Copyright (C) 2015 Renesas Solutions Corp.
* Copyright (C) 2015-2016 Cogent Embedded, Inc. <source@cogentembedded.com>
*
@@ -841,10 +841,8 @@
}
/* gPTP interrupt status summary */
- if (iss & ISS_CGIS) {
- ravb_ptp_interrupt(ndev);
- result = IRQ_HANDLED;
- }
+ if (iss & ISS_CGIS)
+ result = ravb_ptp_interrupt(ndev);
mmiowb();
spin_unlock(&priv->lock);
@@ -874,10 +872,8 @@
}
/* gPTP interrupt status summary */
- if (iss & ISS_CGIS) {
- ravb_ptp_interrupt(ndev);
- result = IRQ_HANDLED;
- }
+ if (iss & ISS_CGIS)
+ result = ravb_ptp_interrupt(ndev);
mmiowb();
spin_unlock(&priv->lock);
@@ -1379,8 +1375,8 @@
};
static inline int ravb_hook_irq(unsigned int irq, irq_handler_t handler,
- struct net_device *ndev, struct device *dev,
- const char *ch)
+ unsigned long flags, struct net_device *ndev,
+ struct device *dev, const char *ch)
{
char *name;
int error;
@@ -1388,7 +1384,7 @@
name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s", ndev->name, ch);
if (!name)
return -ENOMEM;
- error = request_irq(irq, handler, 0, name, ndev);
+ error = request_irq(irq, handler, flags, name, ndev);
if (error)
netdev_err(ndev, "cannot request IRQ %s\n", name);
@@ -1414,28 +1410,28 @@
goto out_napi_off;
}
} else {
- error = ravb_hook_irq(ndev->irq, ravb_multi_interrupt, ndev,
- dev, "ch22:multi");
+ error = ravb_hook_irq(ndev->irq, ravb_multi_interrupt,
+ IRQF_SHARED, ndev, dev, "ch22:multi");
if (error)
goto out_napi_off;
- error = ravb_hook_irq(priv->emac_irq, ravb_emac_interrupt, ndev,
- dev, "ch24:emac");
+ error = ravb_hook_irq(priv->emac_irq, ravb_emac_interrupt,
+ 0, ndev, dev, "ch24:emac");
if (error)
goto out_free_irq;
error = ravb_hook_irq(priv->rx_irqs[RAVB_BE], ravb_be_interrupt,
- ndev, dev, "ch0:rx_be");
+ 0, ndev, dev, "ch0:rx_be");
if (error)
goto out_free_irq_emac;
error = ravb_hook_irq(priv->tx_irqs[RAVB_BE], ravb_be_interrupt,
- ndev, dev, "ch18:tx_be");
+ 0, ndev, dev, "ch18:tx_be");
if (error)
goto out_free_irq_be_rx;
error = ravb_hook_irq(priv->rx_irqs[RAVB_NC], ravb_nc_interrupt,
- ndev, dev, "ch1:rx_nc");
+ 0, ndev, dev, "ch1:rx_nc");
if (error)
goto out_free_irq_be_tx;
error = ravb_hook_irq(priv->tx_irqs[RAVB_NC], ravb_nc_interrupt,
- ndev, dev, "ch19:tx_nc");
+ 0, ndev, dev, "ch19:tx_nc");
if (error)
goto out_free_irq_nc_rx;
}
diff --git a/drivers/net/ethernet/renesas/ravb_ptp.c b/drivers/net/ethernet/renesas/ravb_ptp.c
index eede70e..eef70f1 100644
--- a/drivers/net/ethernet/renesas/ravb_ptp.c
+++ b/drivers/net/ethernet/renesas/ravb_ptp.c
@@ -1,6 +1,6 @@
/* PTP 1588 clock using the Renesas Ethernet AVB
*
- * Copyright (C) 2013-2015 Renesas Electronics Corporation
+ * Copyright (C) 2013-2017 Renesas Electronics Corporation
* Copyright (C) 2015 Renesas Solutions Corp.
* Copyright (C) 2015-2016 Cogent Embedded, Inc. <source@cogentembedded.com>
*
@@ -296,10 +296,11 @@
};
/* Caller must hold the lock */
-void ravb_ptp_interrupt(struct net_device *ndev)
+irqreturn_t ravb_ptp_interrupt(struct net_device *ndev)
{
struct ravb_private *priv = netdev_priv(ndev);
u32 gis = ravb_read(ndev, GIS);
+ irqreturn_t result = IRQ_NONE;
gis &= ravb_read(ndev, GIC);
if (gis & GIS_PTCF) {
@@ -309,6 +310,9 @@
event.index = 0;
event.timestamp = ravb_read(ndev, GCPT);
ptp_clock_event(priv->ptp.clock, &event);
+
+ result = IRQ_HANDLED;
+ gis &= ~GIS_PTCF;
}
if (gis & GIS_PTMF) {
struct ravb_ptp_perout *perout = priv->ptp.perout;
@@ -317,9 +321,14 @@
perout->target += perout->period;
ravb_ptp_update_compare(priv, perout->target);
}
+
+ result = IRQ_HANDLED;
+ gis &= ~GIS_PTCF;
}
- ravb_write(ndev, ~gis, GIS);
+ ravb_write(ndev, gis, GIS);
+
+ return result;
}
void ravb_ptp_init(struct net_device *ndev, struct platform_device *pdev)
diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
index 5751444..8e24d5f 100644
--- a/drivers/pci/host/pcie-rcar.c
+++ b/drivers/pci/host/pcie-rcar.c
@@ -30,7 +30,6 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
-#include <linux/soc/renesas/s2ram_ddr_backup.h>
#define PCIECAR 0x000010
#define PCIECCTLR 0x000018
@@ -148,7 +147,6 @@
return container_of(chip, struct rcar_msi, chip);
}
-
/* Structure representing the PCIe interface */
struct rcar_pcie {
struct device *dev;
@@ -162,144 +160,6 @@
static int rcar_pcie_wait_for_dl(struct rcar_pcie *pcie);
-#ifdef CONFIG_RCAR_DDR_BACKUP
-
-#define PCIE_BACKUP_REGS(pcie_ip_regs) \
-struct hw_register (pcie_ip_regs)[] = { \
-/* PCIEC transfer control registers */ \
- {"PCIETCTLR", 0x2000, 32, 0}, \
- {"PCIEINTER", 0x200C, 32, 0}, \
- {"PCIEERRFER", 0x2024, 32, 0}, \
- {"PCIETIER", 0x2030, 32, 0}, \
- {"PCIEPMSCIER", 0x2038, 32, 0}, \
- {"PCIEMSIALR", 0x2048, 32, 0}, \
- {"PCIEMSIAUR", 0x204C, 32, 0}, \
- {"PCIEMSIIER", 0x2050, 32, 0}, \
- {"PCIEPRAR0", 0x2080, 32, 0}, \
- {"PCIEPRAR1", 0x2084, 32, 0}, \
- {"PCIEPRAR2", 0x2088, 32, 0}, \
- {"PCIEPRAR3", 0x208C, 32, 0}, \
- {"PCIEPRAR4", 0x2090, 32, 0}, \
- {"PCIEPRAR5", 0x2094, 32, 0}, \
- \
- /* Local address registers */ \
- {"PCIELAR0", 0x2200, 32, 0}, \
- {"PCIELAMR0", 0x2208, 32, 0}, \
- {"PCIELAR1", 0x2220, 32, 0}, \
- {"PCIELAMR1", 0x2228, 32, 0}, \
- {"PCIELAR2", 0x2240, 32, 0}, \
- {"PCIELAMR2", 0x2248, 32, 0}, \
- {"PCIELAR3", 0x2260, 32, 0}, \
- {"PCIELAMR3", 0x2268, 32, 0}, \
- {"PCIELAR4", 0x2280, 32, 0}, \
- {"PCIELAMR4", 0x2288, 32, 0}, \
- {"PCIELAR5", 0x22A0, 32, 0}, \
- {"PCIELAMR5", 0x22A8, 32, 0}, \
- \
- /* PCIEC address registers */ \
- {"PCIEPALR0", 0x3400, 32, 0}, \
- {"PCIEPAUR0", 0x3404, 32, 0}, \
- {"PCIEPAMR0", 0x3408, 32, 0}, \
- {"PCIEPTCTLR0", 0x340C, 32, 0}, \
- {"PCIEPALR1", 0x3420, 32, 0}, \
- {"PCIEPAUR1", 0x3424, 32, 0}, \
- {"PCIEPAMR1", 0x3428, 32, 0}, \
- {"PCIEPTCTLR1", 0x342C, 32, 0}, \
- {"PCIEPALR2", 0x3440, 32, 0}, \
- {"PCIEPAUR2", 0x3444, 32, 0}, \
- {"PCIEPAMR2", 0x3448, 32, 0}, \
- {"PCIEPTCTLR2", 0x344C, 32, 0}, \
- {"PCIEPALR3", 0x3460, 32, 0}, \
- {"PCIEPAUR3", 0x3464, 32, 0}, \
- {"PCIEPAMR3", 0x3468, 32, 0}, \
- {"PCIEPTCTLR3", 0x346C, 32, 0}, \
-}
-
-static PCIE_BACKUP_REGS(pcie0_ip_regs);
-static PCIE_BACKUP_REGS(pcie1_ip_regs);
-
-static struct rcar_ip pcie0_ip = {
- .ip_name = "pcie0",
- .reg_count = ARRAY_SIZE(pcie0_ip_regs),
- .ip_reg = pcie0_ip_regs,
-};
-
-static struct rcar_ip pcie1_ip = {
- .ip_name = "pcie1",
- .reg_count = ARRAY_SIZE(pcie1_ip_regs),
- .ip_reg = pcie1_ip_regs,
-};
-
-struct ip_info {
- const char *name;
- struct rcar_ip *ip;
-};
-
-static struct ip_info ip_info_tbl[] = {
- {"fe000000.pcie", &pcie0_ip },
- {"ee800000.pcie", &pcie1_ip },
- {NULL, NULL},
-};
-
-static struct rcar_ip *rcar_pcie_get_ip(const char *name)
-{
- struct ip_info *ip_info = ip_info_tbl;
- struct rcar_ip *ip = NULL;
-
- while (ip_info->name) {
- if (!strcmp(ip_info->name, name)) {
- ip = ip_info->ip;
- break;
- }
- ip_info++;
- }
-
- return ip;
-}
-
-static int rcar_pcie_save_regs(struct device *dev)
-{
- struct rcar_ip *ip = rcar_pcie_get_ip(dev_name(dev));
- struct rcar_pcie *pcie = NULL;
- int ret;
-
- if (ip) {
- if (!ip->virt_addr) {
- pcie = dev_get_drvdata(dev);
- ip->virt_addr = pcie->base;
- }
-
- ret = rcar_handle_registers(ip, DO_BACKUP);
- if (ret)
- pr_err("%s: %s: BACKUP failed, ret=%d\n",
- __func__, dev_name(dev), ret);
- } else
- pr_err("%s: Failed to find backup of dev: %s\n\n",
- __func__, dev_name(dev));
-
- return 0;
-}
-
-static int rcar_pcie_restore_regs(struct device *dev)
-{
- struct rcar_ip *ip = rcar_pcie_get_ip(dev_name(dev));
- int ret = -ENODEV;
-
- if (ip) {
- ret = rcar_handle_registers(ip, DO_RESTORE);
- if (ret)
- pr_err("%s: %s: RESTORE failed, ret=%d\n",
- __func__, dev_name(dev), ret);
-
- } else
- pr_err("%s: Failed to find backup of dev: %s\n\n",
- __func__, dev_name(dev));
-
- return 0;
-}
-
-#endif /* CONFIG_RCAR_DDR_BACKUP */
-
static void rcar_pci_write_reg(struct rcar_pcie *pcie, unsigned long val,
unsigned long reg)
{
@@ -391,6 +251,7 @@
if ((val == 0) || (rcar_pci_read_reg(pcie, PCIETCTLR) & DL_DOWN)) {
/* Wait PCI Express link is re-initialized */
+ dev_info(&bus->dev, "Wait PCI Express link is re-initialized\n");
rcar_pci_write_reg(pcie, CFINIT, PCIETCTLR);
rcar_pcie_wait_for_dl(pcie);
}
@@ -621,6 +482,36 @@
(macsr & LINK_SPEED) == LINK_SPEED_5_0GTS ? "5" : "2.5");
}
+static int rcar_pcie_hw_enable(struct rcar_pcie *pcie)
+{
+ struct resource_entry *win;
+ LIST_HEAD(res);
+ int i = 0;
+
+ /* Try setting 5 GT/s link speed */
+ rcar_pcie_force_speedup(pcie);
+
+ /* Setup PCI resources */
+ resource_list_for_each_entry(win, &pcie->resources) {
+ struct resource *res = win->res;
+
+ if (!res->flags)
+ continue;
+
+ switch (resource_type(res)) {
+ case IORESOURCE_IO:
+ case IORESOURCE_MEM:
+ rcar_pcie_setup_window(i, pcie, res);
+ i++;
+ break;
+ default:
+ continue;
+ }
+ }
+
+ return 0;
+}
+
static int rcar_pcie_enable(struct rcar_pcie *pcie)
{
struct device *dev = pcie->dev;
@@ -710,6 +601,7 @@
if ((rcar_pci_read_reg(pcie, PCIETSTR) & DATA_LINK_ACTIVE))
return 0;
+ /* It sometimes interrupts, I don't use sleep. */
mdelay(5);
}
@@ -1017,6 +909,23 @@
.map = rcar_msi_map,
};
+static int rcar_pcie_hw_enable_msi(struct rcar_pcie *pcie)
+{
+ struct rcar_msi *msi = &pcie->msi;
+ unsigned long base;
+
+ /* setup MSI data target */
+ base = virt_to_phys((void *)msi->pages);
+
+ rcar_pci_write_reg(pcie, base | MSIFE, PCIEMSIALR);
+ rcar_pci_write_reg(pcie, 0, PCIEMSIAUR);
+
+ /* enable all MSI interrupts */
+ rcar_pci_write_reg(pcie, 0xffffffff, PCIEMSIIER);
+
+ return 0;
+}
+
static int rcar_pcie_enable_msi(struct rcar_pcie *pcie)
{
struct device *dev = pcie->dev;
@@ -1364,29 +1273,57 @@
#ifdef CONFIG_PM_SLEEP
static int rcar_pcie_suspend(struct device *dev)
{
- int ret = 0;
-#ifdef CONFIG_RCAR_DDR_BACKUP
- ret = rcar_pcie_save_regs(dev);
-#endif /* CONFIG_RCAR_DDR_BACKUP */
-
- return ret;
+ /* Processing is unnecesary */
+ return 0;
}
static int rcar_pcie_resume(struct device *dev)
{
struct rcar_pcie *pcie = dev_get_drvdata(dev);
- int ret = 0;
+ unsigned int data;
+ const struct of_device_id *of_id;
+ int err;
+ int (*hw_init_fn)(struct rcar_pcie *);
- if (pcie) {
-#ifdef CONFIG_RCAR_DDR_BACKUP
- rcar_pcie_restore_regs(dev);
-#endif /* CONFIG_RCAR_DDR_BACKUP */
- ret = rcar_pcie_hw_init(pcie);
- if (ret)
- pr_debug("%s: %s: re-init hw fail, ret=%d\n",
- __func__, dev_name(dev), ret);
- } else
- pr_warn("%s: %s: pcie NULL\n", __func__, dev_name(dev));
+ /* HW initialize on Resume */
+ if (!pcie) {
+ dev_warn(dev, "%s: %s: pcie NULL\n", __func__, dev_name(dev));
+ return 0; /* resume of the whole system continues */
+ }
+
+ err = rcar_pcie_parse_map_dma_ranges(pcie, dev->of_node);
+ if (err) {
+ dev_err(dev, "%s: %s: parse map dma ranges fail, err=%d\n",
+ __func__, dev_name(dev), err);
+ return 0; /* resume of the whole system continues */
+ }
+
+ of_id = of_match_device(rcar_pcie_of_match, dev);
+ if (!of_id || !of_id->data) {
+ dev_err(dev, "of_match_device not found.\n");
+ return 0; /* resume of the whole system continues */
+ }
+ hw_init_fn = of_id->data;
+
+ /* Failure to get a link might just be that no cards are inserted */
+ err = hw_init_fn(pcie);
+ if (err) {
+ dev_err(dev, "PCIe link down\n");
+ dev_dbg(dev, "%s: %s: re-init hw fail, err=%d\n",
+ __func__, dev_name(dev), err);
+ pm_runtime_put(dev);
+ return 0; /* resume of the whole system continues */
+ }
+
+ data = rcar_pci_read_reg(pcie, MACSR);
+ dev_info(dev, "PCIe x%d: link up\n", (data >> 20) & 0x3f);
+
+ if (IS_ENABLED(CONFIG_PCI_MSI)) {
+ /* enable MSI */
+ rcar_pcie_hw_enable_msi(pcie);
+ dev_dbg(dev, "%s: %s: enable MSI\n", __func__, dev_name(dev));
+ }
+ rcar_pcie_hw_enable(pcie);
return 0;
}
diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c
index 80ee954..f106dee 100644
--- a/drivers/phy/phy-rcar-gen3-usb2.c
+++ b/drivers/phy/phy-rcar-gen3-usb2.c
@@ -1,7 +1,7 @@
/*
* Renesas R-Car Gen3 for USB2.0 PHY driver
*
- * Copyright (C) 2015 Renesas Electronics Corporation
+ * Copyright (C) 2015-2017 Renesas Electronics Corporation
*
* This is based on the phy-rcar-gen2 driver:
* Copyright (C) 2014 Renesas Solutions Corp.
@@ -481,8 +481,15 @@
#ifdef CONFIG_PM_SLEEP
static int rcar_gen3_phy_suspend(struct device *dev)
{
- /* Empty function for now */
- return 0;
+ int ret = 0;
+
+ if (to_phy(dev))
+ ret = rcar_gen3_phy_usb2_exit(to_phy(dev));
+ else {
+ pr_warn("%s: No phy dev\n", __func__);
+ ret = -ENODEV;
+ }
+ return ret;
}
static int rcar_gen3_phy_resume(struct device *dev)
diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
index 659454a..630f3f08 100644
--- a/drivers/pwm/pwm-rcar.c
+++ b/drivers/pwm/pwm-rcar.c
@@ -17,7 +17,6 @@
#include <linux/pm_runtime.h>
#include <linux/pwm.h>
#include <linux/slab.h>
-#include <linux/soc/renesas/s2ram_ddr_backup.h>
#define RCAR_PWM_MAX_DIVISION 24
#define RCAR_PWM_MIN_CYCLE 2
@@ -37,124 +36,6 @@
#define RCAR_PWMCNT_PH0_MASK 0x000003ff
#define RCAR_PWMCNT_PH0_SHIFT 0
-#ifdef CONFIG_RCAR_DDR_BACKUP
-/* PWM0 */
-static struct hw_register pwm0_ip_regs[] = {
- {"PWMCNT", 0x0004, 32, 0},
- {"PWMCR", 0x0000, 32, 0},
-};
-
-static struct rcar_ip pwm0_ip = {
- .ip_name = "PWM0",
- .reg_count = ARRAY_SIZE(pwm0_ip_regs),
- .ip_reg = pwm0_ip_regs,
-};
-
-/* PWM1 */
-static struct hw_register pwm1_ip_regs[] = {
- {"PWMCNT", 0x0004, 32, 0},
- {"PWMCR", 0x0000, 32, 0},
-};
-
-static struct rcar_ip pwm1_ip = {
- .ip_name = "PWM1",
- .reg_count = ARRAY_SIZE(pwm1_ip_regs),
- .ip_reg = pwm1_ip_regs,
-};
-
-/* PWM2 */
-static struct hw_register pwm2_ip_regs[] = {
- {"PWMCNT", 0x0004, 32, 0},
- {"PWMCR", 0x0000, 32, 0},
-};
-
-static struct rcar_ip pwm2_ip = {
- .ip_name = "PWM2",
- .reg_count = ARRAY_SIZE(pwm2_ip_regs),
- .ip_reg = pwm2_ip_regs,
-};
-
-/* PWM3 */
-static struct hw_register pwm3_ip_regs[] = {
- {"PWMCNT", 0x0004, 32, 0},
- {"PWMCR", 0x0000, 32, 0},
-};
-
-static struct rcar_ip pwm3_ip = {
- .ip_name = "PWM3",
- .reg_count = ARRAY_SIZE(pwm3_ip_regs),
- .ip_reg = pwm3_ip_regs,
-};
-
-/* PWM4 */
-static struct hw_register pwm4_ip_regs[] = {
- {"PWMCNT", 0x0004, 32, 0},
- {"PWMCR", 0x0000, 32, 0},
-};
-
-static struct rcar_ip pwm4_ip = {
- .ip_name = "PWM4",
- .reg_count = ARRAY_SIZE(pwm4_ip_regs),
- .ip_reg = pwm4_ip_regs,
-};
-
-/* PWM5 */
-static struct hw_register pwm5_ip_regs[] = {
- {"PWMCNT", 0x0004, 32, 0},
- {"PWMCR", 0x0000, 32, 0},
-};
-
-static struct rcar_ip pwm5_ip = {
- .ip_name = "PWM5",
- .reg_count = ARRAY_SIZE(pwm5_ip_regs),
- .ip_reg = pwm5_ip_regs,
-};
-
-/* PWM6 */
-static struct hw_register pwm6_ip_regs[] = {
- {"PWMCNT", 0x0004, 32, 0},
- {"PWMCR", 0x0000, 32, 0},
-};
-
-static struct rcar_ip pwm6_ip = {
- .ip_name = "PWM6",
- .reg_count = ARRAY_SIZE(pwm6_ip_regs),
- .ip_reg = pwm6_ip_regs,
-};
-
-struct pwm_ip_info {
- const char *name;
- struct rcar_ip *ip;
-};
-
-static struct pwm_ip_info ip_info_tbl[] = {
- {"e6e30000.pwm", &pwm0_ip},
- {"e6e31000.pwm", &pwm1_ip},
- {"e6e32000.pwm", &pwm2_ip},
- {"e6e33000.pwm", &pwm3_ip},
- {"e6e34000.pwm", &pwm4_ip},
- {"e6e35000.pwm", &pwm5_ip},
- {"e6e36000.pwm", &pwm6_ip},
- {NULL, NULL},
-};
-
-static struct rcar_ip *rcar_pwm_get_ip(const char *name)
-{
- struct pwm_ip_info *ip_info = ip_info_tbl;
- struct rcar_ip *ip = NULL;
-
- while (ip_info->name) {
- if (!strcmp(ip_info->name, name)) {
- ip = ip_info->ip;
- break;
- }
- ip_info++;
- }
-
- return ip;
-}
-#endif /* CONFIG_RCAR_DDR_BACKUP */
-
struct rcar_pwm_chip {
struct pwm_chip chip;
void __iomem *base;
@@ -382,44 +263,29 @@
#ifdef CONFIG_PM_SLEEP
static int rcar_pwm_suspend(struct device *dev)
{
- int ret = 0;
-#ifdef CONFIG_RCAR_DDR_BACKUP
- struct platform_device *pdev = to_platform_device(dev);
- struct rcar_ip *ip = rcar_pwm_get_ip(pdev->name);
-
- if (ip) {
- struct rcar_pwm_chip *pwm = platform_get_drvdata(pdev);
-
- if (!ip->virt_addr)
- ip->virt_addr = pwm->base;
- pm_runtime_get_sync(dev);
- ret = rcar_handle_registers(ip, DO_BACKUP);
- pm_runtime_put(dev);
- } else {
- pr_err("%s: Failed to find PWM device\n", __func__);
- ret = -ENODEV;
- }
-#endif /* CONFIG_RCAR_DDR_BACKUP */
- return ret;
+ return 0;
}
static int rcar_pwm_resume(struct device *dev)
{
- int ret = 0;
-#ifdef CONFIG_RCAR_DDR_BACKUP
struct platform_device *pdev = to_platform_device(dev);
- struct rcar_ip *ip = rcar_pwm_get_ip(pdev->name);
+ struct rcar_pwm_chip *rcar_pwm = platform_get_drvdata(pdev);
+ struct pwm_device *pwm_dev;
+ struct pwm_state state;
- if (ip) {
- pm_runtime_get_sync(dev);
- ret = rcar_handle_registers(ip, DO_RESTORE);
- pm_runtime_put(dev);
- } else {
- pr_err("%s: Failed to find PWM device\n", __func__);
- ret = -ENODEV;
- }
-#endif /* CONFIG_RCAR_DDR_BACKUP */
- return ret;
+ pm_runtime_get_sync(dev);
+
+ pwm_dev = &rcar_pwm->chip.pwms[0];
+ pwm_get_state(pwm_dev, &state);
+ rcar_pwm_config(&rcar_pwm->chip, pwm_dev, state.duty_cycle,
+ state.period);
+
+ if (pwm_is_enabled(pwm_dev))
+ rcar_pwm_enable(&rcar_pwm->chip, pwm_dev);
+
+ pm_runtime_put(dev);
+
+ return 0;
}
static SIMPLE_DEV_PM_OPS(rcar_pwm_pm_ops,
diff --git a/drivers/soc/renesas/rcar-avs.c b/drivers/soc/renesas/rcar-avs.c
index 4b673c5..62adb0c 100644
--- a/drivers/soc/renesas/rcar-avs.c
+++ b/drivers/soc/renesas/rcar-avs.c
@@ -18,6 +18,7 @@
#ifdef CONFIG_POWER_AVS
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/slab.h>
/* Change the default opp_table pattern in device tree.
@@ -61,37 +62,48 @@
}
/* Get AVS value */
-#define ADVFS_BASE 0xE60A0000
-#define KSEN_ADJCNTS (ADVFS_BASE + 0x13C)
-#define VOLCOND_MASK_0_3 0x0f /* VOLCOND[3:0] */
+#define VOLCOND_MASK_0_3 0x0f /* VOLCOND[3:0] bits of KSEN_ADJCNTS register */
#define AVS_TABLE_NUM 7
-unsigned int get_avs_value(void)
-{
- unsigned int ret;
- void __iomem *ksen_adjcnts = ioremap_nocache(KSEN_ADJCNTS, 4);
- u32 ksen_adjcnts_value = ioread32(ksen_adjcnts);
-
- ksen_adjcnts_value &= VOLCOND_MASK_0_3;
- if (ksen_adjcnts_value >= 0 && ksen_adjcnts_value < AVS_TABLE_NUM) {
- ret = ksen_adjcnts_value;
- } else {
- ret = 0;
- pr_debug("rcar-cpufreq: hw get invalid avs value, use avs_tb0\n");
- }
- pr_info("rcar-cpufreq: use avs value: %d\n", ksen_adjcnts_value);
- iounmap(ksen_adjcnts);
-
- return ret;
-}
#endif /* CONFIG_POWER_AVS */
+static const struct of_device_id rcar_avs_matches[] = {
+#if defined(CONFIG_ARCH_R8A7795) || defined(CONFIG_ARCH_R8A7796)
+ { .compatible = "renesas,rcar-gen3-avs" },
+#endif
+ { /* sentinel */ }
+};
+
int __init rcar_avs_init(void)
{
#ifdef CONFIG_POWER_AVS
- int avs_val = get_avs_value();
+ int avs_val;
+ struct device_node *np;
+ void __iomem *ksen_adjcnts;
+ /* Map and get KSEN_ADJCNTS register */
+ np = of_find_matching_node(NULL, rcar_avs_matches);
+ if (!np)
+ return -ENODEV;
+
+ ksen_adjcnts = of_iomap(np, 0); /* KSEN_ADJCNTS register from dts */
+ if (!ksen_adjcnts) {
+ pr_warn("%s: Cannot map regs\n", np->full_name);
+ return -ENOMEM;
+ }
+
+ /* Get and check avs value */
+ avs_val = ioread32(ksen_adjcnts);
+
+ avs_val &= VOLCOND_MASK_0_3;
+ if (!(avs_val >= 0 && avs_val < AVS_TABLE_NUM)) {
+ avs_val = 0;
+ pr_debug("rcar-cpufreq: hw get invalid avs value, use avs_tb0\n");
+ }
+ pr_info("rcar-cpufreq: use avs value: %d\n", avs_val);
+
+ /* Apply avs value */
change_default_opp_pattern(avs_val);
#endif /* CONFIG_POWER_AVS */
return 0;
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index eaef234..7a327dc 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -1,7 +1,7 @@
/*
* SuperH MSIOF SPI Master Interface
*
- * Copyright (C) 2016 Renesas Electronics Corporation
+ * Copyright (C) 2016-2017 Renesas Electronics Corporation
* Copyright (c) 2009 Magnus Damm
* Copyright (C) 2014 Glider bvba
*
@@ -202,7 +202,6 @@
{ },
};
-
static int msiof_rcar_is_gen3(struct device *dev)
{
struct device_node *node = dev->of_node;
@@ -549,7 +548,7 @@
sh_msiof_write(p, RMDR1, tmp);
tmp = 0;
- if (soc_device_match(r8a7795es11)) {
+ if (soc_device_match(r8a7795es10)) {
if (p->mode == SPI_MSIOF_MASTER) {
tmp |= 0 << CTR_TSCKIZ_POL_SHIFT;
tmp |= 0 << CTR_RSCKIZ_POL_SHIFT;
@@ -1570,9 +1569,14 @@
static int sh_msiof_spi_suspend(struct device *dev)
{
int ret = 0;
-#ifdef CONFIG_RCAR_DDR_BACKUP
struct platform_device *pdev = to_platform_device(dev);
+ struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev);
+ ret = spi_master_suspend(p->master);
+ if (ret)
+ return ret;
+
+#ifdef CONFIG_RCAR_DDR_BACKUP
pm_runtime_get_sync(dev);
ret = msiof_save_regs(pdev);
pm_runtime_put(dev);
@@ -1583,13 +1587,19 @@
static int sh_msiof_spi_resume(struct device *dev)
{
int ret = 0;
-#ifdef CONFIG_RCAR_DDR_BACKUP
struct platform_device *pdev = to_platform_device(dev);
+ struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev);
+#ifdef CONFIG_RCAR_DDR_BACKUP
pm_runtime_get_sync(dev);
ret = msiof_restore_regs(pdev);
pm_runtime_put(dev);
#endif /* CONFIG_RCAR_DDR_BACKUP */
+
+ ret = spi_master_resume(p->master);
+ if (ret)
+ return ret;
+
return ret;
}
diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c
index 2e5816b..95ea3a8 100644
--- a/drivers/thermal/rcar_gen3_thermal.c
+++ b/drivers/thermal/rcar_gen3_thermal.c
@@ -49,7 +49,7 @@
#define PTAT_SIZE REG_GEN3_PTAT3
/* CTSR bit */
-#define PONM1 (0x1 << 8) /* For H3 WS1.x */
+#define PONM1 (0x1 << 8) /* For H3 ES1.x */
#define AOUT (0x1 << 7)
#define THBGR (0x1 << 5)
#define VMEN (0x1 << 4)
@@ -57,7 +57,7 @@
#define THSST (0x1 << 0)
/* THCTR bit */
-#define PONM2 (0x1 << 6) /* For H3 WS2.0 and M3 WS1.0 */
+#define PONM2 (0x1 << 6) /* For H3 ES2.0 and M3 ES1.0 */
#define CTEMP_MASK 0xFFF
@@ -74,13 +74,18 @@
#define GEN3_FUSE_MASK 0xFFF
/* Attribute structs describing Salvator-X revisions */
-/* H3 WS1.0 and WS1.1 */
+/* H3 ES1.0 and ES1.1 */
static const struct soc_device_attribute r8a7795es1[] = {
{ .soc_id = "r8a7795", .revision = "ES1.*" },
{}
};
-/* M3 WS1.0 */
+static const struct soc_device_attribute r8a7795[] = {
+ { .soc_id = "r8a7795", .revision = "ES2.0" },
+ {}
+};
+
+/* M3 ES1.0 */
static const struct soc_device_attribute r8a7796es10[] = {
{ .soc_id = "r8a7796", .revision = "ES1.0" },
{}
@@ -170,11 +175,12 @@
return -ENOMEM;
}
- /* For H3 WS1.0, H3 WS1.1 and M3 ES1.0
+ /* For H3 ES1.x, H3 ES2.0 and M3 ES1.0
* these registers have not been programmed yet.
* We will use fixed value as temporary solution.
*/
if (soc_device_match(r8a7795es1)
+ || soc_device_match(r8a7795)
|| soc_device_match(r8a7796es10)) {
priv->factor.ptat_1 = 2351;
priv->factor.ptat_2 = 1509;
@@ -378,7 +384,7 @@
spin_unlock_irqrestore(&priv->lock, flags);
} else
- /* H3 WS2.0 has the same init flow with M3 WS1.0 */
+ /* H3 ES2.0 has the same init flow with M3 ES1.0 */
rcar_gen3_r8a7796_thermal_init(priv);
return 0;
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index 4948740..8151197 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -443,6 +443,10 @@
struct usbhs_priv *priv = container_of(work,
struct usbhs_priv,
notify_hotplug_work.work);
+
+ if (priv->suspended)
+ return;
+
usbhsc_hotplug(priv);
}
@@ -735,10 +739,9 @@
{
struct usbhs_priv *priv = dev_get_drvdata(dev);
struct usbhs_mod *mod = usbhs_mod_get_current(priv);
- struct renesas_usbhs_platform_info *info = dev_get_platdata(dev);
- struct renesas_usbhs_driver_callback *dfunc = &info->driver_callback;
- dfunc->notify_hotplug = NULL;
+ priv->suspended = 1;
+
if (mod) {
usbhs_mod_call(priv, stop, priv);
usbhs_mod_change(priv, -1);
@@ -754,14 +757,13 @@
{
struct usbhs_priv *priv = dev_get_drvdata(dev);
struct platform_device *pdev = usbhs_priv_to_pdev(priv);
- struct renesas_usbhs_platform_info *info = dev_get_platdata(dev);
- struct renesas_usbhs_driver_callback *dfunc = &info->driver_callback;
if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
usbhsc_power_ctrl(priv, 1);
usbhs_platform_call(priv, phy_reset, pdev);
- dfunc->notify_hotplug = usbhsc_drvcllbck_notify_hotplug;
+
+ priv->suspended = 0;
usbhsc_drvcllbck_notify_hotplug(pdev);
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
index 8c5fc12..6e02aa3 100644
--- a/drivers/usb/renesas_usbhs/common.h
+++ b/drivers/usb/renesas_usbhs/common.h
@@ -280,6 +280,8 @@
struct usb_phy *usb_phy;
struct phy *phy;
+
+ int suspended;
};
/*
diff --git a/drivers/watchdog/renesas_wdt.c b/drivers/watchdog/renesas_wdt.c
index 3c7708d..b2308a8 100644
--- a/drivers/watchdog/renesas_wdt.c
+++ b/drivers/watchdog/renesas_wdt.c
@@ -2,7 +2,7 @@
* Watchdog driver for Renesas WDT watchdog
*
* Copyright (C) 2015-16 Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>
- * Copyright (C) 2015-16 Renesas Electronics Corporation
+ * Copyright (C) 2015-17 Renesas Electronics Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
@@ -16,7 +16,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
-#include <linux/soc/renesas/s2ram_ddr_backup.h>
#include <linux/watchdog.h>
#define RWTCNT 0
@@ -27,19 +26,6 @@
#define RWDT_DEFAULT_TIMEOUT 60U
-#ifdef CONFIG_RCAR_DDR_BACKUP
-static struct hw_register rwdt_ip_regs[] = {
- {"RWTCNT", 0x00, 16, 0},
- {"RWTCSRA", 0x04, 8, 0},
-};
-
-static struct rcar_ip rwdt_ip = {
- .ip_name = "RWDT",
- .reg_count = ARRAY_SIZE(rwdt_ip_regs),
- .ip_reg = rwdt_ip_regs,
-};
-#endif /* CONFIG_RCAR_DDR_BACKUP*/
-
static const unsigned int clk_divs[] = { 1, 4, 16, 32, 64, 128, 1024 };
static bool nowayout = WATCHDOG_NOWAYOUT;
@@ -226,23 +212,22 @@
static int rwdt_suspend(struct device *dev)
{
int ret = 0;
-#ifdef CONFIG_RCAR_DDR_BACKUP
struct rwdt_priv *priv = dev_get_drvdata(dev);
- if (!rwdt_ip.virt_addr)
- rwdt_ip.virt_addr = priv->base;
+ if (watchdog_active(&priv->wdev))
+ ret = rwdt_stop(&priv->wdev);
- ret = rcar_handle_registers(&rwdt_ip, DO_BACKUP);
-#endif /* CONFIG_RCAR_DDR_BACKUP */
return ret;
}
static int rwdt_resume(struct device *dev)
{
int ret = 0;
-#ifdef CONFIG_RCAR_DDR_BACKUP
- ret = rcar_handle_registers(&rwdt_ip, DO_RESTORE);
-#endif /* CONFIG_RCAR_DDR_BACKUP */
+ struct rwdt_priv *priv = dev_get_drvdata(dev);
+
+ if (watchdog_active(&priv->wdev))
+ ret = rwdt_start(&priv->wdev);
+
return ret;
}
diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h
index 2f2cc7b..3b95dc7 100644
--- a/include/linux/mfd/tmio.h
+++ b/include/linux/mfd/tmio.h
@@ -99,9 +99,6 @@
*/
#define TMIO_MMC_SDIO_STATUS_QUIRK (1 << 8)
-/* The start or stop of SD clock don't wait 10msec. */
-#define TMIO_MMC_CLK_NO_SLEEP (1 << 9)
-
/*
* Some controllers allows to set SDx actual clock
*/
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index 2145957..85a33ac 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -34,6 +34,9 @@
struct clk_onecell_data onecell;
struct rsnd_mod mod;
u32 flags;
+ u32 ckr;
+ u32 rbga;
+ u32 rbgb;
int rbga_rate_for_441khz; /* RBGA */
int rbgb_rate_for_48khz; /* RBGB */
@@ -316,9 +319,11 @@
struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
struct clk *clk;
int i;
u32 data;
+ u32 ckr = 0;
int sel_table[] = {
[CLKA] = 0x1,
[CLKB] = 0x2,
@@ -360,15 +365,14 @@
rsnd_adg_set_ssi_clk(ssi_mod, data);
if (!(adg_mode_flags(adg) & LRCLK_ASYNC)) {
- struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
- u32 ckr = 0;
-
if (0 == (rate % 8000))
ckr = 0x80000000;
-
- rsnd_mod_bset(adg_mod, SSICKR, 0x80000000, ckr);
}
+ rsnd_mod_bset(adg_mod, BRGCKR, 0x80FF0000, adg->ckr | ckr);
+ rsnd_mod_write(adg_mod, BRRA, adg->rbga);
+ rsnd_mod_write(adg_mod, BRRB, adg->rbgb);
+
dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n",
rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod),
data, rate);
@@ -376,6 +380,25 @@
return 0;
}
+void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
+{
+ struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct clk *clk;
+ int i, ret;
+
+ for_each_rsnd_clk(clk, adg, i) {
+ ret = 0;
+ if (enable)
+ ret = clk_prepare_enable(clk);
+ else
+ clk_disable_unprepare(clk);
+
+ if (ret < 0)
+ dev_warn(dev, "can't use clk %d\n", i);
+ }
+}
+
static void rsnd_adg_get_clkin(struct rsnd_priv *priv,
struct rsnd_adg *adg)
{
@@ -387,27 +410,21 @@
[CLKC] = "clk_c",
[CLKI] = "clk_i",
};
- int i, ret;
+ int i;
for (i = 0; i < CLKMAX; i++) {
clk = devm_clk_get(dev, clk_name[i]);
adg->clk[i] = IS_ERR(clk) ? NULL : clk;
}
- for_each_rsnd_clk(clk, adg, i) {
- ret = clk_prepare_enable(clk);
- if (ret < 0)
- dev_warn(dev, "can't use clk %d\n", i);
-
+ for_each_rsnd_clk(clk, adg, i)
dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk));
- }
}
static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
struct rsnd_adg *adg)
{
struct clk *clk;
- struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
struct device *dev = rsnd_priv_to_dev(priv);
struct device_node *np = dev->of_node;
u32 ckr, rbgx, rbga, rbgb;
@@ -532,13 +549,13 @@
}
}
- rsnd_mod_bset(adg_mod, SSICKR, 0x80FF0000, ckr);
- rsnd_mod_write(adg_mod, BRRA, rbga);
- rsnd_mod_write(adg_mod, BRRB, rbgb);
+ adg->ckr = ckr;
+ adg->rbga = rbga;
+ adg->rbgb = rbgb;
for_each_rsnd_clkout(clk, adg, i)
dev_dbg(dev, "clkout %d : %p : %ld\n", i, clk, clk_get_rate(clk));
- dev_dbg(dev, "SSICKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
+ dev_dbg(dev, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
ckr, rbga, rbgb);
}
@@ -565,16 +582,12 @@
priv->adg = adg;
+ rsnd_adg_clk_enable(priv);
+
return 0;
}
void rsnd_adg_remove(struct rsnd_priv *priv)
{
- struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
- struct clk *clk;
- int i;
-
- for_each_rsnd_clk(clk, adg, i) {
- clk_disable_unprepare(clk);
- }
+ rsnd_adg_clk_disable(priv);
}
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 940012d..babbbbc 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -993,7 +993,11 @@
void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg)
{
- snd_ctl_remove(cfg->card, cfg->kctrl);
+ if (cfg->card && cfg->kctrl)
+ snd_ctl_remove(cfg->card, cfg->kctrl);
+
+ cfg->card = NULL;
+ cfg->kctrl = NULL;
}
int rsnd_kctrl_new_m(struct rsnd_mod *mod,
@@ -1251,12 +1255,11 @@
return ret;
}
-#ifdef CONFIG_PM_SLEEP
static int rsnd_suspend(struct device *dev)
{
struct rsnd_priv *priv = dev_get_drvdata(dev);
- rsnd_adg_remove(priv);
+ rsnd_adg_clk_disable(priv);
return 0;
}
@@ -1264,24 +1267,21 @@
static int rsnd_resume(struct device *dev)
{
struct rsnd_priv *priv = dev_get_drvdata(dev);
- int ret;
- ret = rsnd_adg_probe(priv);
+ rsnd_adg_clk_enable(priv);
- return ret;
+ return 0;
}
-static SIMPLE_DEV_PM_OPS(rsnd_pm_ops,
- rsnd_suspend, rsnd_resume);
-#define DEV_PM_OPS (&rsnd_pm_ops)
-#else
-#define DEV_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static const struct dev_pm_ops rsnd_pm_ops = {
+ .suspend = rsnd_suspend,
+ .resume = rsnd_resume,
+};
static struct platform_driver rsnd_driver = {
.driver = {
.name = "rcar_sound",
- .pm = DEV_PM_OPS,
+ .pm = &rsnd_pm_ops,
.of_match_table = rsnd_of_match,
},
.probe = rsnd_probe,
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index 6bc93cb..b3bdd36 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -707,6 +707,17 @@
return 0;
}
+void rsnd_dma_detach(struct rsnd_mod *mod, struct rsnd_mod **dma_mod)
+{
+ if (*dma_mod) {
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct device *dev = rsnd_priv_to_dev(priv);
+
+ devm_kfree(dev, *dma_mod);
+ *dma_mod = NULL;
+ }
+}
+
int rsnd_dma_probe(struct rsnd_priv *priv)
{
struct platform_device *pdev = rsnd_priv_to_pdev(priv);
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index 7d2fdf8..e785fe94 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -311,7 +311,7 @@
static const struct rsnd_regmap_field_conf conf_adg[] = {
RSND_GEN_S_REG(BRRA, 0x00),
RSND_GEN_S_REG(BRRB, 0x04),
- RSND_GEN_S_REG(SSICKR, 0x08),
+ RSND_GEN_S_REG(BRGCKR, 0x08),
RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c),
RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10),
RSND_GEN_S_REG(AUDIO_CLK_SEL2, 0x14),
@@ -362,7 +362,7 @@
static const struct rsnd_regmap_field_conf conf_adg[] = {
RSND_GEN_S_REG(BRRA, 0x00),
RSND_GEN_S_REG(BRRB, 0x04),
- RSND_GEN_S_REG(SSICKR, 0x08),
+ RSND_GEN_S_REG(BRGCKR, 0x08),
RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c),
RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10),
};
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 8ca1705..bf9596b 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -154,7 +154,7 @@
/* ADG */
RSND_REG_BRRA,
RSND_REG_BRRB,
- RSND_REG_SSICKR,
+ RSND_REG_BRGCKR,
RSND_REG_DIV_EN, /* Gen2 only */
RSND_REG_AUDIO_CLK_SEL0,
RSND_REG_AUDIO_CLK_SEL1,
@@ -200,6 +200,7 @@
*/
int rsnd_dma_attach(struct rsnd_dai_stream *io,
struct rsnd_mod *mod, struct rsnd_mod **dma_mod, int id);
+void rsnd_dma_detach(struct rsnd_mod *mod, struct rsnd_mod **dma_mod);
int rsnd_dma_probe(struct rsnd_priv *priv);
struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
struct rsnd_mod *mod, char *name);
@@ -276,9 +277,8 @@
/*
* status
*
- * 0xH0000CBA
+ * 0xH0000CB0
*
- * A 0: probe 1: remove
* B 0: init 1: quit
* C 0: start 1: stop
*
@@ -288,19 +288,19 @@
* H 0: fallback
* H 0: hw_params
*/
-#define __rsnd_mod_shift_probe 0
-#define __rsnd_mod_shift_remove 0
#define __rsnd_mod_shift_init 4
#define __rsnd_mod_shift_quit 4
#define __rsnd_mod_shift_start 8
#define __rsnd_mod_shift_stop 8
+#define __rsnd_mod_shift_probe 28 /* always called */
+#define __rsnd_mod_shift_remove 28 /* always called */
#define __rsnd_mod_shift_irq 28 /* always called */
#define __rsnd_mod_shift_pcm_new 28 /* always called */
#define __rsnd_mod_shift_fallback 28 /* always called */
#define __rsnd_mod_shift_hw_params 28 /* always called */
-#define __rsnd_mod_add_probe 1
-#define __rsnd_mod_add_remove -1
+#define __rsnd_mod_add_probe 0
+#define __rsnd_mod_add_remove 0
#define __rsnd_mod_add_init 1
#define __rsnd_mod_add_quit -1
#define __rsnd_mod_add_start 1
@@ -311,7 +311,7 @@
#define __rsnd_mod_add_hw_params 0
#define __rsnd_mod_call_probe 0
-#define __rsnd_mod_call_remove 1
+#define __rsnd_mod_call_remove 0
#define __rsnd_mod_call_init 0
#define __rsnd_mod_call_quit 1
#define __rsnd_mod_call_start 0
@@ -454,6 +454,9 @@
unsigned int out_rate);
int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
struct rsnd_dai_stream *io);
+#define rsnd_adg_clk_enable(priv) rsnd_adg_clk_control(priv, 1)
+#define rsnd_adg_clk_disable(priv) rsnd_adg_clk_control(priv, 0)
+void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable);
/*
* R-Car sound priv
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index 1e9ca57..85f9879 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -390,6 +390,9 @@
{
struct rsnd_src *src = rsnd_mod_to_src(mod);
+ /* reset sync convert_rate */
+ src->sync.val = 0;
+
rsnd_mod_power_on(mod);
rsnd_src_activation(mod);
@@ -398,9 +401,6 @@
rsnd_src_status_clear(mod);
- /* reset sync convert_rate */
- src->sync.val = 0;
-
return 0;
}
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 8f077cc..5616c94 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -701,7 +701,10 @@
int irq = ssi->irq;
/* PIO will request IRQ again */
- devm_free_irq(dev, irq, mod);
+ if (ssi->dma)
+ devm_free_irq(dev, irq, mod);
+
+ rsnd_dma_detach(mod, &ssi->dma);
return 0;
}