* [PATCH RFC 1/4] drivers: of: add initialization code for reserved memory
From: Josh Cartwright @ 2014-01-22 18:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417133-6650-1-git-send-email-joshc@codeaurora.org>
From: Marek Szyprowski <m.szyprowski@samsung.com>
This patch adds device tree support for contiguous and reserved memory
regions defined in device tree.
Large memory blocks can be reliably reserved only during early boot.
This must happen before the whole memory management subsystem is
initialized, because we need to ensure that the given contiguous blocks
are not yet allocated by kernel. Also it must happen before kernel
mappings for the whole low memory are created, to ensure that there will
be no mappings (for reserved blocks) or mapping with special properties
can be created (for CMA blocks). This all happens before device tree
structures are unflattened, so we need to get reserved memory layout
directly from fdt.
Later, those reserved memory regions are assigned to devices on each
device structure initialization.
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Laura Abbott <lauraa@codeaurora.org>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
[joshc: rework to implement new DT binding, provide mechanism for
plugging in new reserved-memory node handlers via
RESERVEDMEM_OF_DECLARE]
Signed-off-by: Josh Cartwright <joshc@codeaurora.org>
---
drivers/of/Kconfig | 6 ++
drivers/of/Makefile | 1 +
drivers/of/of_reserved_mem.c | 188 ++++++++++++++++++++++++++++++++++++++
drivers/of/platform.c | 4 +
include/asm-generic/vmlinux.lds.h | 11 +++
include/linux/of_reserved_mem.h | 61 +++++++++++++
6 files changed, 271 insertions(+)
create mode 100644 drivers/of/of_reserved_mem.c
create mode 100644 include/linux/of_reserved_mem.h
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index c6973f1..aba13df 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -75,4 +75,10 @@ config OF_MTD
depends on MTD
def_bool y
+config OF_RESERVED_MEM
+ depends on HAVE_MEMBLOCK
+ def_bool y
+ help
+ Helpers to allow for reservation of memory regions
+
endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index efd0510..ed9660a 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_OF_MDIO) += of_mdio.o
obj-$(CONFIG_OF_PCI) += of_pci.o
obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
obj-$(CONFIG_OF_MTD) += of_mtd.o
+obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
new file mode 100644
index 0000000..9fcafb5
--- /dev/null
+++ b/drivers/of/of_reserved_mem.c
@@ -0,0 +1,188 @@
+/*
+ * Device tree based initialization code for reserved memory.
+ *
+ * Copyright (c) 2013, The Linux Foundation. All Rights Reserved.
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ * Author: Marek Szyprowski <m.szyprowski@samsung.com>
+ * Author: Josh Cartwright <joshc@codeaurora.org>
+ *
+ * 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 Free Software Foundation; either version 2 of the
+ * License or (at your optional) any later version of the license.
+ */
+#include <linux/memblock.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
+#include <linux/mm.h>
+#include <linux/sizes.h>
+#include <linux/of_reserved_mem.h>
+
+#define MAX_RESERVED_REGIONS 16
+static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
+static int reserved_mem_count;
+
+static int __init rmem_default_early_setup(struct reserved_mem *rmem,
+ unsigned long node,
+ const char *uname)
+{
+ unsigned long len;
+ __be32 *prop;
+ int err;
+
+ prop = of_get_flat_dt_prop(node, "reg", &len);
+ if (!prop) {
+ pr_err("reg property missing for reserved-memory node '%s'\n",
+ uname);
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (len < (dt_root_size_cells + dt_root_addr_cells) * sizeof(__be32)) {
+ pr_err("invalid reg property for reserved-memory node '%s'\n",
+ uname);
+ err = -EINVAL;
+ goto out;
+ }
+
+ rmem->base = dt_mem_next_cell(dt_root_addr_cells, &prop);
+ rmem->size = dt_mem_next_cell(dt_root_size_cells, &prop);
+
+ if (of_get_flat_dt_prop(node, "no-map", NULL))
+ err = memblock_remove(rmem->base, rmem->size);
+ else
+ err = memblock_reserve(rmem->base, rmem->size);
+
+ pr_info("Reserved mem: found '%s', memory base %pa, size %ld MiB\n",
+ uname, &rmem->base, (unsigned long)rmem->size / SZ_1M);
+
+out:
+ return err;
+}
+
+static const struct of_device_id rmem_default_id
+ __used __section(__reservedmem_of_table_end) = {
+ .data = rmem_default_early_setup,
+};
+
+static int __init fdt_scan_reserved_mem(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
+ extern const struct of_device_id __reservedmem_of_table[];
+ reservedmem_of_init_fn initfn;
+ const struct of_device_id *id;
+ const char *status;
+
+ if (reserved_mem_count == ARRAY_SIZE(reserved_mem)) {
+ pr_err("Not enough space for reserved-memory regions.\n");
+ return -ENOSPC;
+ }
+
+ status = of_get_flat_dt_prop(node, "status", NULL);
+ if (status && strcmp(status, "okay") != 0)
+ return 0;
+
+ /*
+ * The default handler above ensures this section is terminated with a
+ * id whose compatible string is empty
+ */
+ for (id = __reservedmem_of_table; ; id++) {
+ const char *compat = id->compatible;
+
+ if (!compat[0] || of_flat_dt_is_compatible(node, compat)) {
+ initfn = id->data;
+ break;
+ }
+ }
+
+ if (!initfn(rmem, node, uname)) {
+ strlcpy(rmem->name, uname, sizeof(rmem->name));
+ reserved_mem_count++;
+ }
+
+ return 0;
+}
+
+static struct reserved_mem *find_rmem(struct device_node *np)
+{
+ const char *name;
+ unsigned int i;
+
+ name = kbasename(np->full_name);
+
+ for (i = 0; i < reserved_mem_count; i++)
+ if (strcmp(name, reserved_mem[i].name) == 0)
+ return &reserved_mem[i];
+
+ return NULL;
+}
+
+/**
+ * of_reserved_mem_device_init() - assign reserved memory region to given device
+ *
+ * This function assign memory region pointed by "memory-region" device tree
+ * property to the given device.
+ */
+void of_reserved_mem_device_init(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct reserved_mem *rmem;
+ struct of_phandle_args s;
+ unsigned int i;
+
+ for (i = 0; of_parse_phandle_with_args(np, "memory-region",
+ "#memory-region-cells", i, &s) == 0; i++) {
+
+ rmem = find_rmem(s.np);
+ of_node_put(s.np);
+
+ if (!rmem || !rmem->ops || !rmem->ops->device_init)
+ continue;
+
+ rmem->ops->device_init(rmem, pdev, &s);
+ }
+}
+
+/**
+ * of_reserved_mem_device_release() - release reserved memory device structures
+ *
+ * This function releases structures allocated for memory region handling for
+ * the given device.
+ */
+void of_reserved_mem_device_release(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct reserved_mem *rmem;
+ struct of_phandle_args s;
+ unsigned int i;
+
+ for (i = 0; of_parse_phandle_with_args(np, "memory-region",
+ "#memory-region-cells", i, &s) == 0; i++) {
+
+ rmem = find_rmem(s.np);
+ of_node_put(s.np);
+
+ if (!rmem || !rmem->ops || !rmem->ops->device_release)
+ continue;
+
+ rmem->ops->device_release(rmem, pdev);
+ }
+}
+
+/**
+ * early_init_dt_scan_reserved_mem() - create reserved memory regions
+ *
+ * This function grabs memory from early allocator for device exclusive use
+ * defined in device tree structures. It should be called by arch specific code
+ * once the early allocator (memblock) has been activated and all other
+ * subsystems have already allocated/reserved memory.
+ */
+void __init early_init_dt_scan_reserved_mem(void)
+{
+ of_scan_flat_dt_by_path("/reserved-memory", fdt_scan_reserved_mem,
+ NULL);
+}
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 404d1da..b6d3cea 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -21,6 +21,7 @@
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
const struct of_device_id of_default_bus_match_table[] = {
@@ -220,6 +221,8 @@ static struct platform_device *of_platform_device_create_pdata(
dev->dev.bus = &platform_bus_type;
dev->dev.platform_data = platform_data;
+ of_reserved_mem_device_init(dev);
+
/* We do not fill the DMA ops for platform devices by default.
* This is currently the responsibility of the platform code
* to do such, possibly using a device notifier
@@ -227,6 +230,7 @@ static struct platform_device *of_platform_device_create_pdata(
if (of_device_add(dev) != 0) {
platform_device_put(dev);
+ of_reserved_mem_device_release(dev);
return NULL;
}
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index bc2121f..f10f64f 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -167,6 +167,16 @@
#define CLK_OF_TABLES()
#endif
+#ifdef CONFIG_OF_RESERVED_MEM
+#define RESERVEDMEM_OF_TABLES() \
+ . = ALIGN(8); \
+ VMLINUX_SYMBOL(__reservedmem_of_table) = .; \
+ *(__reservedmem_of_table) \
+ *(__reservedmem_of_table_end)
+#else
+#define RESERVEDMEM_OF_TABLES()
+#endif
+
#define KERNEL_DTB() \
STRUCT_ALIGN(); \
VMLINUX_SYMBOL(__dtb_start) = .; \
@@ -490,6 +500,7 @@
TRACE_SYSCALLS() \
MEM_DISCARD(init.rodata) \
CLK_OF_TABLES() \
+ RESERVEDMEM_OF_TABLES() \
CLKSRC_OF_TABLES() \
KERNEL_DTB() \
IRQCHIP_OF_MATCH_TABLE()
diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h
new file mode 100644
index 0000000..a2de510
--- /dev/null
+++ b/include/linux/of_reserved_mem.h
@@ -0,0 +1,61 @@
+#ifndef __OF_RESERVED_MEM_H
+#define __OF_RESERVED_MEM_H
+
+struct cma;
+struct platform_device;
+struct of_phandle_args;
+struct reserved_mem_ops;
+
+struct reserved_mem {
+ const struct reserved_mem_ops *ops;
+ char name[32];
+ union {
+ struct cma *cma;
+ struct {
+ phys_addr_t base;
+ phys_addr_t size;
+ };
+ };
+};
+
+struct reserved_mem_ops {
+ void (*device_init)(struct reserved_mem *rmem,
+ struct platform_device *pdev,
+ struct of_phandle_args *args);
+ void (*device_release)(struct reserved_mem *rmem,
+ struct platform_device *pdev);
+};
+
+typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem,
+ unsigned long node, const char *uname);
+
+#ifdef CONFIG_OF_RESERVED_MEM
+void of_reserved_mem_device_init(struct platform_device *pdev);
+void of_reserved_mem_device_release(struct platform_device *pdev);
+void early_init_dt_scan_reserved_mem(void);
+
+#define RESERVEDMEM_OF_DECLARE(name, compat, init) \
+ static const struct of_device_id __reservedmem_of_table_##name \
+ __used __section(__reservedmem_of_table) \
+ = { .compatible = compat, \
+ .data = (init == (reservedmem_of_init_fn)NULL) ? \
+ init : init }
+
+#else
+static inline void of_reserved_mem_device_init(struct platform_device *pdev) { }
+
+static inline
+void of_reserved_mem_device_release(struct platform_device *pdev) { }
+
+static inline void early_init_dt_scan_reserved_mem(void) { }
+
+#define RESERVEDMEM_OF_DECLARE(name, compat, init) \
+ static const struct of_device_id __reservedmem_of_table_##name \
+ __attribute__((unused)) \
+ = { .compatible = compat, \
+ .data = (init == (reservedmem_of_init_fn)NULL) ? \
+ init : init }
+
+#endif
+
+#endif /* __OF_RESERVED_MEM_H */
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply related
* [PATCH RFC 2/4] drivers: of: implement reserved-memory handling for dma
From: Josh Cartwright @ 2014-01-22 18:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417133-6650-1-git-send-email-joshc@codeaurora.org>
Add support for handling 'shared-dma-pool' reserved-memory nodes.
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Laura Abbott <lauraa@codeaurora.org>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Josh Cartwright <joshc@codeaurora.org>
---
drivers/of/Kconfig | 7 ++
drivers/of/Makefile | 1 +
drivers/of/of_reserved_mem_dma.c | 178 +++++++++++++++++++++++++++++++++++++++
3 files changed, 186 insertions(+)
create mode 100644 drivers/of/of_reserved_mem_dma.c
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index aba13df..ca58fb3e 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -81,4 +81,11 @@ config OF_RESERVED_MEM
help
Helpers to allow for reservation of memory regions
+config OF_RESERVED_MEM_DMA
+ depends on OF_RESERVED_MEM
+ depends on DMA_CMA || HAVE_GENERIC_DMA_COHERENT
+ def_bool y
+ help
+ Helpers for reserving memory regions for DMA use
+
endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index ed9660a..6142227 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_OF_PCI) += of_pci.o
obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
obj-$(CONFIG_OF_MTD) += of_mtd.o
obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
+obj-$(CONFIG_OF_RESERVED_MEM_DMA) += of_reserved_mem_dma.o
diff --git a/drivers/of/of_reserved_mem_dma.c b/drivers/of/of_reserved_mem_dma.c
new file mode 100644
index 0000000..e24f02d
--- /dev/null
+++ b/drivers/of/of_reserved_mem_dma.c
@@ -0,0 +1,178 @@
+/*
+ * Device tree based initialization code for DMA reserved regions.
+ *
+ * Copyright (c) 2013, The Linux Foundation. All Rights Reserved.
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ * Author: Marek Szyprowski <m.szyprowski@samsung.com>
+ * Author: Josh Cartwright <joshc@codeaurora.org>
+ *
+ * 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 Free Software Foundation; either version 2 of the
+ * License or (at your optional) any later version of the license.
+ */
+#include <linux/memblock.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
+#include <linux/mm.h>
+#include <linux/sizes.h>
+#include <linux/mm_types.h>
+#include <linux/dma-contiguous.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_reserved_mem.h>
+
+static void rmem_dma_device_init(struct reserved_mem *rmem,
+ struct platform_device *pdev,
+ struct of_phandle_args *args)
+{
+ dma_declare_coherent_memory(&pdev->dev, rmem->base, rmem->base,
+ rmem->size, DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE);
+}
+
+static void rmem_dma_device_release(struct reserved_mem *rmem,
+ struct platform_device *pdev)
+{
+ dma_release_declared_memory(&pdev->dev);
+}
+
+static const struct reserved_mem_ops rmem_dma_ops = {
+ .device_init = rmem_dma_device_init,
+ .device_release = rmem_dma_device_release,
+};
+
+static int __init rmem_dma_get_reg(unsigned long node, const char *uname,
+ phys_addr_t *base, phys_addr_t *size)
+{
+ unsigned long len;
+ __be32 *prop;
+
+ prop = of_get_flat_dt_prop(node, "reg", &len);
+ if (!prop)
+ return -EINVAL;
+
+ if (len < (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32)) {
+ pr_err("Malformed 'shared-dma-pool' reserved-mem node '%s'.\n",
+ uname);
+ return -EINVAL;
+ }
+
+ *base = dt_mem_next_cell(dt_root_addr_cells, &prop);
+ *size = dt_mem_next_cell(dt_root_size_cells, &prop);
+ return 0;
+}
+
+static int __init rmem_dma_get_size(unsigned long node, const char *uname,
+ phys_addr_t *size)
+{
+ unsigned long len;
+ __be32 *prop;
+
+ prop = of_get_flat_dt_prop(node, "size", &len);
+ if (!prop)
+ return -EINVAL;
+
+ if (len < dt_root_size_cells * sizeof(__be32)) {
+ pr_err("Malformed 'shared-dma-pool' reserved-mem node '%s'.\n",
+ uname);
+ return -EINVAL;
+ }
+
+ *size = dt_mem_next_cell(dt_root_size_cells, &prop);
+ return 0;
+}
+
+static void rmem_cma_device_init(struct reserved_mem *rmem,
+ struct platform_device *pdev,
+ struct of_phandle_args *args)
+{
+ dev_set_cma_area(&pdev->dev, rmem->cma);
+}
+
+static const struct reserved_mem_ops rmem_cma_ops = {
+ .device_init = rmem_cma_device_init,
+};
+
+static int __init rmem_cma_reserve_area(struct reserved_mem *rmem,
+ unsigned long node, const char *uname)
+{
+ int err;
+
+ err = dma_contiguous_reserve_area(rmem->size, rmem->base, 0,
+ &rmem->cma);
+ if (err) {
+ pr_err("Unable to setup CMA reserved-mem region for '%s'.\n",
+ uname);
+ return err;
+ }
+
+ if (of_get_flat_dt_prop(node, "linux,cma-default", NULL))
+ dma_contiguous_set_default(rmem->cma);
+
+ rmem->ops = &rmem_cma_ops;
+ return 0;
+}
+
+static int __init rmem_cma_setup(struct reserved_mem *rmem,
+ unsigned long node,
+ const char *uname)
+{
+ int err;
+
+ err = rmem_dma_get_reg(node, uname, &rmem->base, &rmem->size);
+ if (!err)
+ goto out_done;
+
+ rmem->base = 0;
+ err = rmem_dma_get_size(node, uname, &rmem->size);
+ if (err)
+ goto out_err;
+
+out_done:
+ return rmem_cma_reserve_area(rmem, node, uname);
+
+out_err:
+ pr_err("Malformed 'shared-dma-pool' node '%s'.\n", uname);
+ return err;
+}
+
+static int __init rmem_dma_excl_setup(struct reserved_mem *rmem,
+ unsigned long node,
+ const char *uname)
+{
+ int err;
+
+ err = rmem_dma_get_reg(node, uname, &rmem->base, &rmem->size);
+ if (!err)
+ goto out_done;
+
+ err = rmem_dma_get_size(node, uname, &rmem->size);
+ if (err)
+ goto out_err;
+
+ rmem->base = memblock_alloc_base(rmem->size, PAGE_SIZE,
+ MEMBLOCK_ALLOC_ANYWHERE);
+ memblock_free(rmem->base, rmem->size);
+
+out_done:
+ rmem->ops = &rmem_dma_ops;
+ return memblock_remove(rmem->base, rmem->size);
+
+out_err:
+ pr_err("Unable to setup reserved-mem region '%s' for DMA.\n", uname);
+ return err;
+}
+
+static int __init rmem_dma_setup(struct reserved_mem *rmem,
+ unsigned long node,
+ const char *uname)
+{
+ if (IS_ENABLED(CONFIG_DMA_CMA) &&
+ of_get_flat_dt_prop(node, "reusable", NULL))
+ return rmem_cma_setup(rmem, node, uname);
+
+ return rmem_dma_excl_setup(rmem, node, uname);
+}
+RESERVEDMEM_OF_DECLARE(dma, "shared-dma-pool", rmem_dma_setup);
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply related
* [PATCH RFC 3/4] ARM: init: add support for reserved memory defined by device tree
From: Josh Cartwright @ 2014-01-22 18:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417133-6650-1-git-send-email-joshc@codeaurora.org>
From: Marek Szyprowski <m.szyprowski@samsung.com>
Enable reserved memory initialization from device tree.
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Laura Abbott <lauraa@codeaurora.org>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
arch/arm/mm/init.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 403ba90..5efe0b4 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -17,6 +17,7 @@
#include <linux/nodemask.h>
#include <linux/initrd.h>
#include <linux/of_fdt.h>
+#include <linux/of_reserved_mem.h>
#include <linux/highmem.h>
#include <linux/gfp.h>
#include <linux/memblock.h>
@@ -323,6 +324,8 @@ void __init arm_memblock_init(struct meminfo *mi,
if (mdesc->reserve)
mdesc->reserve();
+ early_init_dt_scan_reserved_mem();
+
/*
* reserve memory for DMA contigouos allocations,
* must come from DMA area inside low memory
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply related
* [PATCH RFC 4/4] of: document bindings for reserved-memory nodes
From: Josh Cartwright @ 2014-01-22 18:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417133-6650-1-git-send-email-joshc@codeaurora.org>
From: Grant Likely <grant.likely@linaro.org>
Reserved memory nodes allow for the reservation of static (fixed
address) regions, or dynamically allocated regions for a specific
purpose.
[joshc: Based on binding document proposed (in non-patch form) here:
http://lkml.kernel.org/g/20131030134702.19B57C402A0 at trevor.secretlab.ca
adapted to support #memory-region-cells]
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Laura Abbott <lauraa@codeaurora.org>
Signed-off-by: Josh Cartwright <joshc@codeaurora.org>
---
Hey Grant-
Seeing as you are the primary author of this binding, with only a few minor
changes on my part, I've marked you as the commit author. Let me know if
that's a problem.
Josh
.../bindings/reserved-memory/reserved-memory.txt | 137 +++++++++++++++++++++
1 file changed, 137 insertions(+)
create mode 100644 Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
diff --git a/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
new file mode 100644
index 0000000..7cd7829
--- /dev/null
+++ b/Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt
@@ -0,0 +1,137 @@
+*** Reserved memory regions ***
+
+Reserved memory is specified as a node under the /reserved-memory node.
+The operating system shall exclude reserved memory from normal usage
+one can create child nodes describing particular reserved (excluded from
+normal use) memory regions. Such memory regions are usually designed for
+the special usage by various device drivers.
+
+Parameters for each memory region can be encoded into the device tree
+with the following nodes:
+
+/reserved-memory node
+---------------------
+#address-cells, #size-cells (required) - standard definition
+ - Should use the same values as the root node
+#memory-region-cells (required) - dictates number of cells used in the child
+ nodes memory-region specifier
+ranges (required) - standard definition
+ - Should be empty
+
+/reserved-memory/ child nodes
+-----------------------------
+Each child of the reserved-memory node specifies one or more regions of
+reserved memory. Each child node may either use a 'reg' property to
+specify a specific range of reserved memory, or a 'size' property with
+optional constraints to request a dynamically allocated block of memory.
+
+Following the generic-names recommended practice, node names should
+reflect the purpose of the node (ie. "framebuffer" or "dma-pool"). Unit
+address (@<address>) should be appended to the name if the node is a
+static allocation.
+
+Properties:
+Requires either a) or b) below.
+a) static allocation
+ reg (required) - standard definition
+b) dynamic allocation
+ size (required) - length based on parent's #size-cells
+ - Size in bytes of memory to reserve.
+ alignment (optional) - length based on parent's #size-cells
+ - Address boundary for alignment of allocation.
+ alloc-ranges (optional) - prop-encoded-array (address, length pairs).
+ - Specifies regions of memory that are
+ acceptable to allocate from.
+
+If both reg and size are present, then the reg property takes precedence
+and size is ignored.
+
+Additional properties:
+compatible (optional) - standard definition
+ - may contain the following strings:
+ - shared-dma-pool: This indicates a region of memory meant to be
+ used as a shared pool of DMA buffers for a set of devices. It can
+ be used by an operating system to instanciate the necessary pool
+ management subsystem if necessary.
+ - vendor specific string in the form <vendor>,[<device>-]<usage>
+no-map (optional) - empty property
+ - Indicates the operating system must not create a virtual mapping
+ of the region as part of its standard mapping of system memory,
+ nor permit speculative access to it under any circumstances other
+ than under the control of the device driver using the region.
+reusable (optional) - empty property
+ - The operating system can use the memory in this region with the
+ limitation that the device driver(s) owning the region need to be
+ able to reclaim it back. Typically that means that the operating
+ system can use that region to store volatile or cached data that
+ can be otherwise regenerated or migrated elsewhere.
+
+Linux implementation note:
+- If a "linux,cma-default" property is present, then Linux will use the
+ region for the default pool of the contiguous memory allocator.
+
+Device node references to reserved memory
+-----------------------------------------
+Regions in the /reserved-memory node may be referenced by other device
+nodes by adding a memory-region property to the device node.
+
+memory-region (optional) - phandle, specifier pairs to children of /reserved-memory
+
+Example
+-------
+This example defines 3 contiguous regions are defined for Linux kernel:
+one default of all device drivers (named linux,cma at 72000000 and 64MiB in size),
+one dedicated to the framebuffer device (named framebuffer at 78000000, 8MiB), and
+one for multimedia processing (named multimedia-memory at 77000000, 64MiB).
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ memory {
+ reg = <0x40000000 0x40000000>;
+ };
+
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ /* global autoconfigured region for contiguous allocations */
+ linux,cma {
+ compatible = "shared-dma-pool";
+ #memory-region-cells = <0>;
+ size = <0x4000000>;
+ alignment = <0x2000>;
+ linux,cma-default;
+ };
+
+ display_reserved: framebuffer at 78000000 {
+ #memory-region-cells = <0>;
+ reg = <0x78000000 0x800000>;
+ };
+
+ multimedia_reserved: multimedia at 77000000 {
+ compatible = "acme,multimedia-memory";
+ #memory-region-cells = <1>;
+ reg = <0x77000000 0x4000000>;
+ };
+ };
+
+ /* ... */
+
+ fb0: video at 12300000 {
+ memory-region = <&display_reserved>;
+ /* ... */
+ };
+
+ scaler: scaler at 12500000 {
+ memory-region = <&multimedia_reserved 0xdeadbeef>;
+ /* ... */
+ };
+
+ codec: codec at 12600000 {
+ memory-region = <&multimedia_reserved 0xfeebdaed>;
+ /* ... */
+ };
+};
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply related
* [PATCH v2 0/5] ARM: add omap3 INCOstartec board support
From: Christoph Fritz @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
This set of patches adds board support for an omap3 system from INCOstartec.
It's based on next-20140122.
Previously it was based on next-20140115. There, everything works as expected.
On branch git://git.linaro.org/people/ulf.hansson/clk.git linaro_clk/clk-next
which holdes all "clock DT conversion" commits, bootlog shows these abnormalities:
[ 0.559600] ------------[ cut here ]------------
[ 0.559631] WARNING: CPU: 0 PID: 1 at /home/honschu/media/linux/drivers/video/omap2/dss/dss.c:540 dss_set_clock_div+0xac/0xcc()
[ 0.559661] clk rate mismatch: 345600000 != 172800000
[ 0.559661] Modules linked in:
[ 0.559692] CPU: 0 PID: 1 Comm: swapper Not tainted 3.13.0-rc7+ 0
[ 0.559722] [<c0012fc4>] (unwind_backtrace+0x0/0xf8) from [<c0010e10>] (show_stack+0x10/0x14)
[ 0.559753] [<c0010e10>] (show_stack+0x10/0x14) from [<c0033fdc>] (warn_slowpath_common+0x64/0x84)
[ 0.559783] [<c0033fdc>] (warn_slowpath_common+0x64/0x84) from [<c0034090>] (warn_slowpath_fmt+0x30/0x40)
[ 0.559814] [<c0034090>] (warn_slowpath_fmt+0x30/0x40) from [<c02b23c0>] (dss_set_clock_div+0xac/0xcc)
[ 0.559844] [<c02b23c0>] (dss_set_clock_div+0xac/0xcc) from [<c0778f48>] (omap_dsshw_probe+0x1ec/0x2e0)
[ 0.559875] [<c0778f48>] (omap_dsshw_probe+0x1ec/0x2e0) from [<c02ff360>] (platform_drv_probe+0x18/0x48)
[ 0.559906] [<c02ff360>] (platform_drv_probe+0x18/0x48) from [<c02fdf84>] (driver_probe_device+0x110/0x230)
[ 0.559936] [<c02fdf84>] (driver_probe_device+0x110/0x230) from [<c02fe138>] (__driver_attach+0x94/0x98)
[ 0.559967] [<c02fe138>] (__driver_attach+0x94/0x98) from [<c02fc724>] (bus_for_each_dev+0x54/0x88)
[ 0.559997] [<c02fc724>] (bus_for_each_dev+0x54/0x88) from [<c02fd720>] (bus_add_driver+0xd4/0x1d0)
[ 0.559997] [<c02fd720>] (bus_add_driver+0xd4/0x1d0) from [<c02fe76c>] (driver_register+0x78/0xf4)
[ 0.560028] [<c02fe76c>] (driver_register+0x78/0xf4) from [<c02ff2c4>] (platform_driver_probe+0x20/0xa4)
[ 0.560058] [<c02ff2c4>] (platform_driver_probe+0x20/0xa4) from [<c0778ce0>] (omap_dss_init+0x1c/0x98)
[ 0.560089] [<c0778ce0>] (omap_dss_init+0x1c/0x98) from [<c0008828>] (do_one_initcall+0xe4/0x144)
[ 0.560119] [<c0008828>] (do_one_initcall+0xe4/0x144) from [<c075eadc>] (kernel_init_freeable+0xe8/0x1b0)
[ 0.560150] [<c075eadc>] (kernel_init_freeable+0xe8/0x1b0) from [<c05522bc>] (kernel_init+0x8/0x118)
[ 0.560180] [<c05522bc>] (kernel_init+0x8/0x118) from [<c000e4c8>] (ret_from_fork+0x14/0x2c)
[ 0.560302] ---[ end trace 187e8d9dd0655394 ]---
[ 0.560424] OMAP DSS rev 2.0
--snip--
[ 2.601745] usb 1-1: new high-speed USB device number 2 using ehci-omap
[ 2.767059] usb 1-1: device descriptor read/64, error -71
[ 3.007934] usb 1-1: device descriptor read/64, error -71
[ 3.237091] usb 1-1: new high-speed USB device number 3 using ehci-omap
[ 3.387054] usb 1-1: device descriptor read/64, error -71
[ 3.637054] usb 1-1: device descriptor read/64, error -71
[ 3.867065] usb 1-1: new high-speed USB device number 4 using ehci-omap
[ 4.296966] usb 1-1: device not accepting address 4, error -71
[ 4.417053] usb 1-1: new high-speed USB device number 5 using ehci-omap
[ 4.846954] usb 1-1: device not accepting address 5, error -71
[ 4.853179] hub 1-0:1.0: unable to enumerate USB device on port 1
[ 5.217041] usb 2-1: new full-speed USB device number 2 using ohci-omap3
[ 5.407043] usb 2-1: device descriptor read/64, error -62
[ 5.697052] usb 2-1: device descriptor read/64, error -62
[ 5.987060] usb 2-1: new full-speed USB device number 3 using ohci-omap3
[ 6.066955] .[ 6.177062] usb 2-1: device descriptor read/64, error -62
[ 6.467041] usb 2-1: device descriptor read/64, error -62
[ 6.757049] usb 2-1: new full-speed USB device number 4 using ohci-omap3
[ 7.176971] usb 2-1: device not accepting address 4, error -62
[ 7.357055] usb 2-1: new full-speed USB device number 5 using ohci-omap3
[ 7.776977] usb 2-1: device not accepting address 5, error -62
[ 7.783233] hub 2-0:1.0: unable to enumerate USB device on port 1
On next-20140122 the tps65930 (which should be compatible to twl4030) doesn't
set voltage on IO.1P8 any more which leads to a lot of external subsystem
failings like dss:
[ 0.602264] omapdss_dss: probe of omapdss_dss failed with error -22
[ 0.602691] omapdss CORE error: Failed to initialize DSS platform driver
[ 0.603240] panel-dpi panel-dpi.0: failed to find video source 'dpi.0'
Changes compared to previous version:
- rebased on next-20140122 from next-20140115
- using omap36xx.dtsi instead of unsupported 1ghz omap37xx100
Christoph Fritz (5):
ARM: dts: omap3: Add support for INCOstartec a83x module
ARM: dts: omap3: Add support for INCOstartec DBB056 baseboard
ARM: OMAP2+: add legacy display for omap3 DBB056
ARM: OMAP2+: Add pdata quirk for sys_clkout2 for omap3 DBB056
[RFC] omapdss: remove FEAT_DPI_USES_VDDS_DSI from omap3
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/omap3-lilly-a83x.dtsi | 445 ++++++++++++++++++++++++++++++
arch/arm/boot/dts/omap3-lilly-dbb056.dts | 160 +++++++++++
arch/arm/mach-omap2/dss-common.c | 49 ++++
arch/arm/mach-omap2/dss-common.h | 1 +
arch/arm/mach-omap2/pdata-quirks.c | 44 ++-
drivers/video/omap2/dss/dss_features.c | 1 -
7 files changed, 699 insertions(+), 2 deletions(-)
create mode 100644 arch/arm/boot/dts/omap3-lilly-a83x.dtsi
create mode 100644 arch/arm/boot/dts/omap3-lilly-dbb056.dts
--
1.7.10.4
^ permalink raw reply
* [PATCH v2 1/5] ARM: dts: omap3: Add support for INCOstartec a83x module
From: Christoph Fritz @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417460-3134-1-git-send-email-chf.fritz@googlemail.com>
INCOstartec LILLY-A83X module is a TI DM3730xx100 (OMAP3) SoC
computer-on-module.
This patch adds device tree support for most of its features.
Signed-off-by: Christoph Fritz <chf.fritz@googlemail.com>
---
arch/arm/boot/dts/omap3-lilly-a83x.dtsi | 445 +++++++++++++++++++++++++++++++
1 file changed, 445 insertions(+)
create mode 100644 arch/arm/boot/dts/omap3-lilly-a83x.dtsi
diff --git a/arch/arm/boot/dts/omap3-lilly-a83x.dtsi b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
new file mode 100644
index 0000000..5e2137a
--- /dev/null
+++ b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2014 Christoph Fritz <chf.fritzc@googlemail.com>
+ *
+ * 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 Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "omap36xx.dtsi"
+
+/ {
+ model = "INCOstartec LILLY-A83X module (DM3730)";
+ compatible = "incostartec,omap3-lilly-a83x", "ti,omap36xx", "ti,omap3";
+
+ chosen {
+ bootargs = "console=ttyO0,115200n8 vt.global_cursor_default=0 consoleblank=0";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x8000000>; /* 128 MB */
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ heartbeat1 {
+ label = "lilly-a83x::led1";
+ gpios = <&gpio1 29 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-on";
+ };
+
+ };
+
+ sound {
+ compatible = "ti,omap-twl4030";
+ ti,model = "lilly-a83x";
+
+ ti,mcbsp = <&mcbsp2>;
+ ti,codec = <&twl_audio>;
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ reg_vcc3: vcc3 {
+ compatible = "regulator-fixed";
+ regulator-name = "VCC3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+ };
+
+ hsusb1_phy: hsusb1_phy {
+ compatible = "usb-nop-xceiv";
+ vcc-supply = <®_vcc3>;
+ };
+};
+
+&omap3_pmx_wkup {
+ pinctrl-names = "default";
+
+ lan9221_pins: pinmux_lan9221_pins {
+ pinctrl-single,pins = <
+ 0x5A (PIN_INPUT | MUX_MODE4) /* gpio_129 */
+ >;
+ };
+
+ tsc2048_pins: pinmux_tsc2048_pins {
+ pinctrl-single,pins = <
+ 0x16 (PIN_INPUT_PULLUP | MUX_MODE4) /* gpio_8 */
+ >;
+ };
+
+ mmc1cd_pins: pinmux_mmc1cd_pins {
+ pinctrl-single,pins = <
+ 0x56 (PIN_INPUT | MUX_MODE4) /* gpio_126 */
+ >;
+ };
+};
+
+&omap3_pmx_core {
+ pinctrl-names = "default";
+
+ gpio1_pins: pinmux_gpio1_pins {
+ pinctrl-single,pins = <
+ 0x5ca (PIN_OUTPUT_PULLDOWN | MUX_MODE4) /* gpio_29 */
+ >;
+ };
+
+ uart1_pins: pinmux_uart1_pins {
+ pinctrl-single,pins = <
+ 0x14c (PIN_OUTPUT | MUX_MODE0) /* uart1_tx.uart1_tx */
+ 0x14e (PIN_OUTPUT | MUX_MODE0) /* uart1_rts.uart1_rts */
+ 0x150 (PIN_INPUT | MUX_MODE0) /* uart1_cts.uart1_cts */
+ 0x152 (PIN_INPUT | MUX_MODE0) /* uart1_rx.uart1_rx */
+ >;
+ };
+
+ uart2_pins: pinmux_uart2_pins {
+ pinctrl-single,pins = <
+ 0x140 (PIN_OUTPUT | MUX_MODE1) /* mcbsp3_clkx.uart2_tx */
+ 0x142 (PIN_INPUT | MUX_MODE1) /* mcbsp3_fsx.uart2_rx */
+ >;
+ };
+
+ uart3_pins: pinmux_uart3_pins {
+ pinctrl-single,pins = <
+ 0x16e (PIN_INPUT | MUX_MODE0) /* uart3_rx_irrx.uart3_rx_irrx */
+ 0x170 (PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */
+ >;
+ };
+
+ i2c1_pins: pinmux_i2c1_pins {
+ pinctrl-single,pins = <
+ 0x18a (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_scl */
+ 0x18c (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_sda */
+ >;
+ };
+
+ i2c2_pins: pinmux_i2c2_pins {
+ pinctrl-single,pins = <
+ 0x18e (PIN_INPUT | MUX_MODE0) /* i2c2_scl.i2c2_scl */
+ 0x190 (PIN_INPUT | MUX_MODE0) /* i2c2_sda.i2c2_sda */
+ >;
+ };
+
+ i2c3_pins: pinmux_i2c3_pins {
+ pinctrl-single,pins = <
+ 0x192 (PIN_INPUT | MUX_MODE0) /* i2c3_scl.i2c3_scl */
+ 0x194 (PIN_INPUT | MUX_MODE0) /* i2c3_sda.i2c3_sda */
+ >;
+ };
+
+ hsusb1_pins: pinmux_hsusb1_pins {
+ pinctrl-single,pins = <
+ 0x5a8 (PIN_OUTPUT | MUX_MODE3) /* etk_clk.hsusb1_stp */
+ 0x5aa (PIN_INPUT | MUX_MODE3) /* etk_ctl.hsusb1_clk */
+ 0x5ac (PIN_INPUT | MUX_MODE3) /* etk_d0.hsusb1_data0 */
+ 0x5ae (PIN_INPUT | MUX_MODE3) /* etk_d1.hsusb1_data1 */
+ 0x5b0 (PIN_INPUT | MUX_MODE3) /* etk_d2.hsusb1_data2 */
+ 0x5b2 (PIN_INPUT | MUX_MODE3) /* etk_d3.hsusb1_data7 */
+ 0x5b4 (PIN_INPUT | MUX_MODE3) /* etk_d4.hsusb1_data4 */
+ 0x5b6 (PIN_INPUT | MUX_MODE3) /* etk_d5.hsusb1_data5 */
+ 0x5b8 (PIN_INPUT | MUX_MODE3) /* etk_d6.hsusb1_data6 */
+ 0x5ba (PIN_INPUT | MUX_MODE3) /* etk_d7.hsusb1_data3 */
+ 0x5bc (PIN_INPUT | MUX_MODE3) /* etk_d8.hsusb1_dir */
+ 0x5be (PIN_INPUT | MUX_MODE3) /* etk_d9.hsusb1_nxt */
+
+ /* GPIO 128 controls USB-Hub reset. But USB-Phy its
+ * reset can't be controlled. So we clamp this GPIO to
+ * high (PIN_OFF_OUTPUT_HIGH) to always enable USB-Hub.
+ */
+
+ 0x1ae (PIN_OUTPUT_PULLUP | PIN_OFF_OUTPUT_HIGH | MUX_MODE4) /* gpio_182 */
+ >;
+ };
+
+ hsusb_otg_pins: pinmux_hsusb_otg_pins {
+ pinctrl-single,pins = <
+ 0x172 (PIN_INPUT | MUX_MODE0) /* hsusb0_clk.hsusb0_clk */
+ 0x174 (PIN_OUTPUT | MUX_MODE0) /* hsusb0_stp.hsusb0_stp */
+ 0x176 (PIN_INPUT | MUX_MODE0) /* hsusb0_dir.hsusb0_dir */
+ 0x178 (PIN_INPUT | MUX_MODE0) /* hsusb0_nxt.hsusb0_nxt */
+ 0x17a (PIN_INPUT | MUX_MODE0) /* hsusb0_data0.hsusb0_data0 */
+ 0x17c (PIN_INPUT | MUX_MODE0) /* hsusb0_data1.hsusb0_data1 */
+ 0x17e (PIN_INPUT | MUX_MODE0) /* hsusb0_data2.hsusb0_data2 */
+ 0x180 (PIN_INPUT | MUX_MODE0) /* hsusb0_data3.hsusb0_data3 */
+ 0x182 (PIN_INPUT | MUX_MODE0) /* hsusb0_data4.hsusb0_data4 */
+ 0x184 (PIN_INPUT | MUX_MODE0) /* hsusb0_data5.hsusb0_data5 */
+ 0x186 (PIN_INPUT | MUX_MODE0) /* hsusb0_data6.hsusb0_data6 */
+ 0x188 (PIN_INPUT | MUX_MODE0) /* hsusb0_data7.hsusb0_data7 */
+ >;
+ };
+
+ mmc1_pins: pinmux_mmc1_pins {
+ pinctrl-single,pins = <
+ 0x114 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_clk.sdmmc1_clk */
+ 0x116 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_cmd.sdmmc1_cmd */
+ 0x118 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat0.sdmmc1_dat0 */
+ 0x11a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat1.sdmmc1_dat1 */
+ 0x11c (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat2.sdmmc1_dat2 */
+ 0x11e (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat3.sdmmc1_dat3 */
+ >;
+ };
+
+ spi2_pins: pinmux_spi2_pins {
+ pinctrl-single,pins = <
+ 0x1a6 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcspi2_clk.mcspi2_clk */
+ 0x1a8 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcspi2_simo.mcspi2_simo */
+ 0x1aa (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcspi2_somi.mcspi2_somi */
+ 0x1ac (PIN_OUTPUT | MUX_MODE0) /* mcspi2_cs0.mcspi2_cs0 */
+ >;
+ };
+};
+
+&gpio1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpio1_pins>;
+};
+
+&i2c1 {
+ clock-frequency = <2600000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins>;
+
+ twl: twl at 48 {
+ reg = <0x48>;
+ interrupts = <7>; /* SYS_NIRQ cascaded to intc */
+ interrupt-parent = <&intc>;
+
+ twl_audio: audio {
+ compatible = "ti,twl4030-audio";
+ codec {
+ };
+ };
+ };
+};
+
+#include "twl4030.dtsi"
+#include "twl4030_omap3.dtsi"
+
+&twl {
+ vmmc1: regulator-vmmc1 {
+ regulator-always-on;
+ };
+
+ vdd1: regulator-vdd1 {
+ regulator-always-on;
+ };
+
+ vdd2: regulator-vdd2 {
+ regulator-always-on;
+ };
+};
+
+&i2c2 {
+ clock-frequency = <2600000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins>;
+};
+
+&i2c3 {
+ clock-frequency = <2600000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c3_pins>;
+ gpiom1: gpio at 20 {
+ compatible = "mcp,mcp23017";
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x20>;
+ };
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>;
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins>;
+};
+
+&uart4 {
+ status = "disabled";
+};
+
+&mmc1 {
+ reg = <0x4809c000 0x400>;
+ cd-gpios = <&gpio4 30 IRQ_TYPE_LEVEL_LOW>;
+ cd-inverted;
+ vmmc-supply = <&vmmc1>;
+ bus-width = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins &mmc1cd_pins>;
+ cap-sdio-irq;
+ cap-sd-highspeed;
+ cap-mmc-highspeed;
+};
+
+&mmc2 {
+ status = "disabled";
+};
+
+&mmc3 {
+ status = "disabled";
+};
+
+&mcspi2 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi2_pins>;
+
+ tsc2046 at 0 {
+ reg = <0>; /* CS0 */
+ compatible = "ti,tsc2046";
+ interrupt-parent = <&gpio1>;
+ interrupts = <8 0>; /* boot6 / gpio_8 */
+ spi-max-frequency = <1000000>;
+ pendown-gpio = <&gpio1 8 0>;
+ vcc-supply = <®_vcc3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&tsc2048_pins>;
+
+ ti,x-min = <300>;
+ ti,x-max = <3000>;
+ ti,y-min = <600>;
+ ti,y-max = <3600>;
+ ti,x-plate-ohms = <80>;
+ ti,pressure-max = <255>;
+ ti,swap-xy;
+
+ linux,wakeup;
+ };
+};
+
+&usbhsehci {
+ phys = <&hsusb1_phy>;
+};
+
+&usbhshost {
+ pinctrl-names = "default";
+ pinctrl-0 = <&hsusb1_pins>;
+ num-ports = <2>;
+ port1-mode = "ehci-phy";
+};
+
+&usb_otg_hs {
+ pinctrl-names = "default";
+ pinctrl-0 = <&hsusb_otg_pins>;
+ interface-type = <0>;
+ usb-phy = <&usb2_phy>;
+ phys = <&usb2_phy>;
+ phy-names = "usb2-phy";
+ mode = <3>;
+ power = <50>;
+};
+
+&gpmc {
+ ranges = <0 0 0x30000000 0x1000000>,
+ <7 0 0x15000000 0x01000000>;
+
+ nand at 0,0 {
+ reg = <0 0 0x1000000>;
+ nand-bus-width = <16>;
+ ti,nand-ecc-opt = "bch8";
+ /* no elm on omap3 */
+
+ gpmc,mux-add-data = <0>;
+ gpmc,device-nand;
+ gpmc,device-width = <2>;
+ gpmc,wait-pin = <0>;
+ gpmc,wait-monitoring-ns = <0>;
+ gpmc,burst-length= <4>;
+ gpmc,cs-on-ns = <0>;
+ gpmc,cs-rd-off-ns = <100>;
+ gpmc,cs-wr-off-ns = <100>;
+ gpmc,adv-on-ns = <0>;
+ gpmc,adv-rd-off-ns = <100>;
+ gpmc,adv-wr-off-ns = <100>;
+ gpmc,oe-on-ns = <5>;
+ gpmc,oe-off-ns = <75>;
+ gpmc,we-on-ns = <5>;
+ gpmc,we-off-ns = <75>;
+ gpmc,rd-cycle-ns = <100>;
+ gpmc,wr-cycle-ns = <100>;
+ gpmc,access-ns = <60>;
+ gpmc,page-burst-access-ns = <5>;
+ gpmc,bus-turnaround-ns = <0>;
+ gpmc,cycle2cycle-samecsen;
+ gpmc,cycle2cycle-delay-ns = <50>;
+ gpmc,wr-data-mux-bus-ns = <75>;
+ gpmc,wr-access-ns = <155>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition at 0 {
+ label = "MLO";
+ reg = <0 0x80000>;
+ };
+
+ partition at 0x80000 {
+ label = "u-boot";
+ reg = <0x80000 0x1e0000>;
+ };
+
+ partition at 0x260000 {
+ label = "u-boot-environment";
+ reg = <0x260000 0x20000>;
+ };
+
+ partition at 0x280000 {
+ label = "kernel";
+ reg = <0x280000 0x500000>;
+ };
+
+ partition at 0x780000 {
+ label = "filesystem";
+ reg = <0x780000 0xf880000>;
+ };
+ };
+
+ ethernet at 7,0 {
+ compatible = "smsc,lan9221", "smsc,lan9115";
+ bank-width = <2>;
+ gpmc,mux-add-data = <2>;
+ gpmc,cs-on-ns = <10>;
+ gpmc,cs-rd-off-ns = <60>;
+ gpmc,cs-wr-off-ns = <60>;
+ gpmc,adv-on-ns = <0>;
+ gpmc,adv-rd-off-ns = <10>;
+ gpmc,adv-wr-off-ns = <10>;
+ gpmc,oe-on-ns = <10>;
+ gpmc,oe-off-ns = <60>;
+ gpmc,we-on-ns = <10>;
+ gpmc,we-off-ns = <60>;
+ gpmc,rd-cycle-ns = <100>;
+ gpmc,wr-cycle-ns = <100>;
+ gpmc,access-ns = <50>;
+ gpmc,page-burst-access-ns = <5>;
+ gpmc,bus-turnaround-ns = <0>;
+ gpmc,cycle2cycle-delay-ns = <75>;
+ gpmc,wr-data-mux-bus-ns = <15>;
+ gpmc,wr-access-ns = <75>;
+ gpmc,cycle2cycle-samecsen;
+ gpmc,cycle2cycle-diffcsen;
+ vddvario-supply = <®_vcc3>;
+ vdd33a-supply = <®_vcc3>;
+ reg-io-width = <4>;
+ interrupt-parent = <&gpio5>;
+ interrupts = <1 0x2>;
+ reg = <7 0 0xff>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&lan9221_pins>;
+ phy-mode = "mii";
+ };
+};
--
1.7.10.4
^ permalink raw reply related
* [PATCH v2 2/5] ARM: dts: omap3: Add support for INCOstartec DBB056 baseboard
From: Christoph Fritz @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417460-3134-1-git-send-email-chf.fritz@googlemail.com>
INCOstartec LILLY-DBB056 is a carrier board (baseboard) for
computer-on-module LILLY-A83X.
This patch adds device-tree support for most of its features.
Signed-off-by: Christoph Fritz <chf.fritz@googlemail.com>
---
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/omap3-lilly-dbb056.dts | 160 ++++++++++++++++++++++++++++++
2 files changed, 161 insertions(+)
create mode 100644 arch/arm/boot/dts/omap3-lilly-dbb056.dts
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index cfd364d..b449161 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -215,6 +215,7 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \
omap3-gta04.dtb \
omap3-igep0020.dtb \
omap3-igep0030.dtb \
+ omap3-lilly-dbb056.dtb \
omap3-zoom3.dtb \
omap4-panda.dtb \
omap4-panda-a4.dtb \
diff --git a/arch/arm/boot/dts/omap3-lilly-dbb056.dts b/arch/arm/boot/dts/omap3-lilly-dbb056.dts
new file mode 100644
index 0000000..a700b71
--- /dev/null
+++ b/arch/arm/boot/dts/omap3-lilly-dbb056.dts
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2014 Christoph Fritz <chf.fritzc@googlemail.com>
+ *
+ * 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 Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+/dts-v1/;
+
+#include "omap3-lilly-a83x.dtsi"
+
+/ {
+ model = "INCOstartec LILLY-DBB056 (DM3730)";
+ compatible = "incostartec,omap3-lilly-dbb056", "incostartec,omap3-lilly-a83x", "ti,omap36xx", "ti,omap3";
+};
+
+&twl {
+ vaux2: regulator-vaux2 {
+ compatible = "ti,twl4030-vaux2";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ };
+};
+
+&omap3_pmx_core {
+ pinctrl-names = "default";
+ pinctrl-0 = <&lcd_pins>;
+
+ lan9117_pins: pinmux_lan9117_pins {
+ pinctrl-single,pins = <
+ 0xe4 (PIN_INPUT | MUX_MODE4) /* gpio_98 */
+ >;
+ };
+
+ gpio4_pins: pinmux_gpio4_pins {
+ pinctrl-single,pins = <
+ 0xfe (PIN_INPUT | MUX_MODE4) /* gpio_111 -> sja1000 IRQ */
+ >;
+ };
+
+ lcd_pins: pinmux_lcd_pins {
+ pinctrl-single,pins = <
+ 0x0a4 (PIN_OUTPUT | MUX_MODE0) /* dss_pclk.dss_pclk */
+ 0x0a6 (PIN_OUTPUT | MUX_MODE0) /* dss_hsync.dss_hsync */
+ 0x0a8 (PIN_OUTPUT | MUX_MODE0) /* dss_vsync.dss_vsync */
+ 0x0aa (PIN_OUTPUT | MUX_MODE0) /* dss_acbias.dss_acbias */
+ 0x0ac (PIN_OUTPUT | MUX_MODE0) /* dss_data0.dss_data0 */
+ 0x0ae (PIN_OUTPUT | MUX_MODE0) /* dss_data1.dss_data1 */
+ 0x0b0 (PIN_OUTPUT | MUX_MODE0) /* dss_data2.dss_data2 */
+ 0x0b2 (PIN_OUTPUT | MUX_MODE0) /* dss_data3.dss_data3 */
+ 0x0b4 (PIN_OUTPUT | MUX_MODE0) /* dss_data4.dss_data4 */
+ 0x0b6 (PIN_OUTPUT | MUX_MODE0) /* dss_data5.dss_data5 */
+ 0x0b8 (PIN_OUTPUT | MUX_MODE0) /* dss_data6.dss_data6 */
+ 0x0ba (PIN_OUTPUT | MUX_MODE0) /* dss_data7.dss_data7 */
+ 0x0bc (PIN_OUTPUT | MUX_MODE0) /* dss_data8.dss_data8 */
+ 0x0be (PIN_OUTPUT | MUX_MODE0) /* dss_data9.dss_data9 */
+ 0x0c0 (PIN_OUTPUT | MUX_MODE0) /* dss_data10.dss_data10 */
+ 0x0c2 (PIN_OUTPUT | MUX_MODE0) /* dss_data11.dss_data11 */
+ 0x0c4 (PIN_OUTPUT | MUX_MODE0) /* dss_data12.dss_data12 */
+ 0x0c6 (PIN_OUTPUT | MUX_MODE0) /* dss_data13.dss_data13 */
+ 0x0c8 (PIN_OUTPUT | MUX_MODE0) /* dss_data14.dss_data14 */
+ 0x0ca (PIN_OUTPUT | MUX_MODE0) /* dss_data15.dss_data15 */
+ 0x0cc (PIN_OUTPUT | MUX_MODE0) /* dss_data16.dss_data16 */
+ 0x0ce (PIN_OUTPUT | MUX_MODE0) /* dss_data17.dss_data17 */
+ 0x15c (PIN_OUTPUT | MUX_MODE4) /* gpio_156 -> enable DSS */
+ >;
+ };
+
+ mmc2_pins: pinmux_mmc2_pins {
+ pinctrl-single,pins = <
+ 0x128 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_clk.sdmmc2_clk */
+ 0x12a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_cmd.sdmmc2_cmd */
+ 0x12c (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat0.sdmmc2_dat0 */
+ 0x12e (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat1.sdmmc2_dat1 */
+ 0x130 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat2.sdmmc2_dat2 */
+ 0x132 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat3.sdmmc2_dat3 */
+ 0x134 (PIN_OUTPUT | MUX_MODE1) /* sdmmc2_dat4.sdmmc2_dir_dat0 */
+ 0x136 (PIN_OUTPUT | MUX_MODE1) /* sdmmc2_dat5.sdmmc2_dir_dat1 */
+ 0x138 (PIN_OUTPUT | MUX_MODE1) /* sdmmc2_dat6.sdmmc2_dir_cmd */
+ 0x13a (PIN_INPUT | MUX_MODE1) /* sdmmc2_dat7.sdmmc2_clkin */
+ 0x16a (PIN_INPUT_PULLUP | MUX_MODE4) /* gpio_163 -> wp */
+ 0x16c (PIN_INPUT_PULLUP | MUX_MODE4) /* gpio_164 -> cd */
+ >;
+ };
+
+ spi1_pins: pinmux_spi1_pins {
+ pinctrl-single,pins = <
+ 0x198 (PIN_INPUT | MUX_MODE0) /* mcspi1_clk.mcspi1_clk */
+ 0x19a (PIN_INPUT | MUX_MODE0) /* mcspi1_simo.mcspi1_simo */
+ 0x19c (PIN_INPUT | MUX_MODE0) /* mcspi1_somi.mcspi1_somi */
+ 0x19e (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcspi1_cs0.mcspi1_cs0 */
+ >;
+ };
+};
+
+&gpio4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpio4_pins>;
+};
+
+&mmc2 {
+ status = "okay";
+ bus-width = <4>;
+ vmmc-supply = <&vmmc1>;
+ cd-gpios = <&gpio6 4 0>; /* gpio_164 */
+ wp-gpios = <&gpio6 3 0>; /* gpio_163 */
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pins>;
+ ti,dual-volt;
+};
+
+&mcspi1 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi1_pins>;
+};
+
+&gpmc {
+ ranges = <0 0 0x30000000 0x1000000>, /* nand assigned by COM a83x */
+ <4 0 0x20000000 0x01000000>,
+ <7 0 0x15000000 0x01000000>; /* eth assigend by COM a83x */
+
+ ethernet at 4,0 {
+ compatible = "smsc,lan9117", "smsc,lan9115";
+ bank-width = <2>;
+ gpmc,mux-add-data = <2>;
+ gpmc,cs-on-ns = <10>;
+ gpmc,cs-rd-off-ns = <65>;
+ gpmc,cs-wr-off-ns = <65>;
+ gpmc,adv-on-ns = <0>;
+ gpmc,adv-rd-off-ns = <10>;
+ gpmc,adv-wr-off-ns = <10>;
+ gpmc,oe-on-ns = <10>;
+ gpmc,oe-off-ns = <65>;
+ gpmc,we-on-ns = <10>;
+ gpmc,we-off-ns = <65>;
+ gpmc,rd-cycle-ns = <100>;
+ gpmc,wr-cycle-ns = <100>;
+ gpmc,access-ns = <60>;
+ gpmc,page-burst-access-ns = <5>;
+ gpmc,bus-turnaround-ns = <0>;
+ gpmc,cycle2cycle-delay-ns = <75>;
+ gpmc,wr-data-mux-bus-ns = <15>;
+ gpmc,wr-access-ns = <75>;
+ gpmc,cycle2cycle-samecsen;
+ gpmc,cycle2cycle-diffcsen;
+ vddvario-supply = <®_vcc3>;
+ vdd33a-supply = <®_vcc3>;
+ reg-io-width = <4>;
+ interrupt-parent = <&gpio4>;
+ interrupts = <2 0x2>;
+ reg = <4 0 0xff>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&lan9117_pins>;
+ phy-mode = "mii";
+ smsc,force-internal-phy;
+ };
+};
--
1.7.10.4
^ permalink raw reply related
* [PATCH v2 3/5] ARM: OMAP2+: add legacy display for omap3 DBB056
From: Christoph Fritz @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417460-3134-1-git-send-email-chf.fritz@googlemail.com>
Full device tree support for omapdss is not yet accomplished. Until
then, init display by legacy platform code.
Signed-off-by: Christoph Fritz <chf.fritz@googlemail.com>
---
arch/arm/mach-omap2/dss-common.c | 49 ++++++++++++++++++++++++++++++++++++
arch/arm/mach-omap2/dss-common.h | 1 +
arch/arm/mach-omap2/pdata-quirks.c | 7 +++++-
3 files changed, 56 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-omap2/dss-common.c b/arch/arm/mach-omap2/dss-common.c
index dadccc9..b8b4e39 100644
--- a/arch/arm/mach-omap2/dss-common.c
+++ b/arch/arm/mach-omap2/dss-common.c
@@ -257,3 +257,52 @@ void __init omap3_igep2_display_init_of(void)
platform_device_register(&omap3_igep2_tfp410_device);
platform_device_register(&omap3_igep2_dvi_connector_device);
}
+
+/* OMAP3 dbb056 data */
+
+#define DBB056_DISPLAY_ENABLE_GPIO 156
+
+static const struct display_timing dbb056_lcd_videomode = {
+ .pixelclock = { 0, 19200000, 0 },
+
+ .hactive = { 0, 640, 0 },
+ .hfront_porch = { 0, 104, 0 },
+ .hback_porch = { 0, 8, 0 },
+ .hsync_len = { 0, 8, 0 },
+
+ .vactive = { 0, 480, 0 },
+ .vfront_porch = { 0, 104, 0 },
+ .vback_porch = { 0, 8, 0 },
+ .vsync_len = { 0, 8, 0 },
+
+ .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
+ DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_NEGEDGE,
+};
+
+static struct panel_dpi_platform_data dbb056_lcd_pdata = {
+ .name = "lcd",
+ .source = "dpi.0",
+
+ .data_lines = 18,
+
+ .display_timing = &dbb056_lcd_videomode,
+
+ .enable_gpio = DBB056_DISPLAY_ENABLE_GPIO,
+ .backlight_gpio = -1,
+};
+
+static struct platform_device dbb056_lcd_device = {
+ .name = "panel-dpi",
+ .id = 0,
+ .dev.platform_data = &dbb056_lcd_pdata,
+};
+
+static struct omap_dss_board_info omap_dbb056_dss_data = {
+ .default_display_name = "lcd",
+};
+
+void __init omap3_dbb056_display_init_of(void)
+{
+ platform_device_register(&dbb056_lcd_device);
+ omap_display_init(&omap_dbb056_dss_data);
+}
diff --git a/arch/arm/mach-omap2/dss-common.h b/arch/arm/mach-omap2/dss-common.h
index a9becf0..a125b55 100644
--- a/arch/arm/mach-omap2/dss-common.h
+++ b/arch/arm/mach-omap2/dss-common.h
@@ -9,5 +9,6 @@
void __init omap4_panda_display_init_of(void);
void __init omap_4430sdp_display_init_of(void);
void __init omap3_igep2_display_init_of(void);
+void __init omap3_dbb056_display_init_of(void);
#endif
diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
index 3d5b24d..a58590f 100644
--- a/arch/arm/mach-omap2/pdata-quirks.c
+++ b/arch/arm/mach-omap2/pdata-quirks.c
@@ -169,6 +169,10 @@ static void __init am3517_evm_legacy_init(void)
omap_ctrl_writel(v, AM35XX_CONTROL_IP_SW_RESET);
omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); /* OCP barrier */
}
+static void __init omap3_dbb056_legacy_init(void)
+{
+ omap3_dbb056_display_init_of();
+}
#endif /* CONFIG_ARCH_OMAP3 */
#ifdef CONFIG_ARCH_OMAP4
@@ -259,10 +263,11 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
static struct pdata_init pdata_quirks[] __initdata = {
#ifdef CONFIG_ARCH_OMAP3
{ "compulab,omap3-sbc-t3730", omap3_sbc_t3730_legacy_init, },
+ { "incostartec,omap3-lilly-dbb056", omap3_dbb056_legacy_init, },
+ { "isee,omap3-igep0020", omap3_igep0020_legacy_init, },
{ "nokia,omap3-n900", hsmmc2_internal_input_clk, },
{ "nokia,omap3-n9", hsmmc2_internal_input_clk, },
{ "nokia,omap3-n950", hsmmc2_internal_input_clk, },
- { "isee,omap3-igep0020", omap3_igep0020_legacy_init, },
{ "ti,omap3-evm-37xx", omap3_evm_legacy_init, },
{ "ti,omap3-zoom3", omap3_zoom_legacy_init, },
{ "ti,am3517-evm", am3517_evm_legacy_init, },
--
1.7.10.4
^ permalink raw reply related
* [PATCH v2 4/5] ARM: OMAP2+: Add pdata quirk for sys_clkout2 for omap3 DBB056
From: Christoph Fritz @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417460-3134-1-git-send-email-chf.fritz@googlemail.com>
Full device tree support for clock control is not yet accomplished. Until
then, configure the 24Mhz of sys_clkout2 to feed an USB-Hub here.
Signed-off-by: Christoph Fritz <chf.fritz@googlemail.com>
---
arch/arm/mach-omap2/pdata-quirks.c | 37 ++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
index a58590f..9ef7ca8 100644
--- a/arch/arm/mach-omap2/pdata-quirks.c
+++ b/arch/arm/mach-omap2/pdata-quirks.c
@@ -171,6 +171,43 @@ static void __init am3517_evm_legacy_init(void)
}
static void __init omap3_dbb056_legacy_init(void)
{
+ struct clk *clkout2;
+ struct clk *cm96fck;
+
+ /* Reparent clkout2 to 96M_FCK */
+ pr_info("a83x-quirk: Late Reparent clkout2 to 96M_FCK\n");
+ clkout2 = clk_get(NULL, "clkout2_src_ck");
+ if(clkout2 < 0) {
+ pr_err("a83x-quirk: couldn't get clkout2_src_ck\n");
+ return;
+ }
+ cm96fck = clk_get(NULL, "cm_96m_fck");
+ if(cm96fck < 0) {
+ pr_err("a83x-quirk: couldn't get cm_96m_fck\n");
+ return;
+ }
+ if(clk_set_parent(clkout2, cm96fck) < 0) {
+ pr_err("a83x-quirk: couldn't reparent clkout2_src_ck\n");
+ return;
+ }
+
+ /* Set clkout2 to 24MHz for internal usb hub*/
+ pr_info("a83x-quirk: Set clkout2 to 24MHz for internal usb hub\n");
+ clkout2 = clk_get(NULL, "sys_clkout2");
+ if(clkout2 < 0) {
+ pr_err("a83x-quirk: couldn't get sys_clkout2\n");
+ return;
+ }
+ if(clk_set_rate(clkout2, 24000000) < 0) {
+ printk(KERN_ERR "board-omap3evm: couldn't set sys_clkout2 rate\n");
+ return;
+ }
+ if(clk_prepare_enable(clkout2) < 0) {
+ pr_err("a83x-quirk: couldn't enable sys_clkout2\n");
+ return;
+ }
+
+ /* Initialize display */
omap3_dbb056_display_init_of();
}
#endif /* CONFIG_ARCH_OMAP3 */
--
1.7.10.4
^ permalink raw reply related
* [PATCH v2 5/5] [RFC] omapdss: remove FEAT_DPI_USES_VDDS_DSI from omap3
From: Christoph Fritz @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417460-3134-1-git-send-email-chf.fritz@googlemail.com>
DBB056 doesn't use DSI for its display, but omap3 forces this
erroneously for all its boards:
| OMAP DSS rev 2.0
| omapdss DPI error: can't get VDDS_DSI regulator
| omapfb omapfb: failed to connect default display
| omapfb omapfb: failed to init overlay connections
| omapfb omapfb: failed to setup omapfb
| platform omapfb: Driver omapfb requests probe deferral
So this patch just disables it for omap3. Consider this as a hack!
Is there a proper fix for this issue?
---
drivers/video/omap2/dss/dss_features.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index 7f89691..dbf5894 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -536,7 +536,6 @@ static const enum dss_feat_id omap3630_dss_feat_list[] = {
FEAT_ALPHA_FIXED_ZORDER,
FEAT_FIFO_MERGE,
FEAT_OMAP3_DSI_FIFO_BUG,
- FEAT_DPI_USES_VDDS_DSI,
};
static const enum dss_feat_id omap4430_es1_0_dss_feat_list[] = {
--
1.7.10.4
^ permalink raw reply related
* [PATCH v5 00/14] ahci: library-ise ahci_platform, add sunxi driver and cleanup imx driver
From: Hans de Goede @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
Hi all,
Here is v4 of my patchset for adding ahci-sunxi support. It has grown quite
a bit since I've been going for a more generic approach this time and I've
also cleaned up the ahci-imx driver to use the same generic approach.
History:
v1, by Olliver Schinagl:
This was using the approach of having a platform device which probe method
creates a new child platform device which gets driven by ahci_platform.c,
as done by ahci_imx.c .
v2, by Hans de Goede:
Stand-alone platform driver based on Olliver's work
v3, by Hans de Goede:
patch-series, with 4 different parts
a) Make ahci_platform.c more generic, handle more then 1 clk, target pwr
regulator
b) New ahci-sunxi code only populating ahci_platform_data, passed to
ahci_platform.c to of_device_id matching.
c) Refactor ahci-imx code to work the same as the new ahci-sunxi code, this
is the reason why v3 is an RFC, I'm waiting for the wandboard I ordered to
arrive so that I can actually test this.
d) dts bindings for the sunxi ahci parts
v4, by Hans de Goede:
patch-series, with 5 different parts:
a) Make ahci_platform.c more generic, handle more then 1 clk, target pwr
regulator
b) Turn parts of ahci_platform.c into a library for use by other drivers
c) New ahci-sunxi driver using the ahci_platform.c library functionality
d) Refactor ahci-imx code to work the same as the new ahci-sunxi code
e) dts bindings for the sunxi ahci parts
v5:
v4 + the following changes:
1) fsl,imx6q driver is now tested
2) fixed suspend / resume on fsl,imx6q
3) Modifed devicetree node naming to match dt spec
4) Reworked the busy waiting code in the sunxi-phy handling as suggested by
Russell King
Parts a-d are intended for merging through the ata tree, the dts bindings
will be merged to Maxime Ripard's sunxi-dts tree.
Regards,
Hans
^ permalink raw reply
* [PATCH v5 01/14] libahci: Allow drivers to override start_engine
From: Hans de Goede @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417489-5354-1-git-send-email-hdegoede@redhat.com>
Allwinner A10 and A20 ARM SoCs have an AHCI sata controller which needs a
special register to be poked before starting the DMA engine.
This register gets reset on an ahci_stop_engine call, so there is no other
place then ahci_start_engine where this poking can be done.
This commit allows drivers to override ahci_start_engine behavior for use by
the Allwinner AHCI driver (and potentially other drivers in the future).
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/ata/ahci.c | 6 ++++--
drivers/ata/ahci.h | 3 ++-
drivers/ata/libahci.c | 27 ++++++++++++++++++---------
drivers/ata/sata_highbank.c | 3 ++-
4 files changed, 26 insertions(+), 13 deletions(-)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index c0ed4f27..bb4c903 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -559,6 +559,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
struct ata_port *ap = link->ap;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
bool online;
int rc;
@@ -569,7 +570,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
deadline, &online, NULL);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
@@ -584,6 +585,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
{
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
bool online;
@@ -599,7 +601,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
deadline, &online, NULL);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
/* The pseudo configuration device on SIMG4726 attached to
* ASUS P5W-DH Deluxe doesn't send signature FIS after
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 2289efd..2c04211 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -323,6 +323,8 @@ struct ahci_host_priv {
u32 em_msg_type; /* EM message type */
struct clk *clk; /* Only for platforms supporting clk */
void *plat_data; /* Other platform data */
+ /* Optional ahci_start_engine override */
+ void (*start_engine)(struct ata_port *ap);
};
extern int ahci_ignore_sss;
@@ -357,7 +359,6 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
int (*check_ready)(struct ata_link *link));
int ahci_stop_engine(struct ata_port *ap);
-void ahci_start_engine(struct ata_port *ap);
int ahci_check_ready(struct ata_link *link);
int ahci_kick_engine(struct ata_port *ap);
int ahci_port_resume(struct ata_port *ap);
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index c482f8c..96d128c 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -69,6 +69,7 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
+static void ahci_start_engine(struct ata_port *ap);
static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
static int ahci_port_start(struct ata_port *ap);
@@ -500,6 +501,9 @@ void ahci_save_initial_config(struct device *dev,
hpriv->cap = cap;
hpriv->cap2 = cap2;
hpriv->port_map = port_map;
+
+ if (!hpriv->start_engine)
+ hpriv->start_engine = ahci_start_engine;
}
EXPORT_SYMBOL_GPL(ahci_save_initial_config);
@@ -565,7 +569,7 @@ static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
return -EINVAL;
}
-void ahci_start_engine(struct ata_port *ap)
+static void ahci_start_engine(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
u32 tmp;
@@ -576,7 +580,6 @@ void ahci_start_engine(struct ata_port *ap)
writel(tmp, port_mmio + PORT_CMD);
readl(port_mmio + PORT_CMD); /* flush */
}
-EXPORT_SYMBOL_GPL(ahci_start_engine);
int ahci_stop_engine(struct ata_port *ap)
{
@@ -766,7 +769,7 @@ static void ahci_start_port(struct ata_port *ap)
/* enable DMA */
if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE))
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
/* turn on LEDs */
if (ap->flags & ATA_FLAG_EM) {
@@ -1234,7 +1237,7 @@ int ahci_kick_engine(struct ata_port *ap)
/* restart engine */
out_restart:
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
return rc;
}
EXPORT_SYMBOL_GPL(ahci_kick_engine);
@@ -1426,6 +1429,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
bool online;
@@ -1443,7 +1447,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
rc = sata_link_hardreset(link, timing, deadline, &online,
ahci_check_ready);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
if (online)
*class = ahci_dev_classify(ap);
@@ -2007,10 +2011,12 @@ static void ahci_thaw(struct ata_port *ap)
void ahci_error_handler(struct ata_port *ap)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
/* restart engine */
ahci_stop_engine(ap);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
}
sata_pmp_error_handler(ap);
@@ -2031,6 +2037,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
struct ata_device *dev = ap->link.device;
u32 devslp, dm, dito, mdat, deto;
@@ -2094,7 +2101,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
PORT_DEVSLP_ADSE);
writel(devslp, port_mmio + PORT_DEVSLP);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
/* enable device sleep feature for the drive */
err_mask = ata_dev_set_feature(dev,
@@ -2106,6 +2113,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
static void ahci_enable_fbs(struct ata_port *ap)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
u32 fbs;
@@ -2134,11 +2142,12 @@ static void ahci_enable_fbs(struct ata_port *ap)
} else
dev_err(ap->host->dev, "Failed to enable FBS\n");
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
}
static void ahci_disable_fbs(struct ata_port *ap)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
u32 fbs;
@@ -2166,7 +2175,7 @@ static void ahci_disable_fbs(struct ata_port *ap)
pp->fbs_enabled = false;
}
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
}
static void ahci_pmp_attach(struct ata_port *ap)
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
index ea3b3dc..30aa9c1 100644
--- a/drivers/ata/sata_highbank.c
+++ b/drivers/ata/sata_highbank.c
@@ -404,6 +404,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
static const unsigned long timing[] = { 5, 100, 500};
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
bool online;
@@ -432,7 +433,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
break;
} while (!online && retry--);
- ahci_start_engine(ap);
+ hpriv->start_engine(ap);
if (online)
*class = ahci_dev_classify(ap);
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 02/14] libahci: Move ahci_host_priv declaration to include/linux/ahci.h
From: Hans de Goede @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417489-5354-1-git-send-email-hdegoede@redhat.com>
With the ahci-platform.c changes later in this patch-set, some
arch/arm/mach-foo/*.c sata drivers need access to ahci_host_priv, so move
its declaration outside of drivers/ata.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/ata/ahci.h | 20 +-------------------
include/linux/ahci.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 47 insertions(+), 19 deletions(-)
create mode 100644 include/linux/ahci.h
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 2c04211..0f80129 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -35,7 +35,7 @@
#ifndef _AHCI_H
#define _AHCI_H
-#include <linux/clk.h>
+#include <linux/ahci.h>
#include <linux/libata.h>
/* Enclosure Management Control */
@@ -309,24 +309,6 @@ struct ahci_port_priv {
char *irq_desc; /* desc in /proc/interrupts */
};
-struct ahci_host_priv {
- void __iomem * mmio; /* bus-independent mem map */
- unsigned int flags; /* AHCI_HFLAG_* */
- u32 cap; /* cap to use */
- u32 cap2; /* cap2 to use */
- u32 port_map; /* port map to use */
- u32 saved_cap; /* saved initial cap */
- u32 saved_cap2; /* saved initial cap2 */
- u32 saved_port_map; /* saved initial port_map */
- u32 em_loc; /* enclosure management location */
- u32 em_buf_sz; /* EM buffer size in byte */
- u32 em_msg_type; /* EM message type */
- struct clk *clk; /* Only for platforms supporting clk */
- void *plat_data; /* Other platform data */
- /* Optional ahci_start_engine override */
- void (*start_engine)(struct ata_port *ap);
-};
-
extern int ahci_ignore_sss;
extern struct device_attribute *ahci_shost_attrs[];
diff --git a/include/linux/ahci.h b/include/linux/ahci.h
new file mode 100644
index 0000000..3499d44
--- /dev/null
+++ b/include/linux/ahci.h
@@ -0,0 +1,46 @@
+/*
+ * ahci.h - Common AHCI SATA definitions and declarations
+ *
+ * Maintained by: Tejun Heo <tj@kernel.org>
+ * Please ALWAYS copy linux-ide at vger.kernel.org
+ * on emails.
+ *
+ * Copyright 2004-2005 Red Hat, Inc.
+ *
+ * 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 Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __LINUX_AHCI_H__
+#define __LINUX_AHCI_H__
+
+#include <linux/clk.h>
+
+struct ata_port;
+
+struct ahci_host_priv {
+ void __iomem *mmio; /* bus-independent mem map */
+ unsigned int flags; /* AHCI_HFLAG_* */
+ u32 cap; /* cap to use */
+ u32 cap2; /* cap2 to use */
+ u32 port_map; /* port map to use */
+ u32 saved_cap; /* saved initial cap */
+ u32 saved_cap2; /* saved initial cap2 */
+ u32 saved_port_map; /* saved initial port_map */
+ u32 em_loc; /* enclosure management location */
+ u32 em_buf_sz; /* EM buffer size in byte */
+ u32 em_msg_type; /* EM message type */
+ struct clk *clk; /* Optional */
+ void *plat_data; /* Other platform data */
+ /* Optional ahci_start_engine override */
+ void (*start_engine)(struct ata_port *ap);
+};
+
+#endif
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 03/14] ahci-platform: Pass ahci_host_priv ptr to ahci_platform_data init method
From: Hans de Goede @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417489-5354-1-git-send-email-hdegoede@redhat.com>
Some ahci_platform_data->init methods need access to the ahci_host_priv data.
When calling ahci_platform_data->init the ata_host has not been allocated yet,
so access to ahci_host_priv through the dev argument is not possible.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/mach-davinci/devices-da8xx.c | 5 +++--
arch/arm/mach-spear/spear1340.c | 2 +-
drivers/ata/ahci_imx.c | 12 ++++++------
drivers/ata/ahci_platform.c | 2 +-
include/linux/ahci_platform.h | 3 ++-
5 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 78829c5..28e7c4c 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -14,6 +14,7 @@
#include <linux/platform_device.h>
#include <linux/dma-contiguous.h>
#include <linux/serial_8250.h>
+#include <linux/ahci.h>
#include <linux/ahci_platform.h>
#include <linux/clk.h>
#include <linux/reboot.h>
@@ -1061,7 +1062,7 @@ static unsigned long da850_sata_xtal[] = {
KHZ_TO_HZ(60000),
};
-static int da850_sata_init(struct device *dev, void __iomem *addr)
+static int da850_sata_init(struct device *dev, struct ahci_host_priv *hpriv)
{
int i, ret;
unsigned int val;
@@ -1096,7 +1097,7 @@ static int da850_sata_init(struct device *dev, void __iomem *addr)
SATA_PHY_TXSWING(3) |
SATA_PHY_ENPLL(1);
- __raw_writel(val, addr + SATA_P0PHYCR_REG);
+ __raw_writel(val, hpriv->mmio + SATA_P0PHYCR_REG);
return 0;
diff --git a/arch/arm/mach-spear/spear1340.c b/arch/arm/mach-spear/spear1340.c
index 3fb6834..9e2f3ac 100644
--- a/arch/arm/mach-spear/spear1340.c
+++ b/arch/arm/mach-spear/spear1340.c
@@ -77,7 +77,7 @@
SPEAR1340_MIPHY_PLL_RATIO_TOP(25))
/* SATA device registration */
-static int sata_miphy_init(struct device *dev, void __iomem *addr)
+static int sata_miphy_init(struct device *dev, struct ahci_host_priv *hpriv)
{
writel(SPEAR1340_SATA_CFG_VAL, SPEAR1340_PCIE_SATA_CFG);
writel(SPEAR1340_PCIE_SATA_MIPHY_CFG_SATA_25M_CRYSTAL_CLK,
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index 3e23e99..49fa0ca 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -91,7 +91,7 @@ static const struct ata_port_info ahci_imx_port_info = {
.port_ops = &ahci_imx_ops,
};
-static int imx6q_sata_init(struct device *dev, void __iomem *mmio)
+static int imx6q_sata_init(struct device *dev, struct ahci_host_priv *hpriv)
{
int ret = 0;
unsigned int reg_val;
@@ -145,19 +145,19 @@ static int imx6q_sata_init(struct device *dev, void __iomem *mmio)
* Implement the port0.
* Get the ahb clock rate, and configure the TIMER1MS register.
*/
- reg_val = readl(mmio + HOST_CAP);
+ reg_val = readl(hpriv->mmio + HOST_CAP);
if (!(reg_val & HOST_CAP_SSS)) {
reg_val |= HOST_CAP_SSS;
- writel(reg_val, mmio + HOST_CAP);
+ writel(reg_val, hpriv->mmio + HOST_CAP);
}
- reg_val = readl(mmio + HOST_PORTS_IMPL);
+ reg_val = readl(hpriv->mmio + HOST_PORTS_IMPL);
if (!(reg_val & 0x1)) {
reg_val |= 0x1;
- writel(reg_val, mmio + HOST_PORTS_IMPL);
+ writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL);
}
reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
- writel(reg_val, mmio + HOST_TIMER1MS);
+ writel(reg_val, hpriv->mmio + HOST_TIMER1MS);
return 0;
}
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 4b231ba..434ab89 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -149,7 +149,7 @@ static int ahci_probe(struct platform_device *pdev)
* returned successfully.
*/
if (pdata && pdata->init) {
- rc = pdata->init(dev, hpriv->mmio);
+ rc = pdata->init(dev, hpriv);
if (rc)
goto disable_unprepare_clk;
}
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index 73a2500..737fe38 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -19,9 +19,10 @@
struct device;
struct ata_port_info;
+struct ahci_host_priv;
struct ahci_platform_data {
- int (*init)(struct device *dev, void __iomem *addr);
+ int (*init)(struct device *dev, struct ahci_host_priv *hpriv);
void (*exit)(struct device *dev);
int (*suspend)(struct device *dev);
int (*resume)(struct device *dev);
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 04/14] ahci-platform: Add support for devices with more then 1 clock
From: Hans de Goede @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417489-5354-1-git-send-email-hdegoede@redhat.com>
The allwinner-sun4i AHCI controller needs 2 clocks to be enabled and the
imx AHCI controller needs 3 clocks to be enabled.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
.../devicetree/bindings/ata/ahci-platform.txt | 1 +
drivers/ata/ahci_platform.c | 97 +++++++++++++++-------
include/linux/ahci.h | 4 +-
include/linux/ahci_platform.h | 3 +
4 files changed, 73 insertions(+), 32 deletions(-)
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index 89de156..3ced07d 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -10,6 +10,7 @@ Required properties:
Optional properties:
- dma-coherent : Present if dma operations are coherent
+- clocks : a list of phandle + clock specifier pairs
Example:
sata at ffe08000 {
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 434ab89..aaa0c08 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -87,6 +87,44 @@ static struct scsi_host_template ahci_platform_sht = {
AHCI_SHT("ahci_platform"),
};
+
+int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
+{
+ int c, rc;
+
+ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
+ rc = clk_prepare_enable(hpriv->clks[c]);
+ if (rc)
+ goto disable_unprepare_clk;
+ }
+ return 0;
+
+disable_unprepare_clk:
+ while (--c >= 0)
+ clk_disable_unprepare(hpriv->clks[c]);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
+
+void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
+{
+ int c;
+
+ for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
+ if (hpriv->clks[c])
+ clk_disable_unprepare(hpriv->clks[c]);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
+
+
+static void ahci_put_clks(struct ahci_host_priv *hpriv)
+{
+ int c;
+
+ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
+ clk_put(hpriv->clks[c]);
+}
+
static int ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -97,10 +135,8 @@ static int ahci_probe(struct platform_device *pdev)
struct ahci_host_priv *hpriv;
struct ata_host *host;
struct resource *mem;
- int irq;
- int n_ports;
- int i;
- int rc;
+ struct clk *clk;
+ int i, irq, max_clk, n_ports, rc;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
@@ -131,17 +167,26 @@ static int ahci_probe(struct platform_device *pdev)
return -ENOMEM;
}
- hpriv->clk = clk_get(dev, NULL);
- if (IS_ERR(hpriv->clk)) {
- dev_err(dev, "can't get clock\n");
- } else {
- rc = clk_prepare_enable(hpriv->clk);
- if (rc) {
- dev_err(dev, "clock prepare enable failed");
- goto free_clk;
+ max_clk = dev->of_node ? AHCI_MAX_CLKS : 1;
+ for (i = 0; i < max_clk; i++) {
+ if (i == 0)
+ clk = clk_get(dev, NULL); /* For old platform init */
+ else
+ clk = of_clk_get(dev->of_node, i);
+
+ if (IS_ERR(clk)) {
+ rc = PTR_ERR(clk);
+ if (rc == -EPROBE_DEFER)
+ goto free_clk;
+ break;
}
+ hpriv->clks[i] = clk;
}
+ rc = ahci_enable_clks(dev, hpriv);
+ if (rc)
+ goto free_clk;
+
/*
* Some platforms might need to prepare for mmio region access,
* which could be done in the following init call. So, the mmio
@@ -222,11 +267,9 @@ pdata_exit:
if (pdata && pdata->exit)
pdata->exit(dev);
disable_unprepare_clk:
- if (!IS_ERR(hpriv->clk))
- clk_disable_unprepare(hpriv->clk);
+ ahci_disable_clks(hpriv);
free_clk:
- if (!IS_ERR(hpriv->clk))
- clk_put(hpriv->clk);
+ ahci_put_clks(hpriv);
return rc;
}
@@ -239,10 +282,8 @@ static void ahci_host_stop(struct ata_host *host)
if (pdata && pdata->exit)
pdata->exit(dev);
- if (!IS_ERR(hpriv->clk)) {
- clk_disable_unprepare(hpriv->clk);
- clk_put(hpriv->clk);
- }
+ ahci_disable_clks(hpriv);
+ ahci_put_clks(hpriv);
}
#ifdef CONFIG_PM_SLEEP
@@ -277,8 +318,7 @@ static int ahci_suspend(struct device *dev)
if (pdata && pdata->suspend)
return pdata->suspend(dev);
- if (!IS_ERR(hpriv->clk))
- clk_disable_unprepare(hpriv->clk);
+ ahci_disable_clks(hpriv);
return 0;
}
@@ -290,13 +330,9 @@ static int ahci_resume(struct device *dev)
struct ahci_host_priv *hpriv = host->private_data;
int rc;
- if (!IS_ERR(hpriv->clk)) {
- rc = clk_prepare_enable(hpriv->clk);
- if (rc) {
- dev_err(dev, "clock prepare enable failed");
- return rc;
- }
- }
+ rc = ahci_enable_clks(dev, hpriv);
+ if (rc)
+ return rc;
if (pdata && pdata->resume) {
rc = pdata->resume(dev);
@@ -317,8 +353,7 @@ static int ahci_resume(struct device *dev)
return 0;
disable_unprepare_clk:
- if (!IS_ERR(hpriv->clk))
- clk_disable_unprepare(hpriv->clk);
+ ahci_disable_clks(hpriv);
return rc;
}
diff --git a/include/linux/ahci.h b/include/linux/ahci.h
index 3499d44..19970b0 100644
--- a/include/linux/ahci.h
+++ b/include/linux/ahci.h
@@ -23,6 +23,8 @@
#include <linux/clk.h>
+#define AHCI_MAX_CLKS 3
+
struct ata_port;
struct ahci_host_priv {
@@ -37,7 +39,7 @@ struct ahci_host_priv {
u32 em_loc; /* enclosure management location */
u32 em_buf_sz; /* EM buffer size in byte */
u32 em_msg_type; /* EM message type */
- struct clk *clk; /* Optional */
+ struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
void *plat_data; /* Other platform data */
/* Optional ahci_start_engine override */
void (*start_engine)(struct ata_port *ap);
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index 737fe38..0071d0b 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -31,4 +31,7 @@ struct ahci_platform_data {
unsigned int mask_port_map;
};
+int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
+void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
+
#endif /* _AHCI_PLATFORM_H */
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 05/14] ahci-platform: Add support for an optional regulator for sata-target power
From: Hans de Goede @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417489-5354-1-git-send-email-hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
.../devicetree/bindings/ata/ahci-platform.txt | 1 +
drivers/ata/ahci_platform.c | 35 ++++++++++++++++++++--
include/linux/ahci.h | 2 ++
3 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index 3ced07d..1ac807f 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -11,6 +11,7 @@ Required properties:
Optional properties:
- dma-coherent : Present if dma operations are coherent
- clocks : a list of phandle + clock specifier pairs
+- target-supply : regulator for SATA target power
Example:
sata at ffe08000 {
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index aaa0c08..2f319e9 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -167,6 +167,13 @@ static int ahci_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
+ if (IS_ERR(hpriv->target_pwr)) {
+ if (PTR_ERR(hpriv->target_pwr) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ hpriv->target_pwr = NULL;
+ }
+
max_clk = dev->of_node ? AHCI_MAX_CLKS : 1;
for (i = 0; i < max_clk; i++) {
if (i == 0)
@@ -183,9 +190,15 @@ static int ahci_probe(struct platform_device *pdev)
hpriv->clks[i] = clk;
}
+ if (hpriv->target_pwr) {
+ rc = regulator_enable(hpriv->target_pwr);
+ if (rc)
+ goto free_clk;
+ }
+
rc = ahci_enable_clks(dev, hpriv);
if (rc)
- goto free_clk;
+ goto disable_regulator;
/*
* Some platforms might need to prepare for mmio region access,
@@ -268,6 +281,9 @@ pdata_exit:
pdata->exit(dev);
disable_unprepare_clk:
ahci_disable_clks(hpriv);
+disable_regulator:
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
free_clk:
ahci_put_clks(hpriv);
return rc;
@@ -284,6 +300,9 @@ static void ahci_host_stop(struct ata_host *host)
ahci_disable_clks(hpriv);
ahci_put_clks(hpriv);
+
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
}
#ifdef CONFIG_PM_SLEEP
@@ -320,6 +339,9 @@ static int ahci_suspend(struct device *dev)
ahci_disable_clks(hpriv);
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+
return 0;
}
@@ -330,9 +352,15 @@ static int ahci_resume(struct device *dev)
struct ahci_host_priv *hpriv = host->private_data;
int rc;
+ if (hpriv->target_pwr) {
+ rc = regulator_enable(hpriv->target_pwr);
+ if (rc)
+ return rc;
+ }
+
rc = ahci_enable_clks(dev, hpriv);
if (rc)
- return rc;
+ goto disable_regulator;
if (pdata && pdata->resume) {
rc = pdata->resume(dev);
@@ -354,6 +382,9 @@ static int ahci_resume(struct device *dev)
disable_unprepare_clk:
ahci_disable_clks(hpriv);
+disable_regulator:
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
return rc;
}
diff --git a/include/linux/ahci.h b/include/linux/ahci.h
index 19970b0..ac69cdc 100644
--- a/include/linux/ahci.h
+++ b/include/linux/ahci.h
@@ -22,6 +22,7 @@
#define __LINUX_AHCI_H__
#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
#define AHCI_MAX_CLKS 3
@@ -40,6 +41,7 @@ struct ahci_host_priv {
u32 em_buf_sz; /* EM buffer size in byte */
u32 em_msg_type; /* EM message type */
struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
+ struct regulator *target_pwr; /* Optional */
void *plat_data; /* Other platform data */
/* Optional ahci_start_engine override */
void (*start_engine)(struct ata_port *ap);
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 06/14] ahci-platform: Add enable_ / disable_resources helper functions
From: Hans de Goede @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417489-5354-1-git-send-email-hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/ata/ahci_platform.c | 83 ++++++++++++++++++++++++-------------------
include/linux/ahci_platform.h | 2 ++
2 files changed, 48 insertions(+), 37 deletions(-)
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 2f319e9..1cce7a2 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -117,6 +117,39 @@ void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
+int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
+{
+ int rc;
+
+ if (hpriv->target_pwr) {
+ rc = regulator_enable(hpriv->target_pwr);
+ if (rc)
+ return rc;
+ }
+
+ rc = ahci_platform_enable_clks(hpriv);
+ if (rc)
+ goto disable_regulator;
+
+ return 0;
+
+disable_regulator:
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
+
+void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
+{
+ ahci_platform_disable_clks(hpriv);
+
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
+
+
static void ahci_put_clks(struct ahci_host_priv *hpriv)
{
int c;
@@ -190,15 +223,9 @@ static int ahci_probe(struct platform_device *pdev)
hpriv->clks[i] = clk;
}
- if (hpriv->target_pwr) {
- rc = regulator_enable(hpriv->target_pwr);
- if (rc)
- goto free_clk;
- }
-
- rc = ahci_enable_clks(dev, hpriv);
+ rc = ahci_platform_enable_resources(hpriv);
if (rc)
- goto disable_regulator;
+ goto free_clk;
/*
* Some platforms might need to prepare for mmio region access,
@@ -209,7 +236,7 @@ static int ahci_probe(struct platform_device *pdev)
if (pdata && pdata->init) {
rc = pdata->init(dev, hpriv);
if (rc)
- goto disable_unprepare_clk;
+ goto disable_resources;
}
ahci_save_initial_config(dev, hpriv,
@@ -279,11 +306,8 @@ static int ahci_probe(struct platform_device *pdev)
pdata_exit:
if (pdata && pdata->exit)
pdata->exit(dev);
-disable_unprepare_clk:
- ahci_disable_clks(hpriv);
-disable_regulator:
- if (hpriv->target_pwr)
- regulator_disable(hpriv->target_pwr);
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
free_clk:
ahci_put_clks(hpriv);
return rc;
@@ -298,11 +322,8 @@ static void ahci_host_stop(struct ata_host *host)
if (pdata && pdata->exit)
pdata->exit(dev);
- ahci_disable_clks(hpriv);
+ ahci_platform_disable_resources(hpriv);
ahci_put_clks(hpriv);
-
- if (hpriv->target_pwr)
- regulator_disable(hpriv->target_pwr);
}
#ifdef CONFIG_PM_SLEEP
@@ -337,10 +358,7 @@ static int ahci_suspend(struct device *dev)
if (pdata && pdata->suspend)
return pdata->suspend(dev);
- ahci_disable_clks(hpriv);
-
- if (hpriv->target_pwr)
- regulator_disable(hpriv->target_pwr);
+ ahci_platform_disable_resources(hpriv);
return 0;
}
@@ -352,26 +370,20 @@ static int ahci_resume(struct device *dev)
struct ahci_host_priv *hpriv = host->private_data;
int rc;
- if (hpriv->target_pwr) {
- rc = regulator_enable(hpriv->target_pwr);
- if (rc)
- return rc;
- }
-
- rc = ahci_enable_clks(dev, hpriv);
+ rc = ahci_platform_enable_resources(hpriv);
if (rc)
- goto disable_regulator;
+ return rc;
if (pdata && pdata->resume) {
rc = pdata->resume(dev);
if (rc)
- goto disable_unprepare_clk;
+ goto disable_resources;
}
if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
rc = ahci_reset_controller(host);
if (rc)
- goto disable_unprepare_clk;
+ goto disable_resources;
ahci_init_controller(host);
}
@@ -380,11 +392,8 @@ static int ahci_resume(struct device *dev)
return 0;
-disable_unprepare_clk:
- ahci_disable_clks(hpriv);
-disable_regulator:
- if (hpriv->target_pwr)
- regulator_disable(hpriv->target_pwr);
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
return rc;
}
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index 0071d0b..5e5f85e 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -33,5 +33,7 @@ struct ahci_platform_data {
int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
+int ahci_platform_enable_resources(struct ahci_host_priv *hpriv);
+void ahci_platform_disable_resources(struct ahci_host_priv *hpriv);
#endif /* _AHCI_PLATFORM_H */
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 07/14] ahci-platform: "Library-ise" ahci_probe functionality
From: Hans de Goede @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417489-5354-1-git-send-email-hdegoede@redhat.com>
ahci_probe consists of 3 steps:
1) Get resources (get mmio, clks, regulator)
2) Enable resources, handled by ahci_platform_enable_resouces
3) The more or less standard ahci-host controller init sequence
This commit refactors step 1 and 3 into separate functions, so the platform
drivers for AHCI implementations which need a specific order in step 2,
and / or need to do some custom register poking at some time, can re-use
ahci-platform.c code without needing to copy and paste it.
Note that ahci_platform_init_host's prototype takes the 3 non function
members of ahci_platform_data as arguments, the idea is that drivers using
the new exported utility functions will not use ahci_platform_data at all,
and hopefully in the future ahci_platform_data can go away entirely.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/ata/ahci_platform.c | 158 ++++++++++++++++++++++++------------------
include/linux/ahci_platform.h | 14 ++++
2 files changed, 106 insertions(+), 66 deletions(-)
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 1cce7a2..b260ebe 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -150,60 +150,31 @@ void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
-static void ahci_put_clks(struct ahci_host_priv *hpriv)
-{
- int c;
-
- for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
- clk_put(hpriv->clks[c]);
-}
-
-static int ahci_probe(struct platform_device *pdev)
+struct ahci_host_priv *ahci_platform_get_resources(
+ struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct ahci_platform_data *pdata = dev_get_platdata(dev);
- const struct platform_device_id *id = platform_get_device_id(pdev);
- struct ata_port_info pi = ahci_port_info[id ? id->driver_data : 0];
- const struct ata_port_info *ppi[] = { &pi, NULL };
struct ahci_host_priv *hpriv;
- struct ata_host *host;
- struct resource *mem;
struct clk *clk;
- int i, irq, max_clk, n_ports, rc;
-
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(dev, "no mmio space\n");
- return -EINVAL;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq <= 0) {
- dev_err(dev, "no irq\n");
- return -EINVAL;
- }
-
- if (pdata && pdata->ata_port_info)
- pi = *pdata->ata_port_info;
+ int i, max_clk, rc;
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv) {
dev_err(dev, "can't alloc ahci_host_priv\n");
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
}
- hpriv->flags |= (unsigned long)pi.private_data;
-
- hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
+ hpriv->mmio = devm_ioremap_resource(dev,
+ platform_get_resource(pdev, IORESOURCE_MEM, 0));
if (!hpriv->mmio) {
- dev_err(dev, "can't map %pR\n", mem);
- return -ENOMEM;
+ dev_err(dev, "no mmio space\n");
+ return ERR_PTR(-EINVAL);
}
hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
if (IS_ERR(hpriv->target_pwr)) {
if (PTR_ERR(hpriv->target_pwr) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
+ return ERR_PTR(-EPROBE_DEFER);
hpriv->target_pwr = NULL;
}
@@ -223,27 +194,48 @@ static int ahci_probe(struct platform_device *pdev)
hpriv->clks[i] = clk;
}
- rc = ahci_platform_enable_resources(hpriv);
- if (rc)
- goto free_clk;
+ return hpriv;
- /*
- * Some platforms might need to prepare for mmio region access,
- * which could be done in the following init call. So, the mmio
- * region shouldn't be accessed before init (if provided) has
- * returned successfully.
- */
- if (pdata && pdata->init) {
- rc = pdata->init(dev, hpriv);
- if (rc)
- goto disable_resources;
- }
+free_clk:
+ while (--i >= 0)
+ clk_put(hpriv->clks[i]);
+ return ERR_PTR(rc);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
+
+void ahci_platform_put_resources(struct ahci_host_priv *hpriv)
+{
+ int c;
+
+ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
+ clk_put(hpriv->clks[c]);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_put_resources);
+
+
+int ahci_platform_init_host(struct platform_device *pdev,
+ struct ahci_host_priv *hpriv,
+ const struct ata_port_info *pi_template,
+ unsigned int force_port_map,
+ unsigned int mask_port_map)
+{
+ struct device *dev = &pdev->dev;
+ struct ata_port_info pi = *pi_template;
+ const struct ata_port_info *ppi[] = { &pi, NULL };
+ struct ata_host *host;
+ int i, irq, n_ports, rc;
- ahci_save_initial_config(dev, hpriv,
- pdata ? pdata->force_port_map : 0,
- pdata ? pdata->mask_port_map : 0);
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(dev, "no irq\n");
+ return -EINVAL;
+ }
/* prepare host */
+ hpriv->flags |= (unsigned long)pi.private_data;
+
+ ahci_save_initial_config(dev, hpriv, force_port_map, mask_port_map);
+
if (hpriv->cap & HOST_CAP_NCQ)
pi.flags |= ATA_FLAG_NCQ;
@@ -260,10 +252,8 @@ static int ahci_probe(struct platform_device *pdev)
n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
host = ata_host_alloc_pinfo(dev, ppi, n_ports);
- if (!host) {
- rc = -ENOMEM;
- goto pdata_exit;
- }
+ if (!host)
+ return -ENOMEM;
host->private_data = hpriv;
@@ -278,7 +268,8 @@ static int ahci_probe(struct platform_device *pdev)
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
- ata_port_desc(ap, "mmio %pR", mem);
+ ata_port_desc(ap, "mmio %pR",
+ platform_get_resource(pdev, IORESOURCE_MEM, 0));
ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
/* set enclosure management message type */
@@ -292,13 +283,48 @@ static int ahci_probe(struct platform_device *pdev)
rc = ahci_reset_controller(host);
if (rc)
- goto pdata_exit;
+ return rc;
ahci_init_controller(host);
ahci_print_info(host, "platform");
- rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
- &ahci_platform_sht);
+ return ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
+ &ahci_platform_sht);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_init_host);
+
+static int ahci_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ahci_platform_data *pdata = dev_get_platdata(dev);
+ const struct platform_device_id *id = platform_get_device_id(pdev);
+ struct ahci_host_priv *hpriv;
+ int rc;
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ goto put_resources;
+
+ /*
+ * Some platforms might need to prepare for mmio region access,
+ * which could be done in the following init call. So, the mmio
+ * region shouldn't be accessed before init (if provided) has
+ * returned successfully.
+ */
+ if (pdata && pdata->init) {
+ rc = pdata->init(dev, hpriv);
+ if (rc)
+ goto disable_resources;
+ }
+
+ rc = ahci_platform_init_host(pdev, hpriv,
+ &ahci_port_info[id ? id->driver_data : 0],
+ pdata ? pdata->force_port_map : 0,
+ pdata ? pdata->mask_port_map : 0);
if (rc)
goto pdata_exit;
@@ -308,8 +334,8 @@ pdata_exit:
pdata->exit(dev);
disable_resources:
ahci_platform_disable_resources(hpriv);
-free_clk:
- ahci_put_clks(hpriv);
+put_resources:
+ ahci_platform_put_resources(hpriv);
return rc;
}
@@ -323,7 +349,7 @@ static void ahci_host_stop(struct ata_host *host)
pdata->exit(dev);
ahci_platform_disable_resources(hpriv);
- ahci_put_clks(hpriv);
+ ahci_platform_put_resources(hpriv);
}
#ifdef CONFIG_PM_SLEEP
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index 5e5f85e..1dc7602 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -20,7 +20,13 @@
struct device;
struct ata_port_info;
struct ahci_host_priv;
+struct platform_device;
+/*
+ * Note ahci_platform_data is deprecated. New drivers which need to override
+ * any of these, should instead declare there own platform_driver struct, and
+ * use ahci_platform* functions in their own probe, suspend and resume methods.
+ */
struct ahci_platform_data {
int (*init)(struct device *dev, struct ahci_host_priv *hpriv);
void (*exit)(struct device *dev);
@@ -35,5 +41,13 @@ int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
int ahci_platform_enable_resources(struct ahci_host_priv *hpriv);
void ahci_platform_disable_resources(struct ahci_host_priv *hpriv);
+struct ahci_host_priv *ahci_platform_get_resources(
+ struct platform_device *pdev);
+void ahci_platform_put_resources(struct ahci_host_priv *hpriv);
+int ahci_platform_init_host(struct platform_device *pdev,
+ struct ahci_host_priv *hpriv,
+ const struct ata_port_info *pi_template,
+ unsigned int force_port_map,
+ unsigned int mask_port_map);
#endif /* _AHCI_PLATFORM_H */
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 08/14] ahci-platform: "Library-ise" suspend / resume functionality
From: Hans de Goede @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417489-5354-1-git-send-email-hdegoede@redhat.com>
Split suspend / resume code into host suspend / resume functionality and
resource enable / disabling phases, and export the new suspend_ / resume_host
functions.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/ata/ahci_platform.c | 55 +++++++++++++++++++++++++++++++------------
include/linux/ahci_platform.h | 7 ++++++
2 files changed, 47 insertions(+), 15 deletions(-)
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index b260ebe..ba93930 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -353,14 +353,12 @@ static void ahci_host_stop(struct ata_host *host)
}
#ifdef CONFIG_PM_SLEEP
-static int ahci_suspend(struct device *dev)
+int ahci_platform_suspend_host(struct device *dev)
{
- struct ahci_platform_data *pdata = dev_get_platdata(dev);
struct ata_host *host = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = host->private_data;
void __iomem *mmio = hpriv->mmio;
u32 ctl;
- int rc;
if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
dev_err(dev, "firmware update required for suspend/resume\n");
@@ -377,7 +375,37 @@ static int ahci_suspend(struct device *dev)
writel(ctl, mmio + HOST_CTL);
readl(mmio + HOST_CTL); /* flush */
- rc = ata_host_suspend(host, PMSG_SUSPEND);
+ return ata_host_suspend(host, PMSG_SUSPEND);
+}
+EXPORT_SYMBOL_GPL(ahci_platform_suspend_host);
+
+int ahci_platform_resume_host(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ int rc;
+
+ if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
+ rc = ahci_reset_controller(host);
+ if (rc)
+ return rc;
+
+ ahci_init_controller(host);
+ }
+
+ ata_host_resume(host);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_resume_host);
+
+int ahci_platform_suspend(struct device *dev)
+{
+ struct ahci_platform_data *pdata = dev_get_platdata(dev);
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ int rc;
+
+ rc = ahci_platform_suspend_host(dev);
if (rc)
return rc;
@@ -388,8 +416,9 @@ static int ahci_suspend(struct device *dev)
return 0;
}
+EXPORT_SYMBOL_GPL(ahci_platform_suspend);
-static int ahci_resume(struct device *dev)
+int ahci_platform_resume(struct device *dev)
{
struct ahci_platform_data *pdata = dev_get_platdata(dev);
struct ata_host *host = dev_get_drvdata(dev);
@@ -406,15 +435,9 @@ static int ahci_resume(struct device *dev)
goto disable_resources;
}
- if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
- rc = ahci_reset_controller(host);
- if (rc)
- goto disable_resources;
-
- ahci_init_controller(host);
- }
-
- ata_host_resume(host);
+ rc = ahci_platform_resume_host(dev);
+ if (rc)
+ goto disable_resources;
return 0;
@@ -423,9 +446,11 @@ disable_resources:
return rc;
}
+EXPORT_SYMBOL_GPL(ahci_platform_resume);
#endif
-static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume);
+static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
+ ahci_platform_resume);
static const struct of_device_id ahci_of_match[] = {
{ .compatible = "snps,spear-ahci", },
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index 1dc7602..b484ac0 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -50,4 +50,11 @@ int ahci_platform_init_host(struct platform_device *pdev,
unsigned int force_port_map,
unsigned int mask_port_map);
+#ifdef CONFIG_PM_SLEEP
+int ahci_platform_suspend_host(struct device *dev);
+int ahci_platform_resume_host(struct device *dev);
+int ahci_platform_suspend(struct device *dev);
+int ahci_platform_resume(struct device *dev);
+#endif
+
#endif /* _AHCI_PLATFORM_H */
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 09/14] ARM: sunxi: Add support for Allwinner SUNXi SoCs sata to ahci_platform
From: Hans de Goede @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417489-5354-1-git-send-email-hdegoede@redhat.com>
From: Olliver Schinagl <oliver@schinagl.nl>
This patch adds support for the ahci sata controler found on Allwinner A10
and A20 SoCs to the ahci_platform driver.
Orignally written by Olliver Schinagl using the approach of having a platform
device which probe method creates a new child platform device which gets
driven by ahci_platform.c, as done by ahci_imx.c .
Refactored by Hans de Goede to add most of the non sunxi specific functionality
to ahci_platform.c and use a platform_data pointer from of_device_id for the
sunxi specific bits.
Signed-off-by: Olliver Schinagl <oliver@schinagl.nl>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
.../devicetree/bindings/ata/ahci-platform.txt | 18 +-
drivers/ata/Kconfig | 9 +
drivers/ata/Makefile | 1 +
drivers/ata/ahci_sunxi.c | 251 +++++++++++++++++++++
4 files changed, 276 insertions(+), 3 deletions(-)
create mode 100644 drivers/ata/ahci_sunxi.c
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index 1ac807f..78b2e80 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -4,7 +4,9 @@ SATA nodes are defined to describe on-chip Serial ATA controllers.
Each SATA controller should have its own node.
Required properties:
-- compatible : compatible list, contains "snps,spear-ahci"
+- compatible : compatible list, one of "snps,spear-ahci",
+ "snps,exynos5440-ahci", "ibm,476gtr-ahci", or
+ "allwinner,sun4i-a10-ahci"
- interrupts : <interrupt mapping for SATA IRQ>
- reg : <registers mapping>
@@ -13,10 +15,20 @@ Optional properties:
- clocks : a list of phandle + clock specifier pairs
- target-supply : regulator for SATA target power
-Example:
+allwinner,sun4i-a10-ahci required properties:
+- clocks : index 0 must point to the sata_ref clk, 1 to the ahb clk
+
+Examples:
sata at ffe08000 {
compatible = "snps,spear-ahci";
reg = <0xffe08000 0x1000>;
interrupts = <115>;
-
};
+
+ ahci: sata at 01c18000 {
+ compatible = "allwinner,sun4i-a10-ahci";
+ reg = <0x01c18000 0x1000>;
+ interrupts = <56>;
+ clocks = <&pll6 0>, <&ahb_gates 25>;
+ target-supply = <®_ahci_5v>;
+ };
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 4e73772..cc67cc0 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -106,6 +106,15 @@ config AHCI_IMX
If unsure, say N.
+config AHCI_SUNXI
+ tristate "Allwinner sunxi AHCI SATA support"
+ depends on ARCH_SUNXI && SATA_AHCI_PLATFORM
+ help
+ This option enables support for the Allwinner sunxi SoC's
+ onboard AHCI SATA.
+
+ If unsure, say N.
+
config SATA_FSL
tristate "Freescale 3.0Gbps SATA support"
depends on FSL_SOC
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 46518c6..246050b 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o
obj-$(CONFIG_AHCI_IMX) += ahci_imx.o
+obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o
# SFF w/ custom DMA
obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c
new file mode 100644
index 0000000..568a211
--- /dev/null
+++ b/drivers/ata/ahci_sunxi.c
@@ -0,0 +1,251 @@
+/*
+ * Allwinner sunxi AHCI SATA platform driver
+ * Copyright 2013 Olliver Schinagl <oliver@schinagl.nl>
+ * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
+ * Based on code from Allwinner Technology Co., Ltd. <www.allwinnertech.com>,
+ * Daniel Wang <danielwang@allwinnertech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/ahci_platform.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include "ahci.h"
+
+#define AHCI_BISTAFR 0x00a0
+#define AHCI_BISTCR 0x00a4
+#define AHCI_BISTFCTR 0x00a8
+#define AHCI_BISTSR 0x00ac
+#define AHCI_BISTDECR 0x00b0
+#define AHCI_DIAGNR0 0x00b4
+#define AHCI_DIAGNR1 0x00b8
+#define AHCI_OOBR 0x00bc
+#define AHCI_PHYCS0R 0x00c0
+#define AHCI_PHYCS1R 0x00c4
+#define AHCI_PHYCS2R 0x00c8
+#define AHCI_TIMER1MS 0x00e0
+#define AHCI_GPARAM1R 0x00e8
+#define AHCI_GPARAM2R 0x00ec
+#define AHCI_PPARAMR 0x00f0
+#define AHCI_TESTR 0x00f4
+#define AHCI_VERSIONR 0x00f8
+#define AHCI_IDR 0x00fc
+#define AHCI_RWCR 0x00fc
+#define AHCI_P0DMACR 0x0170
+#define AHCI_P0PHYCR 0x0178
+#define AHCI_P0PHYSR 0x017c
+
+static void sunxi_clrbits(void __iomem *reg, u32 clr_val)
+{
+ u32 reg_val;
+
+ reg_val = readl(reg);
+ reg_val &= ~(clr_val);
+ writel(reg_val, reg);
+}
+
+static void sunxi_setbits(void __iomem *reg, u32 set_val)
+{
+ u32 reg_val;
+
+ reg_val = readl(reg);
+ reg_val |= set_val;
+ writel(reg_val, reg);
+}
+
+static void sunxi_clrsetbits(void __iomem *reg, u32 clr_val, u32 set_val)
+{
+ u32 reg_val;
+
+ reg_val = readl(reg);
+ reg_val &= ~(clr_val);
+ reg_val |= set_val;
+ writel(reg_val, reg);
+}
+
+static u32 sunxi_getbits(void __iomem *reg, u8 mask, u8 shift)
+{
+ return (readl(reg) >> shift) & mask;
+}
+
+static int ahci_sunxi_phy_init(struct device *dev, void __iomem *reg_base)
+{
+ u32 reg_val;
+ int timeout;
+
+ /* This magic is from the original code */
+ writel(0, reg_base + AHCI_RWCR);
+ mdelay(5);
+
+ sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(19));
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS0R,
+ (0x7 << 24),
+ (0x5 << 24) | BIT(23) | BIT(18));
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS1R,
+ (0x3 << 16) | (0x1f << 8) | (0x3 << 6),
+ (0x2 << 16) | (0x6 << 8) | (0x2 << 6));
+ sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(28) | BIT(15));
+ sunxi_clrbits(reg_base + AHCI_PHYCS1R, BIT(19));
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS0R,
+ (0x7 << 20), (0x3 << 20));
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS2R,
+ (0x1f << 5), (0x19 << 5));
+ mdelay(5);
+
+ sunxi_setbits(reg_base + AHCI_PHYCS0R, (0x1 << 19));
+
+ timeout = 250; /* Power up takes aprox 50 us */
+ do {
+ reg_val = sunxi_getbits(reg_base + AHCI_PHYCS0R, 0x7, 28);
+ if (reg_val == 0x02)
+ break;
+
+ if (--timeout == 0) {
+ dev_err(dev, "PHY power up failed.\n");
+ return -EIO;
+ }
+ udelay(1);
+ } while (1);
+
+ sunxi_setbits(reg_base + AHCI_PHYCS2R, (0x1 << 24));
+
+ timeout = 100; /* Calibration takes aprox 10 us */
+ do {
+ reg_val = sunxi_getbits(reg_base + AHCI_PHYCS2R, 0x1, 24);
+ if (reg_val == 0x00)
+ break;
+
+ if (--timeout == 0) {
+ dev_err(dev, "PHY calibration failed.\n");
+ return -EIO;
+ }
+ udelay(1);
+ } while (1);
+
+ mdelay(15);
+
+ writel(0x7, reg_base + AHCI_RWCR);
+
+ return 0;
+}
+
+static void ahci_sunxi_start_engine(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+
+ /* Setup DMA before DMA start */
+ sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ff00, 0x00004400);
+
+ /* Start DMA */
+ sunxi_setbits(port_mmio + PORT_CMD, PORT_CMD_START);
+}
+
+static const struct ata_port_info ahci_sunxi_port_info = {
+ AHCI_HFLAGS(AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
+ AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ),
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_platform_ops,
+};
+
+static int ahci_sunxi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ int rc;
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ hpriv->start_engine = ahci_sunxi_start_engine;
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ goto put_resources;
+
+ rc = ahci_sunxi_phy_init(dev, hpriv->mmio);
+ if (rc)
+ goto disable_resources;
+
+ rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info, 0, 0);
+ if (rc)
+ goto disable_resources;
+
+ return 0;
+
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+put_resources:
+ ahci_platform_put_resources(hpriv);
+ return rc;
+}
+
+#ifdef CONFIG_PM_SLEEP
+int ahci_sunxi_resume(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ int rc;
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ return rc;
+
+ rc = ahci_sunxi_phy_init(dev, hpriv->mmio);
+ if (rc)
+ goto disable_resources;
+
+ rc = ahci_platform_resume_host(dev);
+ if (rc)
+ goto disable_resources;
+
+ return 0;
+
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+ return rc;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(ahci_sunxi_pm_ops, ahci_platform_suspend,
+ ahci_sunxi_resume);
+
+static const struct of_device_id ahci_sunxi_of_match[] = {
+ { .compatible = "allwinner,sun4i-a10-ahci", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ahci_sunxi_of_match);
+
+static struct platform_driver ahci_sunxi_driver = {
+ .probe = ahci_sunxi_probe,
+ .remove = ata_platform_remove_one,
+ .driver = {
+ .name = "ahci-sunxi",
+ .owner = THIS_MODULE,
+ .of_match_table = ahci_sunxi_of_match,
+ .pm = &ahci_sunxi_pm_ops,
+ },
+};
+module_platform_driver(ahci_sunxi_driver);
+
+MODULE_DESCRIPTION("Allwinner sunxi AHCI SATA driver");
+MODULE_AUTHOR("Olliver Schinagl <oliver@schinagl.nl>");
+MODULE_LICENSE("GPL");
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 10/14] ahci-imx: Port to library-ised ahci_platform
From: Hans de Goede @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417489-5354-1-git-send-email-hdegoede@redhat.com>
This avoids the ugliness of creating a nested platform device from probe.
Tested on a wandboard i.mx6 quad.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
.../devicetree/bindings/ata/ahci-platform.txt | 8 +-
drivers/ata/ahci_imx.c | 218 +++++++++------------
2 files changed, 101 insertions(+), 125 deletions(-)
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index 78b2e80..5be0f5b 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -5,8 +5,8 @@ Each SATA controller should have its own node.
Required properties:
- compatible : compatible list, one of "snps,spear-ahci",
- "snps,exynos5440-ahci", "ibm,476gtr-ahci", or
- "allwinner,sun4i-a10-ahci"
+ "snps,exynos5440-ahci", "ibm,476gtr-ahci",
+ "allwinner,sun4i-a10-ahci" or "fsl,imx6q-ahci"
- interrupts : <interrupt mapping for SATA IRQ>
- reg : <registers mapping>
@@ -18,6 +18,10 @@ Optional properties:
allwinner,sun4i-a10-ahci required properties:
- clocks : index 0 must point to the sata_ref clk, 1 to the ahb clk
+fsl,imx6q-ahci required properties:
+- clocks : index 0 must point to the sataf clk, 1 to the sata_ref
+ clk and 2 to the ahb clk
+
Examples:
sata at ffe08000 {
compatible = "snps,spear-ahci";
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index 49fa0ca..2210866 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -34,10 +34,14 @@ enum {
HOST_TIMER1MS = 0xe0, /* Timer 1-ms */
};
+enum {
+ CLK_SATA,
+ CLK_SATA_REF,
+ CLK_AHB
+};
+
struct imx_ahci_priv {
struct platform_device *ahci_pdev;
- struct clk *sata_ref_clk;
- struct clk *ahb_clk;
struct regmap *gpr;
bool no_device;
bool first_time;
@@ -47,6 +51,8 @@ static int ahci_imx_hotplug;
module_param_named(hotplug, ahci_imx_hotplug, int, 0644);
MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support)");
+static void ahci_imx_host_stop(struct ata_host *host);
+
static void ahci_imx_error_handler(struct ata_port *ap)
{
u32 reg_val;
@@ -54,7 +60,7 @@ static void ahci_imx_error_handler(struct ata_port *ap)
struct ata_host *host = dev_get_drvdata(ap->dev);
struct ahci_host_priv *hpriv = host->private_data;
void __iomem *mmio = hpriv->mmio;
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent);
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
ahci_error_handler(ap);
@@ -75,12 +81,13 @@ static void ahci_imx_error_handler(struct ata_port *ap)
regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
IMX6Q_GPR13_SATA_MPLL_CLK_EN,
!IMX6Q_GPR13_SATA_MPLL_CLK_EN);
- clk_disable_unprepare(imxpriv->sata_ref_clk);
+ ahci_platform_disable_clks(hpriv);
imxpriv->no_device = true;
}
static struct ata_port_operations ahci_imx_ops = {
- .inherits = &ahci_platform_ops,
+ .inherits = &ahci_ops,
+ .host_stop = ahci_imx_host_stop,
.error_handler = ahci_imx_error_handler,
};
@@ -91,25 +98,46 @@ static const struct ata_port_info ahci_imx_port_info = {
.port_ops = &ahci_imx_ops,
};
-static int imx6q_sata_init(struct device *dev, struct ahci_host_priv *hpriv)
+static int imx_ahci_probe(struct platform_device *pdev)
{
- int ret = 0;
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ struct imx_ahci_priv *imxpriv;
unsigned int reg_val;
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+ int rc;
+
+ imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL);
+ if (!imxpriv)
+ return -ENOMEM;
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+ if (!hpriv->clks[CLK_AHB]) {
+ dev_err(dev, "no ahb clk, need sata, sata_ref and ahb clks\n");
+ rc = -ENOENT;
+ goto put_resources;
+ }
+ hpriv->plat_data = imxpriv;
imxpriv->gpr =
syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
if (IS_ERR(imxpriv->gpr)) {
dev_err(dev, "failed to find fsl,imx6q-iomux-gpr regmap\n");
- return PTR_ERR(imxpriv->gpr);
+ rc = PTR_ERR(imxpriv->gpr);
+ goto put_resources;
}
- ret = clk_prepare_enable(imxpriv->sata_ref_clk);
- if (ret < 0) {
- dev_err(dev, "prepare-enable sata_ref clock err:%d\n", ret);
- return ret;
+ if (hpriv->target_pwr) {
+ rc = regulator_enable(hpriv->target_pwr);
+ if (rc)
+ goto put_resources;
}
+ rc = ahci_platform_enable_clks(hpriv);
+ if (rc)
+ goto disable_regulator;
+
/*
* set PHY Paremeters, two steps to configure the GPR13,
* one write for rest of parameters, mask of first write
@@ -156,24 +184,53 @@ static int imx6q_sata_init(struct device *dev, struct ahci_host_priv *hpriv)
writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL);
}
- reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
+ reg_val = clk_get_rate(hpriv->clks[CLK_AHB]) / 1000;
writel(reg_val, hpriv->mmio + HOST_TIMER1MS);
+ rc = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, 0, 0);
+ if (rc)
+ goto disable_clks;
+
return 0;
+
+disable_clks:
+ ahci_platform_disable_clks(hpriv);
+disable_regulator:
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+put_resources:
+ ahci_platform_put_resources(hpriv);
+ return rc;
}
-static void imx6q_sata_exit(struct device *dev)
+static void ahci_imx_host_stop(struct ata_host *host)
{
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+ struct ahci_host_priv *hpriv = host->private_data;
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
- regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_MPLL_CLK_EN,
+ if (!imxpriv->no_device) {
+ regmap_update_bits(imxpriv->gpr, 0x34,
+ IMX6Q_GPR13_SATA_MPLL_CLK_EN,
!IMX6Q_GPR13_SATA_MPLL_CLK_EN);
- clk_disable_unprepare(imxpriv->sata_ref_clk);
+ ahci_platform_disable_clks(hpriv);
+ }
+
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+
+ ahci_platform_put_resources(hpriv);
}
static int imx_ahci_suspend(struct device *dev)
{
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
+ int rc;
+
+ rc = ahci_platform_suspend_host(dev);
+ if (rc)
+ return rc;
/*
* If no_device is set, The CLKs had been gated off in the
@@ -183,19 +240,30 @@ static int imx_ahci_suspend(struct device *dev)
regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
IMX6Q_GPR13_SATA_MPLL_CLK_EN,
!IMX6Q_GPR13_SATA_MPLL_CLK_EN);
- clk_disable_unprepare(imxpriv->sata_ref_clk);
+ ahci_platform_disable_clks(hpriv);
}
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+
return 0;
}
static int imx_ahci_resume(struct device *dev)
{
- struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent);
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
int ret;
+ if (hpriv->target_pwr) {
+ ret = regulator_enable(hpriv->target_pwr);
+ if (ret)
+ return ret;
+ }
+
if (!imxpriv->no_device) {
- ret = clk_prepare_enable(imxpriv->sata_ref_clk);
+ ret = ahci_platform_enable_clks(hpriv);
if (ret < 0) {
dev_err(dev, "pre-enable sata_ref clock err:%d\n", ret);
return ret;
@@ -207,123 +275,27 @@ static int imx_ahci_resume(struct device *dev)
usleep_range(1000, 2000);
}
- return 0;
+ return ahci_platform_resume_host(dev);
}
-static struct ahci_platform_data imx6q_sata_pdata = {
- .init = imx6q_sata_init,
- .exit = imx6q_sata_exit,
- .ata_port_info = &ahci_imx_port_info,
- .suspend = imx_ahci_suspend,
- .resume = imx_ahci_resume,
-};
+static SIMPLE_DEV_PM_OPS(ahci_imx_pm_ops, imx_ahci_suspend, imx_ahci_resume);
static const struct of_device_id imx_ahci_of_match[] = {
- { .compatible = "fsl,imx6q-ahci", .data = &imx6q_sata_pdata},
+ { .compatible = "fsl,imx6q-ahci", },
{},
};
MODULE_DEVICE_TABLE(of, imx_ahci_of_match);
-static int imx_ahci_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct resource *mem, *irq, res[2];
- const struct of_device_id *of_id;
- const struct ahci_platform_data *pdata = NULL;
- struct imx_ahci_priv *imxpriv;
- struct device *ahci_dev;
- struct platform_device *ahci_pdev;
- int ret;
-
- imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL);
- if (!imxpriv) {
- dev_err(dev, "can't alloc ahci_host_priv\n");
- return -ENOMEM;
- }
-
- ahci_pdev = platform_device_alloc("ahci", -1);
- if (!ahci_pdev)
- return -ENODEV;
-
- ahci_dev = &ahci_pdev->dev;
- ahci_dev->parent = dev;
-
- imxpriv->no_device = false;
- imxpriv->first_time = true;
- imxpriv->ahb_clk = devm_clk_get(dev, "ahb");
- if (IS_ERR(imxpriv->ahb_clk)) {
- dev_err(dev, "can't get ahb clock.\n");
- ret = PTR_ERR(imxpriv->ahb_clk);
- goto err_out;
- }
-
- imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref");
- if (IS_ERR(imxpriv->sata_ref_clk)) {
- dev_err(dev, "can't get sata_ref clock.\n");
- ret = PTR_ERR(imxpriv->sata_ref_clk);
- goto err_out;
- }
-
- imxpriv->ahci_pdev = ahci_pdev;
- platform_set_drvdata(pdev, imxpriv);
-
- of_id = of_match_device(imx_ahci_of_match, dev);
- if (of_id) {
- pdata = of_id->data;
- } else {
- ret = -EINVAL;
- goto err_out;
- }
-
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!mem || !irq) {
- dev_err(dev, "no mmio/irq resource\n");
- ret = -ENOMEM;
- goto err_out;
- }
-
- res[0] = *mem;
- res[1] = *irq;
-
- ahci_dev->coherent_dma_mask = DMA_BIT_MASK(32);
- ahci_dev->dma_mask = &ahci_dev->coherent_dma_mask;
- ahci_dev->of_node = dev->of_node;
-
- ret = platform_device_add_resources(ahci_pdev, res, 2);
- if (ret)
- goto err_out;
-
- ret = platform_device_add_data(ahci_pdev, pdata, sizeof(*pdata));
- if (ret)
- goto err_out;
-
- ret = platform_device_add(ahci_pdev);
- if (ret) {
-err_out:
- platform_device_put(ahci_pdev);
- return ret;
- }
-
- return 0;
-}
-static int imx_ahci_remove(struct platform_device *pdev)
-{
- struct imx_ahci_priv *imxpriv = platform_get_drvdata(pdev);
- struct platform_device *ahci_pdev = imxpriv->ahci_pdev;
-
- platform_device_unregister(ahci_pdev);
- return 0;
-}
static struct platform_driver imx_ahci_driver = {
.probe = imx_ahci_probe,
- .remove = imx_ahci_remove,
+ .remove = ata_platform_remove_one,
.driver = {
.name = "ahci-imx",
.owner = THIS_MODULE,
.of_match_table = imx_ahci_of_match,
+ .pm = &ahci_imx_pm_ops,
},
};
module_platform_driver(imx_ahci_driver);
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 11/14] ahci-imx: Add imx_ahci_phy_init / _exit helpers
From: Hans de Goede @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417489-5354-1-git-send-email-hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/ata/ahci_imx.c | 142 +++++++++++++++++++++++++++----------------------
1 file changed, 77 insertions(+), 65 deletions(-)
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index 2210866..e58e062 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -51,6 +51,7 @@ static int ahci_imx_hotplug;
module_param_named(hotplug, ahci_imx_hotplug, int, 0644);
MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support)");
+static void imx_ahci_phy_exit(struct ahci_host_priv *hpriv);
static void ahci_imx_host_stop(struct ata_host *host);
static void ahci_imx_error_handler(struct ata_port *ap)
@@ -78,10 +79,8 @@ static void ahci_imx_error_handler(struct ata_port *ap)
*/
reg_val = readl(mmio + PORT_PHY_CTL);
writel(reg_val | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL);
- regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
- IMX6Q_GPR13_SATA_MPLL_CLK_EN,
- !IMX6Q_GPR13_SATA_MPLL_CLK_EN);
- ahci_platform_disable_clks(hpriv);
+
+ imx_ahci_phy_exit(hpriv);
imxpriv->no_device = true;
}
@@ -98,40 +97,18 @@ static const struct ata_port_info ahci_imx_port_info = {
.port_ops = &ahci_imx_ops,
};
-static int imx_ahci_probe(struct platform_device *pdev)
+static int imx_ahci_phy_init(struct ahci_host_priv *hpriv)
{
- struct device *dev = &pdev->dev;
- struct ahci_host_priv *hpriv;
- struct imx_ahci_priv *imxpriv;
- unsigned int reg_val;
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
int rc;
- imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL);
- if (!imxpriv)
- return -ENOMEM;
-
- hpriv = ahci_platform_get_resources(pdev);
- if (IS_ERR(hpriv))
- return PTR_ERR(hpriv);
- if (!hpriv->clks[CLK_AHB]) {
- dev_err(dev, "no ahb clk, need sata, sata_ref and ahb clks\n");
- rc = -ENOENT;
- goto put_resources;
- }
- hpriv->plat_data = imxpriv;
-
- imxpriv->gpr =
- syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
- if (IS_ERR(imxpriv->gpr)) {
- dev_err(dev, "failed to find fsl,imx6q-iomux-gpr regmap\n");
- rc = PTR_ERR(imxpriv->gpr);
- goto put_resources;
- }
+ if (imxpriv->no_device)
+ return 0;
if (hpriv->target_pwr) {
rc = regulator_enable(hpriv->target_pwr);
if (rc)
- goto put_resources;
+ return rc;
}
rc = ahci_platform_enable_clks(hpriv);
@@ -144,7 +121,8 @@ static int imx_ahci_probe(struct platform_device *pdev)
* is 0x07ffffff, and the other one write for setting
* the mpll_clk_en.
*/
- regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13
+ , IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK
| IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK
| IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK
| IMX6Q_GPR13_SATA_SPD_MODE_MASK
@@ -162,9 +140,69 @@ static int imx_ahci_probe(struct platform_device *pdev)
| IMX6Q_GPR13_SATA_TX_ATTEN_9_16
| IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB
| IMX6Q_GPR13_SATA_TX_LVL_1_025_V);
- regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_MPLL_CLK_EN,
+
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
+ IMX6Q_GPR13_SATA_MPLL_CLK_EN,
IMX6Q_GPR13_SATA_MPLL_CLK_EN);
- usleep_range(100, 200);
+
+ usleep_range(1000, 2000);
+ return 0;
+
+disable_regulator:
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+ return rc;
+}
+
+static void imx_ahci_phy_exit(struct ahci_host_priv *hpriv)
+{
+ struct imx_ahci_priv *imxpriv = hpriv->plat_data;
+
+ if (imxpriv->no_device)
+ return;
+
+ regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
+ IMX6Q_GPR13_SATA_MPLL_CLK_EN,
+ !IMX6Q_GPR13_SATA_MPLL_CLK_EN);
+ ahci_platform_disable_clks(hpriv);
+
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+}
+
+static int imx_ahci_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ struct imx_ahci_priv *imxpriv;
+ unsigned int reg_val;
+ int rc;
+
+ imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL);
+ if (!imxpriv)
+ return -ENOMEM;
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+ if (!hpriv->clks[CLK_AHB]) {
+ dev_err(dev, "no ahb clk, need sata, sata_ref and ahb clks\n");
+ rc = -ENOENT;
+ goto put_resources;
+ }
+ hpriv->plat_data = imxpriv;
+
+ imxpriv->gpr =
+ syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
+ if (IS_ERR(imxpriv->gpr)) {
+ dev_err(dev, "failed to find fsl,imx6q-iomux-gpr regmap\n");
+ rc = PTR_ERR(imxpriv->gpr);
+ goto put_resources;
+ }
+
+ rc = imx_ahci_phy_init(hpriv);
+ if (rc)
+ goto put_resources;
/*
* Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL,
@@ -189,15 +227,12 @@ static int imx_ahci_probe(struct platform_device *pdev)
rc = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info, 0, 0);
if (rc)
- goto disable_clks;
+ goto phy_exit;
return 0;
-disable_clks:
- ahci_platform_disable_clks(hpriv);
-disable_regulator:
- if (hpriv->target_pwr)
- regulator_disable(hpriv->target_pwr);
+phy_exit:
+ imx_ahci_phy_exit(hpriv);
put_resources:
ahci_platform_put_resources(hpriv);
return rc;
@@ -206,18 +241,8 @@ put_resources:
static void ahci_imx_host_stop(struct ata_host *host)
{
struct ahci_host_priv *hpriv = host->private_data;
- struct imx_ahci_priv *imxpriv = hpriv->plat_data;
-
- if (!imxpriv->no_device) {
- regmap_update_bits(imxpriv->gpr, 0x34,
- IMX6Q_GPR13_SATA_MPLL_CLK_EN,
- !IMX6Q_GPR13_SATA_MPLL_CLK_EN);
- ahci_platform_disable_clks(hpriv);
- }
-
- if (hpriv->target_pwr)
- regulator_disable(hpriv->target_pwr);
+ imx_ahci_phy_exit(hpriv);
ahci_platform_put_resources(hpriv);
}
@@ -225,26 +250,13 @@ static int imx_ahci_suspend(struct device *dev)
{
struct ata_host *host = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = host->private_data;
- struct imx_ahci_priv *imxpriv = hpriv->plat_data;
int rc;
rc = ahci_platform_suspend_host(dev);
if (rc)
return rc;
- /*
- * If no_device is set, The CLKs had been gated off in the
- * initialization so don't do it again here.
- */
- if (!imxpriv->no_device) {
- regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
- IMX6Q_GPR13_SATA_MPLL_CLK_EN,
- !IMX6Q_GPR13_SATA_MPLL_CLK_EN);
- ahci_platform_disable_clks(hpriv);
- }
-
- if (hpriv->target_pwr)
- regulator_disable(hpriv->target_pwr);
+ imx_ahci_phy_exit(hpriv);
return 0;
}
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 12/14] ahci-imx: Fix link not coming back up after suspend / resume
From: Hans de Goede @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417489-5354-1-git-send-email-hdegoede@redhat.com>
The phy needs to be re-initialized on resume for the link to properly come
back up.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/ata/ahci_imx.c | 22 +++-------------------
1 file changed, 3 insertions(+), 19 deletions(-)
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index e58e062..68d89fa 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -265,27 +265,11 @@ static int imx_ahci_resume(struct device *dev)
{
struct ata_host *host = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = host->private_data;
- struct imx_ahci_priv *imxpriv = hpriv->plat_data;
int ret;
- if (hpriv->target_pwr) {
- ret = regulator_enable(hpriv->target_pwr);
- if (ret)
- return ret;
- }
-
- if (!imxpriv->no_device) {
- ret = ahci_platform_enable_clks(hpriv);
- if (ret < 0) {
- dev_err(dev, "pre-enable sata_ref clock err:%d\n", ret);
- return ret;
- }
-
- regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13,
- IMX6Q_GPR13_SATA_MPLL_CLK_EN,
- IMX6Q_GPR13_SATA_MPLL_CLK_EN);
- usleep_range(1000, 2000);
- }
+ ret = imx_ahci_phy_init(hpriv);
+ if (ret)
+ return ret;
return ahci_platform_resume_host(dev);
}
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 13/14] ARM: sun4i: dts: Add ahci / sata support
From: Hans de Goede @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417489-5354-1-git-send-email-hdegoede@redhat.com>
From: Oliver Schinagl <oliver@schinagl.nl>
This patch adds sunxi sata support to A10 boards that have such a connector.
Some boards also feature a regulator via a GPIO and support for this is also
added.
Signed-off-by: Olliver Schinagl <oliver@schinagl.nl>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun4i-a10-a1000.dts | 4 ++++
arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 6 +++++
arch/arm/boot/dts/sun4i-a10.dtsi | 8 +++++++
arch/arm/boot/dts/sunxi-ahci-reg.dtsi | 38 ++++++++++++++++++++++++++++++
4 files changed, 56 insertions(+)
create mode 100644 arch/arm/boot/dts/sunxi-ahci-reg.dtsi
diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts
index aef8207..3fb7305 100644
--- a/arch/arm/boot/dts/sun4i-a10-a1000.dts
+++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts
@@ -48,6 +48,10 @@
status = "okay";
};
+ ahci: sata at 01c18000 {
+ status = "okay";
+ };
+
pinctrl at 01c20800 {
mmc0_cd_pin_a1000: mmc0_cd_pin at 0 {
allwinner,pins = "PH1";
diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
index f50fb2b..6ae1110 100644
--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
@@ -12,6 +12,7 @@
/dts-v1/;
/include/ "sun4i-a10.dtsi"
+/include/ "sunxi-ahci-reg.dtsi"
/ {
model = "Cubietech Cubieboard";
@@ -51,6 +52,11 @@
status = "okay";
};
+ ahci: sata at 01c18000 {
+ target-supply = <®_ahci_5v>;
+ status = "okay";
+ };
+
pinctrl at 01c20800 {
mmc0_cd_pin_cubieboard: mmc0_cd_pin at 0 {
allwinner,pins = "PH1";
diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 4736dd2..198dcda 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -331,6 +331,14 @@
status = "disabled";
};
+ ahci: sata at 01c18000 {
+ compatible = "allwinner,sun4i-a10-ahci";
+ reg = <0x01c18000 0x1000>;
+ interrupts = <56>;
+ clocks = <&pll6 0>, <&ahb_gates 25>;
+ status = "disabled";
+ };
+
intc: interrupt-controller at 01c20400 {
compatible = "allwinner,sun4i-ic";
reg = <0x01c20400 0x400>;
diff --git a/arch/arm/boot/dts/sunxi-ahci-reg.dtsi b/arch/arm/boot/dts/sunxi-ahci-reg.dtsi
new file mode 100644
index 0000000..955b197
--- /dev/null
+++ b/arch/arm/boot/dts/sunxi-ahci-reg.dtsi
@@ -0,0 +1,38 @@
+/*
+ * sunxi boards sata target power supply common code
+ *
+ * Copyright 2014 - Hans de Goede <hdegoede@redhat.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/ {
+ soc at 01c00000 {
+ ahci_pwr_pin_a: ahci_pwr_pin at 0 {
+ allwinner,pins = "PB8";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ pinctrl-names = "default";
+
+ reg_ahci_5v: ahci-5v {
+ compatible = "regulator-fixed";
+ regulator-name = "ahci-5v";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ pinctrl-0 = <&ahci_pwr_pin_a>;
+ gpio = <&pio 1 8 0>;
+ enable-active-high;
+ };
+ };
+};
--
1.8.5.3
^ permalink raw reply related
* [PATCH v5 14/14] ARM: sun7i: dts: Add ahci / sata support
From: Hans de Goede @ 2014-01-22 19:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390417489-5354-1-git-send-email-hdegoede@redhat.com>
This patch adds sunxi sata support to A20 boards that have such a connector.
Some boards also feature a regulator via a GPIO and support for this is also
added.
Signed-off-by: Olliver Schinagl <oliver@schinagl.nl>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 6 ++++++
arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 20 ++++++++++++++++++++
arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 6 ++++++
arch/arm/boot/dts/sun7i-a20.dtsi | 8 ++++++++
4 files changed, 40 insertions(+)
diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
index 48777cd..1cab521 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
@@ -13,6 +13,7 @@
/dts-v1/;
/include/ "sun7i-a20.dtsi"
+/include/ "sunxi-ahci-reg.dtsi"
/ {
model = "Cubietech Cubieboard2";
@@ -28,6 +29,11 @@
status = "okay";
};
+ ahci: sata at 01c18000 {
+ target-supply = <®_ahci_5v>;
+ status = "okay";
+ };
+
pinctrl at 01c20800 {
mmc0_cd_pin_cubieboard2: mmc0_cd_pin at 0 {
allwinner,pins = "PH1";
diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
index 2684f27..1247ea1 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -13,6 +13,7 @@
/dts-v1/;
/include/ "sun7i-a20.dtsi"
+/include/ "sunxi-ahci-reg.dtsi"
/ {
model = "Cubietech Cubietruck";
@@ -28,6 +29,11 @@
status = "okay";
};
+ ahci: sata at 01c18000 {
+ target-supply = <®_ahci_5v>;
+ status = "okay";
+ };
+
pinctrl at 01c20800 {
mmc0_cd_pin_cubietruck: mmc0_cd_pin at 0 {
allwinner,pins = "PH1";
@@ -36,6 +42,13 @@
allwinner,pull = <0>;
};
+ ahci_pwr_pin_cubietruck: ahci_pwr_pin at 1 {
+ allwinner,pins = "PH12";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
led_pins_cubietruck: led_pins at 0 {
allwinner,pins = "PH7", "PH11", "PH20", "PH21";
allwinner,function = "gpio_out";
@@ -84,4 +97,11 @@
gpios = <&pio 7 7 0>;
};
};
+
+ regulators {
+ reg_ahci_5v: ahci-5v {
+ pinctrl-0 = <&ahci_pwr_pin_cubietruck>;
+ gpio = <&pio 7 12 0>;
+ };
+ };
};
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
index bf6f6c8..f135886 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
@@ -13,6 +13,7 @@
/dts-v1/;
/include/ "sun7i-a20.dtsi"
+/include/ "sunxi-ahci-reg.dtsi"
/ {
model = "Olimex A20-Olinuxino Micro";
@@ -37,6 +38,11 @@
status = "okay";
};
+ ahci: sata at 01c18000 {
+ target-supply = <®_ahci_5v>;
+ status = "okay";
+ };
+
pinctrl at 01c20800 {
mmc0_cd_pin_olinuxinom: mmc0_cd_pin at 0 {
allwinner,pins = "PH1";
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index c9c123a..0657bad 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -347,6 +347,14 @@
status = "disabled";
};
+ ahci: sata at 01c18000 {
+ compatible = "allwinner,sun4i-a10-ahci";
+ reg = <0x01c18000 0x1000>;
+ interrupts = <0 56 1>;
+ clocks = <&pll6 0>, <&ahb_gates 25>;
+ status = "disabled";
+ };
+
pio: pinctrl at 01c20800 {
compatible = "allwinner,sun7i-a20-pinctrl";
reg = <0x01c20800 0x400>;
--
1.8.5.3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox