summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/firmware/psci/psci.c17
-rw-r--r--drivers/gpu/drm/bridge/dumb-vga-dac.c22
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.c15
-rw-r--r--drivers/gpu/drm/imx/parallel-display.c3
-rw-r--r--drivers/gpu/drm/panel/panel-lvds.c46
-rw-r--r--drivers/i2c/busses/i2c-imx.c128
-rw-r--r--drivers/net/phy/micrel.c2
-rw-r--r--drivers/pci/controller/dwc/pci-imx6.c102
-rw-r--r--drivers/spi/spidev.c1
-rw-r--r--drivers/tty/serial/imx.c17
10 files changed, 290 insertions, 63 deletions
diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c
index f82ccd39a913..a7e2deab930a 100644
--- a/drivers/firmware/psci/psci.c
+++ b/drivers/firmware/psci/psci.c
@@ -82,6 +82,7 @@ static u32 psci_function_id[PSCI_FN_MAX];
static u32 psci_cpu_suspend_feature;
static bool psci_system_reset2_supported;
+static struct notifier_block psci_restart_handler;
static inline bool psci_has_ext_power_state(void)
{
@@ -250,7 +251,8 @@ static int get_set_conduit_method(struct device_node *np)
return 0;
}
-static void psci_sys_reset(enum reboot_mode reboot_mode, const char *cmd)
+static int psci_sys_reset(struct notifier_block *this,
+ unsigned long reboot_mode, void *cmd)
{
if ((reboot_mode == REBOOT_WARM || reboot_mode == REBOOT_SOFT) &&
psci_system_reset2_supported) {
@@ -263,6 +265,8 @@ static void psci_sys_reset(enum reboot_mode reboot_mode, const char *cmd)
} else {
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0);
}
+
+ return NOTIFY_DONE;
}
static void psci_sys_poweroff(void)
@@ -562,6 +566,8 @@ static void __init psci_init_smccc(void)
static void __init psci_0_2_set_functions(void)
{
+ int ret;
+
pr_info("Using standard PSCI v0.2 function IDs\n");
psci_ops.get_version = psci_get_version;
@@ -582,7 +588,14 @@ static void __init psci_0_2_set_functions(void)
psci_ops.migrate_info_type = psci_migrate_info_type;
- arm_pm_restart = psci_sys_reset;
+ psci_restart_handler.notifier_call = psci_sys_reset;
+ psci_restart_handler.priority = 160;
+
+ ret = register_restart_handler(&psci_restart_handler);
+ if (ret) {
+ pr_err("Cannot register restart handler, %d\n", ret);
+ return;
+ }
pm_power_off = psci_sys_poweroff;
}
diff --git a/drivers/gpu/drm/bridge/dumb-vga-dac.c b/drivers/gpu/drm/bridge/dumb-vga-dac.c
index d32885b906ae..751c4000870e 100644
--- a/drivers/gpu/drm/bridge/dumb-vga-dac.c
+++ b/drivers/gpu/drm/bridge/dumb-vga-dac.c
@@ -175,6 +175,7 @@ static struct i2c_adapter *dumb_vga_retrieve_ddc(struct device *dev)
static int dumb_vga_probe(struct platform_device *pdev)
{
struct dumb_vga *vga;
+ u32 de;
vga = devm_kzalloc(&pdev->dev, sizeof(*vga), GFP_KERNEL);
if (!vga)
@@ -190,6 +191,23 @@ static int dumb_vga_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "No vdd regulator found: %d\n", ret);
}
+ vga->bridge.funcs = &dumb_vga_bridge_funcs;
+ vga->bridge.of_node = pdev->dev.of_node;
+ vga->bridge.timings = of_device_get_match_data(&pdev->dev);
+
+ if (!vga->bridge.timings &&
+ !of_property_read_u32(pdev->dev.of_node, "de-active", &de)) {
+ struct drm_bridge_timings *timings;
+
+ timings = devm_kzalloc(&pdev->dev, sizeof(*timings), GFP_KERNEL);
+ if (!timings)
+ return -ENOMEM;
+
+ timings->input_bus_flags = de ? DRM_BUS_FLAG_DE_HIGH :
+ DRM_BUS_FLAG_DE_LOW;
+ vga->bridge.timings = timings;
+ }
+
vga->ddc = dumb_vga_retrieve_ddc(&pdev->dev);
if (IS_ERR(vga->ddc)) {
if (PTR_ERR(vga->ddc) == -ENODEV) {
@@ -201,10 +219,6 @@ static int dumb_vga_probe(struct platform_device *pdev)
}
}
- vga->bridge.funcs = &dumb_vga_bridge_funcs;
- vga->bridge.of_node = pdev->dev.of_node;
- vga->bridge.timings = of_device_get_match_data(&pdev->dev);
-
drm_bridge_add(&vga->bridge);
return 0;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 5418a1a87b2c..8453fc05dcf2 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -4,7 +4,9 @@
*/
#include <linux/clk.h>
+#include <linux/cma.h>
#include <linux/component.h>
+#include <linux/dma-contiguous.h>
#include <linux/dma-fence.h>
#include <linux/moduleparam.h>
#include <linux/of_device.h>
@@ -724,11 +726,18 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
*/
if (!(gpu->identity.features & chipFeatures_PIPE_3D) ||
(gpu->identity.minor_features0 & chipMinorFeatures0_MC20)) {
- u32 dma_mask = (u32)dma_get_required_mask(gpu->dev);
- if (dma_mask < PHYS_OFFSET + SZ_2G)
+ struct cma *cma = dev_get_cma_area(gpu->dev);
+ phys_addr_t end_mask;
+
+ if (cma)
+ end_mask = cma_get_base(cma) - 1 + cma_get_size(cma);
+ else
+ end_mask = dma_get_required_mask(gpu->dev);
+
+ if (end_mask < PHYS_OFFSET + SZ_2G)
gpu->memory_base = PHYS_OFFSET;
else
- gpu->memory_base = dma_mask - SZ_2G + 1;
+ gpu->memory_base = end_mask - SZ_2G + 1;
} else if (PHYS_OFFSET >= SZ_2G) {
dev_info(gpu->dev, "Need to move linear window on MC1.0, disabling TS\n");
gpu->memory_base = PHYS_OFFSET;
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
index 1a76de1e8e7b..5e8ea973bc71 100644
--- a/drivers/gpu/drm/imx/parallel-display.c
+++ b/drivers/gpu/drm/imx/parallel-display.c
@@ -231,6 +231,9 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
if (ret && ret != -ENODEV)
return ret;
+ if (imxpd->bridge && imxpd->bridge->timings)
+ imxpd->bus_flags = imxpd->bridge->timings->input_bus_flags;
+
imxpd->dev = dev;
ret = imx_pd_register(drm, imxpd);
diff --git a/drivers/gpu/drm/panel/panel-lvds.c b/drivers/gpu/drm/panel/panel-lvds.c
index 1ec57d0806a8..200c6169daa5 100644
--- a/drivers/gpu/drm/panel/panel-lvds.c
+++ b/drivers/gpu/drm/panel/panel-lvds.c
@@ -23,6 +23,11 @@
#include <drm/drm_crtc.h>
#include <drm/drm_panel.h>
+enum panel_type {
+ PANEL_LVDS,
+ PANEL_DPI
+};
+
struct panel_lvds {
struct drm_panel panel;
struct device *dev;
@@ -124,7 +129,9 @@ static int panel_lvds_get_modes(struct drm_panel *panel)
connector->display_info.height_mm = lvds->height;
drm_display_info_set_bus_formats(&connector->display_info,
&lvds->bus_format, 1);
- connector->display_info.bus_flags = lvds->data_mirror
+ drm_bus_flags_from_videomode(&lvds->video_mode,
+ &connector->display_info.bus_flags);
+ connector->display_info.bus_flags |= lvds->data_mirror
? DRM_BUS_FLAG_DATA_LSB_TO_MSB
: DRM_BUS_FLAG_DATA_MSB_TO_LSB;
@@ -145,6 +152,7 @@ static int panel_lvds_parse_dt(struct panel_lvds *lvds)
struct display_timing timing;
const char *mapping;
int ret;
+ enum panel_type type;
ret = of_get_display_timing(np, "panel-timing", &timing);
if (ret < 0)
@@ -174,13 +182,30 @@ static int panel_lvds_parse_dt(struct panel_lvds *lvds)
return -ENODEV;
}
- if (!strcmp(mapping, "jeida-18")) {
- lvds->bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG;
- } else if (!strcmp(mapping, "jeida-24")) {
- lvds->bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA;
- } else if (!strcmp(mapping, "vesa-24")) {
- lvds->bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG;
- } else {
+ type = (enum panel_type)of_device_get_match_data(lvds->dev);
+ switch (type) {
+ case PANEL_LVDS:
+ if (!strcmp(mapping, "jeida-18")) {
+ lvds->bus_format = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG;
+ } else if (!strcmp(mapping, "jeida-24")) {
+ lvds->bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA;
+ } else if (!strcmp(mapping, "vesa-24")) {
+ lvds->bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG;
+ }
+ break;
+ case PANEL_DPI:
+ if (!strcmp(mapping, "rgb24")) {
+ lvds->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+ } else if (!strcmp(mapping, "rgb565")) {
+ lvds->bus_format = MEDIA_BUS_FMT_RGB565_1X16;
+ } else if (!strcmp(mapping, "bgr666")) {
+ lvds->bus_format = MEDIA_BUS_FMT_RGB666_1X18;
+ } else if (!strcmp(mapping, "lvds666")) {
+ lvds->bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI;
+ }
+ };
+
+ if (!lvds->bus_format) {
dev_err(lvds->dev, "%pOF: invalid or missing %s DT property\n",
np, "data-mapping");
return -EINVAL;
@@ -288,7 +313,8 @@ static int panel_lvds_remove(struct platform_device *pdev)
}
static const struct of_device_id panel_lvds_of_table[] = {
- { .compatible = "panel-lvds", },
+ { .compatible = "panel-lvds", .data = (void *)PANEL_LVDS },
+ { .compatible = "panel-dpi", .data = (void *)PANEL_DPI },
{ /* Sentinel */ },
};
@@ -298,7 +324,7 @@ static struct platform_driver panel_lvds_driver = {
.probe = panel_lvds_probe,
.remove = panel_lvds_remove,
.driver = {
- .name = "panel-lvds",
+ .name = "panel-generic",
.of_match_table = panel_lvds_of_table,
},
};
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 15f6cde6452f..0f8f8b1267b0 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -407,7 +407,7 @@ static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx)
dma->chan_using = NULL;
}
-static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)
+static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool atomic)
{
unsigned long orig_jiffies = jiffies;
unsigned int temp;
@@ -437,15 +437,39 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)
"<%s> I2C bus is busy\n", __func__);
return -ETIMEDOUT;
}
- schedule();
+ if (!atomic)
+ schedule();
+ else
+ udelay(100);
}
return 0;
}
-static int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx)
+static int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx, bool atomic)
{
- wait_event_timeout(i2c_imx->queue, i2c_imx->i2csr & I2SR_IIF, HZ / 10);
+ if (!atomic) {
+ wait_event_timeout(i2c_imx->queue, i2c_imx->i2csr & I2SR_IIF, HZ / 10);
+ } else {
+ int counter = 0;
+
+ while (1) {
+ unsigned int reg;
+
+ reg = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
+ i2c_imx->i2csr = reg;
+ if (reg & I2SR_IIF)
+ break;
+
+ if (counter > 1000) {
+ dev_err(&i2c_imx->adapter.dev, "<%s> TXR timeout\n", __func__);
+ return -EIO;
+ }
+ udelay(100);
+ counter++;
+ }
+ imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
+ }
if (unlikely(!(i2c_imx->i2csr & I2SR_IIF))) {
dev_dbg(&i2c_imx->adapter.dev, "<%s> Timeout\n", __func__);
@@ -523,7 +547,7 @@ static int i2c_imx_clk_notifier_call(struct notifier_block *nb,
return NOTIFY_OK;
}
-static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
+static int i2c_imx_start(struct imx_i2c_struct *i2c_imx, bool atomic)
{
unsigned int temp = 0;
int result;
@@ -536,23 +560,32 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx, IMX_I2C_I2CR);
/* Wait controller to be stable */
- usleep_range(50, 150);
+ if (!atomic)
+ usleep_range(50, 150);
+ else
+ udelay(50);
/* Start I2C transaction */
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp |= I2CR_MSTA;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
- result = i2c_imx_bus_busy(i2c_imx, 1);
+ result = i2c_imx_bus_busy(i2c_imx, 1, atomic);
if (result)
return result;
- temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
+ if (!atomic) {
+ temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
+ } else {
+ temp |= I2CR_MTX | I2CR_TXAK;
+ temp &= ~I2CR_IIEN; /* Disable interrupt */
+ }
+
temp &= ~I2CR_DMAEN;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
return result;
}
-static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
+static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx, bool atomic)
{
unsigned int temp = 0;
@@ -574,7 +607,7 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
}
if (!i2c_imx->stopped)
- i2c_imx_bus_busy(i2c_imx, 0);
+ i2c_imx_bus_busy(i2c_imx, 0, atomic);
/* Disable I2C controller */
temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
@@ -655,7 +688,7 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
/* The last data byte must be transferred by the CPU. */
imx_i2c_write_reg(msgs->buf[msgs->len-1],
i2c_imx, IMX_I2C_I2DR);
- result = i2c_imx_trx_complete(i2c_imx);
+ result = i2c_imx_trx_complete(i2c_imx, false);
if (result)
return result;
@@ -714,7 +747,7 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
msgs->buf[msgs->len-2] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
/* read n byte data */
- result = i2c_imx_trx_complete(i2c_imx);
+ result = i2c_imx_trx_complete(i2c_imx, false);
if (result)
return result;
@@ -727,7 +760,7 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp &= ~(I2CR_MSTA | I2CR_MTX);
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
- i2c_imx_bus_busy(i2c_imx, 0);
+ i2c_imx_bus_busy(i2c_imx, 0, false);
} else {
/*
* For i2c master receiver repeat restart operation like:
@@ -745,7 +778,7 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
return 0;
}
-static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
+static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bool atomic)
{
int i, result;
@@ -754,7 +787,7 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
/* write slave address */
imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR);
- result = i2c_imx_trx_complete(i2c_imx);
+ result = i2c_imx_trx_complete(i2c_imx, atomic);
if (result)
return result;
result = i2c_imx_acked(i2c_imx);
@@ -768,7 +801,7 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
"<%s> write byte: B%d=0x%X\n",
__func__, i, msgs->buf[i]);
imx_i2c_write_reg(msgs->buf[i], i2c_imx, IMX_I2C_I2DR);
- result = i2c_imx_trx_complete(i2c_imx);
+ result = i2c_imx_trx_complete(i2c_imx, atomic);
if (result)
return result;
result = i2c_imx_acked(i2c_imx);
@@ -778,7 +811,7 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
return 0;
}
-static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bool is_lastmsg)
+static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bool is_lastmsg, bool atomic)
{
int i, result;
unsigned int temp;
@@ -791,7 +824,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo
/* write slave address */
imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR);
- result = i2c_imx_trx_complete(i2c_imx);
+ result = i2c_imx_trx_complete(i2c_imx, atomic);
if (result)
return result;
result = i2c_imx_acked(i2c_imx);
@@ -824,7 +857,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo
for (i = 0; i < msgs->len; i++) {
u8 len = 0;
- result = i2c_imx_trx_complete(i2c_imx);
+ result = i2c_imx_trx_complete(i2c_imx, atomic);
if (result)
return result;
/*
@@ -852,7 +885,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp &= ~(I2CR_MSTA | I2CR_MTX);
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
- i2c_imx_bus_busy(i2c_imx, 0);
+ i2c_imx_bus_busy(i2c_imx, 0, atomic);
} else {
/*
* For i2c master receiver repeat restart operation like:
@@ -883,8 +916,8 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo
return 0;
}
-static int i2c_imx_xfer(struct i2c_adapter *adapter,
- struct i2c_msg *msgs, int num)
+static int i2c_imx_xfer_common(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs, int num, bool atomic)
{
unsigned int i, temp;
int result;
@@ -898,11 +931,11 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
goto out;
/* Start I2C transfer */
- result = i2c_imx_start(i2c_imx);
+ result = i2c_imx_start(i2c_imx, atomic);
if (result) {
if (i2c_imx->adapter.bus_recovery_info) {
i2c_recover_bus(&i2c_imx->adapter);
- result = i2c_imx_start(i2c_imx);
+ result = i2c_imx_start(i2c_imx, atomic);
}
}
@@ -920,7 +953,7 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
temp |= I2CR_RSTA;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
- result = i2c_imx_bus_busy(i2c_imx, 1);
+ result = i2c_imx_bus_busy(i2c_imx, 1, atomic);
if (result)
goto fail0;
}
@@ -944,13 +977,17 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
(temp & I2SR_SRW ? 1 : 0), (temp & I2SR_IIF ? 1 : 0),
(temp & I2SR_RXAK ? 1 : 0));
#endif
- if (msgs[i].flags & I2C_M_RD)
- result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg);
- else {
- if (i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD)
- result = i2c_imx_dma_write(i2c_imx, &msgs[i]);
- else
- result = i2c_imx_write(i2c_imx, &msgs[i]);
+ if (msgs[i].flags & I2C_M_RD) {
+ result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg, atomic);
+ } else {
+ if (!atomic) {
+ if (i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD)
+ result = i2c_imx_dma_write(i2c_imx, &msgs[i]);
+ else
+ result = i2c_imx_write(i2c_imx, &msgs[i], atomic);
+ } else {
+ result = i2c_imx_write(i2c_imx, &msgs[i], atomic);
+ }
}
if (result)
goto fail0;
@@ -958,7 +995,7 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
fail0:
/* Stop I2C transfer */
- i2c_imx_stop(i2c_imx);
+ i2c_imx_stop(i2c_imx, atomic);
pm_runtime_mark_last_busy(i2c_imx->adapter.dev.parent);
pm_runtime_put_autosuspend(i2c_imx->adapter.dev.parent);
@@ -970,6 +1007,18 @@ out:
return (result < 0) ? result : num;
}
+static int i2c_imx_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs, int num)
+{
+ return i2c_imx_xfer_common(adapter, msgs, num, false);
+}
+
+static int i2c_imx_xfer_atomic(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs, int num)
+{
+ return i2c_imx_xfer_common(adapter, msgs, num, true);
+}
+
static void i2c_imx_prepare_recovery(struct i2c_adapter *adap)
{
struct imx_i2c_struct *i2c_imx;
@@ -1042,8 +1091,9 @@ static u32 i2c_imx_func(struct i2c_adapter *adapter)
}
static const struct i2c_algorithm i2c_imx_algo = {
- .master_xfer = i2c_imx_xfer,
- .functionality = i2c_imx_func,
+ .master_xfer = i2c_imx_xfer,
+ .master_xfer_atomic = i2c_imx_xfer_atomic,
+ .functionality = i2c_imx_func,
};
static int i2c_imx_probe(struct platform_device *pdev)
@@ -1121,6 +1171,14 @@ static int i2c_imx_probe(struct platform_device *pdev)
/* Set up platform driver data */
platform_set_drvdata(pdev, i2c_imx);
+ /*
+ * Driver's PM callbacks are safe to be called in atomic contexts.
+ * Providing this information to the PM subsystem is required for the
+ * 'master_xfer_atomic' implementation that calls PM routines in IRQ
+ * less/atomic contexts.
+ */
+ pm_runtime_irq_safe(&pdev->dev);
+
pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 63dedec0433d..e17054fdd9e0 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -1033,8 +1033,6 @@ static struct phy_driver ksphy_driver[] = {
.get_sset_count = kszphy_get_sset_count,
.get_strings = kszphy_get_strings,
.get_stats = kszphy_get_stats,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
}, {
.phy_id = PHY_ID_KSZ8041RNLI,
.phy_id_mask = MICREL_PHY_ID_MASK,
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index aabf22eaa6b9..b201ad54463f 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -31,6 +31,7 @@
#include <linux/reset.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
+#include <asm/opcodes.h>
#include "pcie-designware.h"
@@ -57,6 +58,7 @@ enum imx6_pcie_variants {
struct imx6_pcie_drvdata {
enum imx6_pcie_variants variant;
u32 flags;
+ int dbi_length;
};
struct imx6_pcie {
@@ -303,8 +305,14 @@ static int imx6q_pcie_abort_handler(unsigned long addr,
unsigned int fsr, struct pt_regs *regs)
{
unsigned long pc = instruction_pointer(regs);
- unsigned long instr = *(unsigned long *)pc;
- int reg = (instr >> 12) & 15;
+ unsigned long instr;
+ int reg;
+
+ if (user_mode(regs))
+ return 1;
+
+ instr = *(unsigned long *)pc;
+ reg = (instr >> 12) & 15;
/*
* If the instruction being executed was a read,
@@ -373,6 +381,59 @@ static int imx6_pcie_attach_pd(struct device *dev)
return 0;
}
+static int imx6q_pcie_abort_handler_thumb2(unsigned long addr,
+ unsigned int fsr, struct pt_regs *regs)
+{
+ unsigned long pc = instruction_pointer(regs);
+ unsigned long instr;
+
+ if (user_mode(regs))
+ return 1;
+
+ instr = __mem_to_opcode_thumb32(*(unsigned long *)pc);
+
+ if (__opcode_is_thumb32(instr)) {
+ /* Load word/byte and halfword immediate offset */
+ if ((instr & 0xff100000UL) == 0xf8100000UL) {
+ int reg = (instr >> 12) & 0xf;
+ unsigned long val;
+
+ if ((instr & 0x00700000UL) == 0x00100000UL)
+ val = 0xff;
+ else if ((instr & 0x00700000UL) == 0x00300000UL)
+ val = 0xffff;
+ else
+ val = 0xffffffffUL;
+
+ regs->uregs[reg] = val;
+ regs->ARM_pc += 4;
+ return 0;
+ }
+ } else {
+ instr = __mem_to_opcode_thumb16(*(unsigned long *)pc);
+
+ /* Load word/byte and halfword immediate offset */
+ if (((instr & 0xe800) == 0x6800) ||
+ ((instr & 0xf800) == 0x8800)) {
+ int reg = instr & 0x7;
+ unsigned long val;
+
+ if (instr & 0x1000)
+ val = 0xff;
+ else if (instr & 0x8000)
+ val = 0xffff;
+ else
+ val = 0xffffffffUL;
+
+ regs->uregs[reg] = val;
+ regs->ARM_pc += 2;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
{
struct device *dev = imx6_pcie->pci->dev;
@@ -1212,6 +1273,7 @@ static const struct imx6_pcie_drvdata drvdata[] = {
.variant = IMX6Q,
.flags = IMX6_PCIE_FLAG_IMX6_PHY |
IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE,
+ .dbi_length = 0x200,
},
[IMX6SX] = {
.variant = IMX6SX,
@@ -1254,9 +1316,42 @@ static struct platform_driver imx6_pcie_driver = {
.shutdown = imx6_pcie_shutdown,
};
+static void imx6_pcie_quirk(struct pci_dev *dev)
+{
+ struct pci_bus *bus = dev->bus;
+ struct pcie_port *pp = bus->sysdata;
+
+ /* Bus parent is the PCI bridge, its parent is this platform driver */
+ if (!bus->dev.parent || !bus->dev.parent->parent)
+ return;
+
+ /* Make sure we only quirk devices associated with this driver */
+ if (bus->dev.parent->parent->driver != &imx6_pcie_driver.driver)
+ return;
+
+ if (bus->number == pp->root_bus_nr) {
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci);
+
+ /*
+ * Limit config length to avoid the kernel reading beyond
+ * the register set and causing an abort on i.MX 6Quad
+ */
+ if (imx6_pcie->drvdata->dbi_length) {
+ dev->cfg_size = imx6_pcie->drvdata->dbi_length;
+ dev_info(&dev->dev, "Limiting cfg_size to %d\n",
+ dev->cfg_size);
+ }
+ }
+}
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_SYNOPSYS, 0xabcd,
+ PCI_CLASS_BRIDGE_PCI, 8, imx6_pcie_quirk);
+
static int __init imx6_pcie_init(void)
{
#ifdef CONFIG_ARM
+ bool thumb2 = IS_ENABLED(CONFIG_THUMB2_KERNEL);
+
/*
* Since probe() can be deferred we need to make sure that
* hook_fault_code is not called after __init memory is freed
@@ -1264,7 +1359,8 @@ static int __init imx6_pcie_init(void)
* we can install the handler here without risking it
* accessing some uninitialized driver state.
*/
- hook_fault_code(8, imx6q_pcie_abort_handler, SIGBUS, 0,
+ hook_fault_code(8, thumb2 ? imx6q_pcie_abort_handler_thumb2 :
+ imx6q_pcie_abort_handler, SIGBUS, 0,
"external abort on non-linefetch");
#endif
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 255786f2e844..c43ad883548a 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -665,6 +665,7 @@ static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "lwn,bk4" },
{ .compatible = "dh,dhcom-board" },
{ .compatible = "menlo,m53cpld" },
+ { .compatible = "toradex,evalspi" },
{},
};
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 57d6e6ba556e..49c622bf2fd3 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -1957,7 +1957,7 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count)
* If the port was already initialised (eg, by a boot loader),
* try to determine the current setup.
*/
-static void __init
+static void
imx_uart_console_get_options(struct imx_port *sport, int *baud,
int *parity, int *bits)
{
@@ -2016,7 +2016,7 @@ imx_uart_console_get_options(struct imx_port *sport, int *baud,
}
}
-static int __init
+static int
imx_uart_console_setup(struct console *co, char *options)
{
struct imx_port *sport;
@@ -2076,7 +2076,7 @@ static struct console imx_uart_console = {
.data = &imx_uart_uart_driver,
};
-#define IMX_CONSOLE &imx_uart_console
+#define IMX_CONSOLE (&imx_uart_console)
#ifdef CONFIG_OF
static void imx_uart_console_early_putchar(struct uart_port *port, int ch)
@@ -2369,8 +2369,17 @@ static int imx_uart_probe(struct platform_device *pdev)
static int imx_uart_remove(struct platform_device *pdev)
{
struct imx_port *sport = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = uart_remove_one_port(&imx_uart_uart_driver, &sport->port);
- return uart_remove_one_port(&imx_uart_uart_driver, &sport->port);
+ if (IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE) && IMX_CONSOLE->index >= 0) {
+ clk_unprepare(sport->clk_ipg);
+ clk_unprepare(sport->clk_per);
+ IMX_CONSOLE->index = -1;
+ }
+
+ return ret;
}
static void imx_uart_restore_context(struct imx_port *sport)