linux/arch/m68k/coldfire/device.c
Greg Ungerer f61e64310b m68k: set dma and coherent masks for platform FEC ethernets
As of commit 205e1b7f51 ("dma-mapping: warn when there is no
coherent_dma_mask") the Freescale FEC driver is issuing the following
warning on driver initialization on ColdFire systems:

WARNING: CPU: 0 PID: 1 at ./include/linux/dma-mapping.h:516 0x40159e20
Modules linked in:
CPU: 0 PID: 1 Comm: swapper Not tainted 4.16.0-rc7-dirty #4
Stack from 41833dd8:
        41833dd8 40259c53 40025534 40279e26 00000003 00000000 4004e514 41827000
        400255de 40244e42 00000204 40159e20 00000009 00000000 00000000 4024531d
        40159e20 40244e42 00000204 00000000 00000000 00000000 00000007 00000000
        00000000 40279e26 4028d040 40226576 4003ae88 40279e26 418273f6 41833ef8
        7fffffff 418273f2 41867028 4003c9a2 4180ac6c 00000004 41833f8c 4013e71c
        40279e1c 40279e26 40226c16 4013ced2 40279e26 40279e58 4028d040 00000000
Call Trace:
        [<40025534>] 0x40025534
 [<4004e514>] 0x4004e514
 [<400255de>] 0x400255de
 [<40159e20>] 0x40159e20
 [<40159e20>] 0x40159e20

It is not fatal, the driver and the system continue to function normally.

As per the warning the coherent_dma_mask is not set on this device.
There is nothing special about the DMA memory coherency on this hardware
so we can just set the mask to 32bits in the platform data for the FEC
ethernet devices.

Signed-off-by: Greg Ungerer <gerg@linux-m68k.org>
2018-03-28 22:27:09 +10:00

537 lines
11 KiB
C

/*
* device.c -- common ColdFire SoC device support
*
* (C) Copyright 2011, Greg Ungerer <gerg@uclinux.org>
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/spi/spi.h>
#include <linux/gpio.h>
#include <linux/fec.h>
#include <asm/traps.h>
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
#include <asm/mcfuart.h>
#include <asm/mcfqspi.h>
/*
* All current ColdFire parts contain from 2, 3, 4 or 10 UARTS.
*/
static struct mcf_platform_uart mcf_uart_platform_data[] = {
{
.mapbase = MCFUART_BASE0,
.irq = MCF_IRQ_UART0,
},
{
.mapbase = MCFUART_BASE1,
.irq = MCF_IRQ_UART1,
},
#ifdef MCFUART_BASE2
{
.mapbase = MCFUART_BASE2,
.irq = MCF_IRQ_UART2,
},
#endif
#ifdef MCFUART_BASE3
{
.mapbase = MCFUART_BASE3,
.irq = MCF_IRQ_UART3,
},
#endif
#ifdef MCFUART_BASE4
{
.mapbase = MCFUART_BASE4,
.irq = MCF_IRQ_UART4,
},
#endif
#ifdef MCFUART_BASE5
{
.mapbase = MCFUART_BASE5,
.irq = MCF_IRQ_UART5,
},
#endif
#ifdef MCFUART_BASE6
{
.mapbase = MCFUART_BASE6,
.irq = MCF_IRQ_UART6,
},
#endif
#ifdef MCFUART_BASE7
{
.mapbase = MCFUART_BASE7,
.irq = MCF_IRQ_UART7,
},
#endif
#ifdef MCFUART_BASE8
{
.mapbase = MCFUART_BASE8,
.irq = MCF_IRQ_UART8,
},
#endif
#ifdef MCFUART_BASE9
{
.mapbase = MCFUART_BASE9,
.irq = MCF_IRQ_UART9,
},
#endif
{ },
};
static struct platform_device mcf_uart = {
.name = "mcfuart",
.id = 0,
.dev.platform_data = mcf_uart_platform_data,
};
#if IS_ENABLED(CONFIG_FEC)
#ifdef CONFIG_M5441x
#define FEC_NAME "enet-fec"
static struct fec_platform_data fec_pdata = {
.phy = PHY_INTERFACE_MODE_RMII,
};
#define FEC_PDATA (&fec_pdata)
#else
#define FEC_NAME "fec"
#define FEC_PDATA NULL
#endif
/*
* Some ColdFire cores contain the Fast Ethernet Controller (FEC)
* block. It is Freescale's own hardware block. Some ColdFires
* have 2 of these.
*/
static struct resource mcf_fec0_resources[] = {
{
.start = MCFFEC_BASE0,
.end = MCFFEC_BASE0 + MCFFEC_SIZE0 - 1,
.flags = IORESOURCE_MEM,
},
{
.start = MCF_IRQ_FECRX0,
.end = MCF_IRQ_FECRX0,
.flags = IORESOURCE_IRQ,
},
{
.start = MCF_IRQ_FECTX0,
.end = MCF_IRQ_FECTX0,
.flags = IORESOURCE_IRQ,
},
{
.start = MCF_IRQ_FECENTC0,
.end = MCF_IRQ_FECENTC0,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device mcf_fec0 = {
.name = FEC_NAME,
.id = 0,
.num_resources = ARRAY_SIZE(mcf_fec0_resources),
.resource = mcf_fec0_resources,
.dev = {
.dma_mask = &mcf_fec0.dev.coherent_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = FEC_PDATA,
}
};
#ifdef MCFFEC_BASE1
static struct resource mcf_fec1_resources[] = {
{
.start = MCFFEC_BASE1,
.end = MCFFEC_BASE1 + MCFFEC_SIZE1 - 1,
.flags = IORESOURCE_MEM,
},
{
.start = MCF_IRQ_FECRX1,
.end = MCF_IRQ_FECRX1,
.flags = IORESOURCE_IRQ,
},
{
.start = MCF_IRQ_FECTX1,
.end = MCF_IRQ_FECTX1,
.flags = IORESOURCE_IRQ,
},
{
.start = MCF_IRQ_FECENTC1,
.end = MCF_IRQ_FECENTC1,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device mcf_fec1 = {
.name = FEC_NAME,
.id = 1,
.num_resources = ARRAY_SIZE(mcf_fec1_resources),
.resource = mcf_fec1_resources,
.dev = {
.dma_mask = &mcf_fec1.dev.coherent_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = FEC_PDATA,
}
};
#endif /* MCFFEC_BASE1 */
#endif /* CONFIG_FEC */
#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
/*
* The ColdFire QSPI module is an SPI protocol hardware block used
* on a number of different ColdFire CPUs.
*/
static struct resource mcf_qspi_resources[] = {
{
.start = MCFQSPI_BASE,
.end = MCFQSPI_BASE + MCFQSPI_SIZE - 1,
.flags = IORESOURCE_MEM,
},
{
.start = MCF_IRQ_QSPI,
.end = MCF_IRQ_QSPI,
.flags = IORESOURCE_IRQ,
},
};
static int mcf_cs_setup(struct mcfqspi_cs_control *cs_control)
{
int status;
status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
if (status) {
pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
goto fail0;
}
status = gpio_direction_output(MCFQSPI_CS0, 1);
if (status) {
pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
goto fail1;
}
status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
if (status) {
pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
goto fail1;
}
status = gpio_direction_output(MCFQSPI_CS1, 1);
if (status) {
pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
goto fail2;
}
status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
if (status) {
pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
goto fail2;
}
status = gpio_direction_output(MCFQSPI_CS2, 1);
if (status) {
pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
goto fail3;
}
#ifdef MCFQSPI_CS3
status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
if (status) {
pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
goto fail3;
}
status = gpio_direction_output(MCFQSPI_CS3, 1);
if (status) {
pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
gpio_free(MCFQSPI_CS3);
goto fail3;
}
#endif
return 0;
fail3:
gpio_free(MCFQSPI_CS2);
fail2:
gpio_free(MCFQSPI_CS1);
fail1:
gpio_free(MCFQSPI_CS0);
fail0:
return status;
}
static void mcf_cs_teardown(struct mcfqspi_cs_control *cs_control)
{
#ifdef MCFQSPI_CS3
gpio_free(MCFQSPI_CS3);
#endif
gpio_free(MCFQSPI_CS2);
gpio_free(MCFQSPI_CS1);
gpio_free(MCFQSPI_CS0);
}
static void mcf_cs_select(struct mcfqspi_cs_control *cs_control,
u8 chip_select, bool cs_high)
{
switch (chip_select) {
case 0:
gpio_set_value(MCFQSPI_CS0, cs_high);
break;
case 1:
gpio_set_value(MCFQSPI_CS1, cs_high);
break;
case 2:
gpio_set_value(MCFQSPI_CS2, cs_high);
break;
#ifdef MCFQSPI_CS3
case 3:
gpio_set_value(MCFQSPI_CS3, cs_high);
break;
#endif
}
}
static void mcf_cs_deselect(struct mcfqspi_cs_control *cs_control,
u8 chip_select, bool cs_high)
{
switch (chip_select) {
case 0:
gpio_set_value(MCFQSPI_CS0, !cs_high);
break;
case 1:
gpio_set_value(MCFQSPI_CS1, !cs_high);
break;
case 2:
gpio_set_value(MCFQSPI_CS2, !cs_high);
break;
#ifdef MCFQSPI_CS3
case 3:
gpio_set_value(MCFQSPI_CS3, !cs_high);
break;
#endif
}
}
static struct mcfqspi_cs_control mcf_cs_control = {
.setup = mcf_cs_setup,
.teardown = mcf_cs_teardown,
.select = mcf_cs_select,
.deselect = mcf_cs_deselect,
};
static struct mcfqspi_platform_data mcf_qspi_data = {
.bus_num = 0,
.num_chipselect = 4,
.cs_control = &mcf_cs_control,
};
static struct platform_device mcf_qspi = {
.name = "mcfqspi",
.id = 0,
.num_resources = ARRAY_SIZE(mcf_qspi_resources),
.resource = mcf_qspi_resources,
.dev.platform_data = &mcf_qspi_data,
};
#endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
#if IS_ENABLED(CONFIG_I2C_IMX)
static struct resource mcf_i2c0_resources[] = {
{
.start = MCFI2C_BASE0,
.end = MCFI2C_BASE0 + MCFI2C_SIZE0 - 1,
.flags = IORESOURCE_MEM,
},
{
.start = MCF_IRQ_I2C0,
.end = MCF_IRQ_I2C0,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device mcf_i2c0 = {
.name = "imx1-i2c",
.id = 0,
.num_resources = ARRAY_SIZE(mcf_i2c0_resources),
.resource = mcf_i2c0_resources,
};
#ifdef MCFI2C_BASE1
static struct resource mcf_i2c1_resources[] = {
{
.start = MCFI2C_BASE1,
.end = MCFI2C_BASE1 + MCFI2C_SIZE1 - 1,
.flags = IORESOURCE_MEM,
},
{
.start = MCF_IRQ_I2C1,
.end = MCF_IRQ_I2C1,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device mcf_i2c1 = {
.name = "imx1-i2c",
.id = 1,
.num_resources = ARRAY_SIZE(mcf_i2c1_resources),
.resource = mcf_i2c1_resources,
};
#endif /* MCFI2C_BASE1 */
#ifdef MCFI2C_BASE2
static struct resource mcf_i2c2_resources[] = {
{
.start = MCFI2C_BASE2,
.end = MCFI2C_BASE2 + MCFI2C_SIZE2 - 1,
.flags = IORESOURCE_MEM,
},
{
.start = MCF_IRQ_I2C2,
.end = MCF_IRQ_I2C2,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device mcf_i2c2 = {
.name = "imx1-i2c",
.id = 2,
.num_resources = ARRAY_SIZE(mcf_i2c2_resources),
.resource = mcf_i2c2_resources,
};
#endif /* MCFI2C_BASE2 */
#ifdef MCFI2C_BASE3
static struct resource mcf_i2c3_resources[] = {
{
.start = MCFI2C_BASE3,
.end = MCFI2C_BASE3 + MCFI2C_SIZE3 - 1,
.flags = IORESOURCE_MEM,
},
{
.start = MCF_IRQ_I2C3,
.end = MCF_IRQ_I2C3,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device mcf_i2c3 = {
.name = "imx1-i2c",
.id = 3,
.num_resources = ARRAY_SIZE(mcf_i2c3_resources),
.resource = mcf_i2c3_resources,
};
#endif /* MCFI2C_BASE3 */
#ifdef MCFI2C_BASE4
static struct resource mcf_i2c4_resources[] = {
{
.start = MCFI2C_BASE4,
.end = MCFI2C_BASE4 + MCFI2C_SIZE4 - 1,
.flags = IORESOURCE_MEM,
},
{
.start = MCF_IRQ_I2C4,
.end = MCF_IRQ_I2C4,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device mcf_i2c4 = {
.name = "imx1-i2c",
.id = 4,
.num_resources = ARRAY_SIZE(mcf_i2c4_resources),
.resource = mcf_i2c4_resources,
};
#endif /* MCFI2C_BASE4 */
#ifdef MCFI2C_BASE5
static struct resource mcf_i2c5_resources[] = {
{
.start = MCFI2C_BASE5,
.end = MCFI2C_BASE5 + MCFI2C_SIZE5 - 1,
.flags = IORESOURCE_MEM,
},
{
.start = MCF_IRQ_I2C5,
.end = MCF_IRQ_I2C5,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device mcf_i2c5 = {
.name = "imx1-i2c",
.id = 5,
.num_resources = ARRAY_SIZE(mcf_i2c5_resources),
.resource = mcf_i2c5_resources,
};
#endif /* MCFI2C_BASE5 */
#endif /* IS_ENABLED(CONFIG_I2C_IMX) */
static struct platform_device *mcf_devices[] __initdata = {
&mcf_uart,
#if IS_ENABLED(CONFIG_FEC)
&mcf_fec0,
#ifdef MCFFEC_BASE1
&mcf_fec1,
#endif
#endif
#if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
&mcf_qspi,
#endif
#if IS_ENABLED(CONFIG_I2C_IMX)
&mcf_i2c0,
#ifdef MCFI2C_BASE1
&mcf_i2c1,
#endif
#ifdef MCFI2C_BASE2
&mcf_i2c2,
#endif
#ifdef MCFI2C_BASE3
&mcf_i2c3,
#endif
#ifdef MCFI2C_BASE4
&mcf_i2c4,
#endif
#ifdef MCFI2C_BASE5
&mcf_i2c5,
#endif
#endif
};
/*
* Some ColdFire UARTs let you set the IRQ line to use.
*/
static void __init mcf_uart_set_irq(void)
{
#ifdef MCFUART_UIVR
/* UART0 interrupt setup */
writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCFSIM_UART1ICR);
writeb(MCF_IRQ_UART0, MCFUART_BASE0 + MCFUART_UIVR);
mcf_mapirq2imr(MCF_IRQ_UART0, MCFINTC_UART0);
/* UART1 interrupt setup */
writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCFSIM_UART2ICR);
writeb(MCF_IRQ_UART1, MCFUART_BASE1 + MCFUART_UIVR);
mcf_mapirq2imr(MCF_IRQ_UART1, MCFINTC_UART1);
#endif
}
static int __init mcf_init_devices(void)
{
mcf_uart_set_irq();
platform_add_devices(mcf_devices, ARRAY_SIZE(mcf_devices));
return 0;
}
arch_initcall(mcf_init_devices);