Hi everyone,
Although I'm not present at the Linaro Connect hacking
sessions, I am participating remotely and have tried
hacking on multiplatform support for Exynos. This patch
set is far from complete, but I think the patches
can be useful anyway.
The series gets increasingly fishy towards the end,
and we should probably not apply any of the last nine
patches as-is, nor do I expect everything to work, since
I have not tested them at all.
With this patch set, we can build mach-exynos as part
of a multiplatform kernel, with the following caveats:
* Only DT based boards are supported
* Moving to common-clk breaks things including cpufreq
and others. Thomas is working on a patch for this
* We disable the gpio implementation, which also breaks
stuff, but Thomas has a patch already
* Using the generic DMA engine API in SPI and ASoC
means they no longer work on S3C
* I did not like the solution for the UART driver, but
could also not think of a better one.
* The FB_S3C, S3C2410_WATCHDOG and S3C_ADC drivers
are left as an exercise to the reader, they are
currently disabled with multiplatform
* sparsemem support is not available on multiplatform
The patches are based on v3.9-rc1 and I have pushed
the git branch to
git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git testing/exynos-multiplatform
I have not yet added subsystem maintainers to Cc on the
patches, I'd like to coordinate with the other people
involved first, so see if they already have patches
for the same drivers.
Arnd
Arnd Bergmann (23):
ARM: exynos: introduce EXYNOS_ATAGS symbol
irqchip: exynos: remove dependency on mach/irqs.h
tty: serial/samsung: prepare for common clock API
tty: serial/samsung: make register definitions global
tty: serial/samsung: fix modular build
ARM: exynos: move debug-macro.S to include/debug/
i2c: s3c2410: make header file local
mmc: sdhci-s3c: remove platform dependencies
usb: exynos: do not include plat/usb-phy.h
[media] exynos: remove unnecessary header inclusions
video/exynos: remove unnecessary header inclusions
thermal/exynos: remove unnecessary header inclusions
mtd: onenand/samsung: make regs-onenand.h file local
rtc: s3c: make header file local
spi: s3c64xx: move to generic dmaengine API
pwm: samsung: repair the worst MMIO abuses
ASoC: samsung: move plat/ headers to local directory
ASoC: samsung: convert to dmaengine API
ASoC: samsung: use irq resource for idma
ARM: exynos: prepare for sparse IRQ
ARM: exynos: hack to disable private clock code
ARM: exynos: work around missing gpio code on multiplatform
ARM: exynos: experimental multiplatform support
arch/arm/Kconfig | 11 +-
arch/arm/Kconfig.debug | 8 +
arch/arm/include/debug/exynos.S | 39 +++
arch/arm/include/debug/samsung.S | 87 +++++++
arch/arm/mach-exynos/Kconfig | 36 ++-
arch/arm/mach-exynos/Makefile | 5 +
arch/arm/mach-exynos/common.c | 14 +-
arch/arm/mach-exynos/common.h | 2 +-
arch/arm/mach-exynos/dev-audio.c | 1 +
arch/arm/mach-exynos/dev-uart.c | 1 +
arch/arm/mach-exynos/include/mach/debug-macro.S | 39 ---
arch/arm/mach-exynos/include/mach/gpio.h | 2 +
arch/arm/mach-exynos/include/mach/irqs.h | 5 +-
arch/arm/mach-exynos/mach-armlex4210.c | 3 +
arch/arm/mach-exynos/mach-exynos4-dt.c | 2 +
arch/arm/mach-exynos/mach-exynos5-dt.c | 2 +
arch/arm/mach-exynos/mach-nuri.c | 2 +
arch/arm/mach-exynos/mach-origen.c | 3 +
arch/arm/mach-exynos/mach-smdk4x12.c | 2 +
arch/arm/mach-exynos/mach-smdkv310.c | 3 +
arch/arm/mach-exynos/setup-i2c0.c | 3 +-
arch/arm/mach-exynos/setup-sdhci-gpio.c | 2 +-
arch/arm/mach-exynos/setup-usb-phy.c | 8 +-
arch/arm/mach-s3c24xx/clock-s3c2440.c | 5 +
arch/arm/mach-s3c24xx/common.c | 5 +
arch/arm/mach-s3c24xx/dma-s3c2410.c | 2 -
arch/arm/mach-s3c24xx/dma-s3c2412.c | 2 -
arch/arm/mach-s3c24xx/dma-s3c2440.c | 2 -
arch/arm/mach-s3c24xx/dma-s3c2443.c | 2 -
arch/arm/mach-s3c24xx/include/mach/debug-macro.S | 2 +-
arch/arm/mach-s3c24xx/mach-rx1950.c | 1 -
arch/arm/mach-s3c64xx/include/mach/debug-macro.S | 2 +-
arch/arm/mach-s3c64xx/include/mach/gpio.h | 4 +
arch/arm/mach-s3c64xx/setup-usb-phy.c | 4 +-
arch/arm/mach-s5p64x0/include/mach/debug-macro.S | 2 +-
arch/arm/mach-s5pc100/include/mach/debug-macro.S | 2 +-
arch/arm/mach-s5pc100/setup-sdhci-gpio.c | 1 -
arch/arm/mach-s5pv210/include/mach/debug-macro.S | 2 +-
arch/arm/mach-s5pv210/setup-sdhci-gpio.c | 1 -
arch/arm/mach-s5pv210/setup-usb-phy.c | 4 +-
arch/arm/plat-samsung/Kconfig | 5 +
arch/arm/plat-samsung/Makefile | 3 +
arch/arm/plat-samsung/clock-clksrc.c | 3 +
arch/arm/plat-samsung/devs.c | 17 +-
arch/arm/plat-samsung/include/plat/debug-macro.S | 87 -------
arch/arm/plat-samsung/include/plat/gpio-core.h | 3 +
arch/arm/plat-samsung/include/plat/regs-ac97.h | 67 -----
arch/arm/plat-samsung/include/plat/regs-iic.h | 56 -----
arch/arm/plat-samsung/include/plat/regs-iis.h | 70 ------
arch/arm/plat-samsung/include/plat/regs-onenand.h | 63 -----
arch/arm/plat-samsung/include/plat/regs-rtc.h | 71 ------
arch/arm/plat-samsung/include/plat/regs-sdhci.h | 87 -------
arch/arm/plat-samsung/include/plat/regs-serial.h | 282 +---------------------
arch/arm/plat-samsung/include/plat/sdhci.h | 56 +----
arch/arm/plat-samsung/include/plat/usb-phy.h | 5 +-
arch/arm/plat-samsung/irq-vic-timer.c | 1 +
arch/arm/plat-samsung/pm-gpio.c | 1 +
arch/arm/plat-samsung/pm.c | 1 +
arch/arm/plat-samsung/s5p-clock.c | 3 +
arch/arm/plat-samsung/s5p-irq.c | 1 +
drivers/cpufreq/Kconfig.arm | 4 +-
drivers/devfreq/Kconfig | 1 +
drivers/gpio/Makefile | 2 +-
drivers/i2c/busses/i2c-s3c2410.c | 3 +-
drivers/i2c/busses/i2c-s3c2410.h | 56 +++++
drivers/irqchip/exynos-combiner.c | 113 +++++----
drivers/media/platform/exynos-gsc/gsc-regs.c | 1 -
drivers/media/platform/s5p-tv/sii9234_drv.c | 3 -
drivers/mmc/host/Kconfig | 2 +-
drivers/mmc/host/sdhci-s3c-regs.h | 87 +++++++
drivers/mmc/host/sdhci-s3c.c | 5 +-
drivers/mtd/onenand/samsung.c | 4 +-
drivers/mtd/onenand/samsung.h | 61 +++++
drivers/pwm/pwm-samsung.c | 60 +++--
drivers/rtc/rtc-s3c.c | 3 +-
drivers/rtc/rtc-s3c.h | 70 ++++++
drivers/spi/spi-s3c64xx.c | 107 ++++----
drivers/thermal/exynos_thermal.c | 2 -
drivers/tty/serial/samsung.c | 17 +-
drivers/tty/serial/samsung.h | 4 +-
drivers/usb/host/ehci-s5p.c | 1 -
drivers/usb/host/ohci-exynos.c | 1 -
drivers/video/Kconfig | 2 +-
drivers/video/exynos/exynos_mipi_dsi.c | 2 -
drivers/video/exynos/exynos_mipi_dsi_common.c | 2 -
drivers/video/exynos/exynos_mipi_dsi_lowlevel.c | 2 -
drivers/watchdog/Kconfig | 1 +
include/linux/platform_data/mmc-sdhci-s3c.h | 56 +++++
include/linux/platform_data/spi-s3c64xx.h | 3 +
include/linux/serial_s3c.h | 260 ++++++++++++++++++++
sound/soc/samsung/ac97.c | 17 +-
sound/soc/samsung/dma.c | 104 ++++----
sound/soc/samsung/dma.h | 4 +-
sound/soc/samsung/h1940_uda1380.c | 2 +-
sound/soc/samsung/i2s.c | 9 +-
sound/soc/samsung/idma.c | 10 +-
sound/soc/samsung/neo1973_wm8753.c | 2 +-
sound/soc/samsung/pcm.c | 13 -
sound/soc/samsung/regs-ac97.h | 67 +++++
sound/soc/samsung/regs-iis.h | 70 ++++++
sound/soc/samsung/rx1950_uda1380.c | 2 +-
sound/soc/samsung/s3c2412-i2s.c | 10 -
sound/soc/samsung/s3c24xx-i2s.c | 12 +-
sound/soc/samsung/s3c24xx_uda134x.c | 2 +-
sound/soc/samsung/spdif.c | 6 -
105 files changed, 1262 insertions(+), 1208 deletions(-)
create mode 100644 arch/arm/include/debug/exynos.S
create mode 100644 arch/arm/include/debug/samsung.S
delete mode 100644 arch/arm/mach-exynos/include/mach/debug-macro.S
delete mode 100644 arch/arm/plat-samsung/include/plat/debug-macro.S
delete mode 100644 arch/arm/plat-samsung/include/plat/regs-ac97.h
delete mode 100644 arch/arm/plat-samsung/include/plat/regs-iic.h
delete mode 100644 arch/arm/plat-samsung/include/plat/regs-iis.h
delete mode 100644 arch/arm/plat-samsung/include/plat/regs-onenand.h
delete mode 100644 arch/arm/plat-samsung/include/plat/regs-rtc.h
delete mode 100644 arch/arm/plat-samsung/include/plat/regs-sdhci.h
create mode 100644 drivers/i2c/busses/i2c-s3c2410.h
create mode 100644 drivers/mmc/host/sdhci-s3c-regs.h
create mode 100644 drivers/mtd/onenand/samsung.h
create mode 100644 drivers/rtc/rtc-s3c.h
create mode 100644 include/linux/platform_data/mmc-sdhci-s3c.h
create mode 100644 include/linux/serial_s3c.h
create mode 100644 sound/soc/samsung/regs-ac97.h
create mode 100644 sound/soc/samsung/regs-iis.h
--
1.8.1.2
As a preparation for multiplatform support, this introduces
a new Kconfig symbol to split the ATAGS based EXYNOS platforms
from the DT based ones. Turning off CONFIG_EXYNOS_ATAGS disables
all platforms that are not yet converted to DT, and we can
have code that relies on DT checking for this symbol being
disabled.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/mach-exynos/Kconfig | 15 +++++++++++++++
1 file changed, 15 insertions(+)
@@ -176,7 +176,20 @@ config EXYNOS_SETUP_SPIhelpCommonsetupcodeforSPIGPIOconfigurations.++configEXYNOS_ATAGS+bool"ATAGS based boot for EXYNOS (deprecated)"+depends onARCH_EXYNOS_SINGLE+depends onATAGS+defaulty+help+TheEXYNOSplatformismovingtowardsbeingcompletelyprobed+throughdevicetree.Thisenablessupportforboardfilesusing+thetraditionalATAGSbootformat.+Notethatthisoptionisnotavailableformultiplatformbuilds.+# machine support+ifEXYNOS_ATAGSifARCH_EXYNOS4
@@ -400,6 +413,8 @@ config MACH_SMDK4412MachinesupportforSamsungSMDK4412endif+endif+comment"Flattened Device Tree based board for EXYNOS SoCs"configMACH_EXYNOS4_DT
As a preparation for multiplatform, this changes the exynos
"combiner" irqchip to no longer make any assumptions about
using specific IRQ numbers or the number of combiners in the
system.
For this, we have to revert to always initializing the combiner
explicitly from architecture code, rather than using the new
irqchip_init function as we should. The problem is the
dependency on the IRQ base value for the combiner, which is
currently hardcoded in the mach/irqs.h file. Once that file
becomes unused, we can move to irqchip_init again.
Getting rid of the dependency on the number of combiners
actually cleans up the code, because we also remove the
global combiner_data array and pass dynamically allocated
pointers through the irq domain instead.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/mach-exynos/common.c | 5 +-
arch/arm/mach-exynos/common.h | 2 +-
drivers/irqchip/exynos-combiner.c | 113 ++++++++++++++++++++------------------
3 files changed, 64 insertions(+), 56 deletions(-)
@@ -135,7 +109,7 @@ static int combiner_irq_domain_xlate(struct irq_domain *d,if(intsize<2)return-EINVAL;-*out_hwirq=intspec[0]*MAX_IRQ_IN_COMBINER+intspec[1];+*out_hwirq=intspec[0]*IRQ_IN_COMBINER+intspec[1];*out_type=0;return0;
@@ -154,6 +128,8 @@ static int combiner_irq_domain_xlate(struct irq_domain *d,staticintcombiner_irq_domain_map(structirq_domain*d,unsignedintirq,irq_hw_number_thw){+structcombiner_chip_data*combiner_data=d->host_data;+irq_set_chip_and_handler(irq,&combiner_chip,handle_level_irq);irq_set_chip_data(irq,&combiner_data[hw>>3]);set_irq_flags(irq,IRQF_VALID|IRQF_PROBE);
@@ -167,49 +143,80 @@ static struct irq_domain_ops combiner_irq_domain_ops = {};void__initcombiner_init(void__iomem*combiner_base,+intplat_irq_base,structdevice_node*np){inti,irq,irq_base;unsignedintmax_nr,nr_irq;+structirq_domain*domain;+structcombiner_chip_data*combiner_data;-if(np){-if(of_property_read_u32(np,"samsung,combiner-nr",&max_nr)){-pr_warning("%s: number of combiners not specified, "-"setting default as %d.\n",-__func__,EXYNOS4_MAX_COMBINER_NR);-max_nr=EXYNOS4_MAX_COMBINER_NR;-}-}else{+max_nr=0;+if(of_property_read_u32(np,"samsung,combiner-nr",&max_nr)){+#ifdef CONFIG_EXYNOS_ATAGSmax_nr=soc_is_exynos5250()?EXYNOS5_MAX_COMBINER_NR:-EXYNOS4_MAX_COMBINER_NR;+EXYNOS4_MAX_COMBINER_NR;+pr_warning("%s: number of combiners not specified, "+"setting default as %d.\n",__func__,max_nr);+#endif}-nr_irq=max_nr*MAX_IRQ_IN_COMBINER;+if(!max_nr)+return;++nr_irq=max_nr*IRQ_IN_COMBINER;-irq_base=irq_alloc_descs(COMBINER_IRQ(0,0),1,nr_irq,0);+irq_base=irq_alloc_descs(plat_irq_base,1,nr_irq,0);if(IS_ERR_VALUE(irq_base)){-irq_base=COMBINER_IRQ(0,0);+irq_base=plat_irq_base;pr_warning("%s: irq desc alloc failed. Continuing with %d as linux irq base\n",__func__,irq_base);}-combiner_irq_domain=irq_domain_add_legacy(np,nr_irq,irq_base,0,-&combiner_irq_domain_ops,&combiner_data);-if(WARN_ON(!combiner_irq_domain)){+combiner_data=kcalloc(max_nr,sizeof*combiner_data,GFP_KERNEL);+if(WARN_ON(!combiner_data)){+pr_warning("%s: combiner data alloc failed\n",__func__);+return;+}++domain=irq_domain_add_legacy(np,nr_irq,irq_base,0,+&combiner_irq_domain_ops,combiner_data);+if(WARN_ON(!domain)){pr_warning("%s: irq domain init failed\n",__func__);return;}for(i=0;i<max_nr;i++){-combiner_init_one(i,combiner_base+(i>>2)*0x10);+structcombiner_chip_data*data=&combiner_data[i];++data->base=combiner_base+(i>>2)*0x10;+data->irq_offset=irq_find_mapping(domain,+i*IRQ_IN_COMBINER);+data->irq_mask=0xff<<((i%4)<<3);++/* Disable all interrupts */+__raw_writel(data->irq_mask,+data->base+COMBINER_ENABLE_CLEAR);++#ifdef CONFIG_EXYNOS_ATAGSirq=IRQ_SPI(i);+#else+irq=0;+#endif#ifdef CONFIG_OFif(np)irq=irq_of_parse_and_map(np,i);#endif-combiner_cascade_irq(i,irq);+if(irq_set_handler_data(irq,&combiner_data[i])!=0)+BUG();+irq_set_chained_handler(irq,combiner_handle_cascade_irq);}}-#ifdef CONFIG_OF+#ifdef CONFIG_EXYNOS_IRQDOMAIN_CONVERSION_COMPLETE+/*+*wecanonlyrenablethisoneafterallhardcodedIRQnumbers+*aregonefromDTbootedsystemsandwecanallowpicking+*anarbitraryirq_base.+*/staticint__initcombiner_of_init(structdevice_node*np,structdevice_node*parent){
@@ -221,7 +228,7 @@ static int __init combiner_of_init(struct device_node *np,return-ENXIO;}-combiner_init(combiner_base,np);+combiner_init(combiner_base,-1,np);return0;}
With the common clock interface, there is no way to
provide the "clock_source" sysfs attribute for the
samsung serial ports. Given that this file was
purely informational and had fixed contents, we have
reason to believe that no user space programs
were relying on it.
The sysfs file is not documented in the ABI docs.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/tty/serial/samsung.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
The registers for the Samsung S3C serial port are currently defined in
the platform specific arch/arm/plat-samsung/include/plat/regs-serial.h
file, which is not visible to multiplatform capable drivers.
Unfortunately, it is not possible to move the file into a more local
place as we should normally try to, because the same registers
may be used in one of four places:
* In the driver itself
* In platform-independent ARM code for early debug output
* In platform_data definitions
* In the Samsung platform power management code
I have also found no way to logically split out a platform_data
file, other than possibly move everything into
include/linux/platform_data, which also felt wrong. The only
part of this file that makes sense to keep specific to the s3c24xx
platform are the virtual and physical addresses defined here,
which are needed in no other location.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/mach-s3c24xx/clock-s3c2440.c | 5 +
arch/arm/mach-s3c24xx/common.c | 5 +
arch/arm/plat-samsung/include/plat/regs-serial.h | 282 +----------------------
drivers/tty/serial/samsung.c | 6 +-
include/linux/serial_s3c.h | 260 +++++++++++++++++++++
5 files changed, 274 insertions(+), 284 deletions(-)
create mode 100644 include/linux/serial_s3c.h
There are a few bugs in the samsung serial driver when
built as a loadable module, which makes the console
code unavailable, as well as giving no access to
the 'printascii' early debug function. This adds
the appropriate compile time conditionals.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/tty/serial/samsung.c | 4 ++--
drivers/tty/serial/samsung.h | 4 +++-
2 files changed, 5 insertions(+), 3 deletions(-)
@@ -1,39 +0,0 @@-/* linux/arch/arm/mach-exynos4/include/mach/debug-macro.S- *- * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.- * http://www.samsung.com- *- * Based on arch/arm/mach-s3c6400/include/mach/debug-macro.S- *- * This program is free software; you can redistribute it and/or modify- * it under the terms of the GNU General Public License version 2 as- * published by the Free Software Foundation.-*/--/* pull in the relevant register and map files. */--#include <mach/map.h>-- /* note, for the boot process to work we have to keep the UART- * virtual address aligned to an 1MiB boundary for the L1- * mapping the head code makes. We keep the UART virtual address- * aligned and add in the offset when we load the value here.- */-- .macro addruart, rp, rv, tmp- mrc p15, 0, \tmp, c0, c0, 0- and \tmp, \tmp, #0xf0- teq \tmp, #0xf0 @@ A15- ldreq \rp, =EXYNOS5_PA_UART- movne \rp, #EXYNOS4_PA_UART @@ EXYNOS4- ldr \rv, =S3C_VA_UART-#if CONFIG_DEBUG_S3C_UART != 0- add \rp, \rp, #(0x10000 * CONFIG_DEBUG_S3C_UART)- add \rv, \rv, #(0x10000 * CONFIG_DEBUG_S3C_UART)-#endif- .endm--#define fifo_full fifo_full_s5pv210-#define fifo_level fifo_level_s5pv210--#include <plat/debug-macro.S>
No other file in the kernel besides i2c-s3c2410.c uses
the current plat/regs-iic.h, so we can simply move the
header file to live in the same directory as the driver,
as a preparation to multiplatform builds.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/mach-s3c24xx/mach-rx1950.c | 1 -
arch/arm/plat-samsung/devs.c | 1 -
arch/arm/plat-samsung/include/plat/regs-iic.h | 56 ---------------------------
drivers/i2c/busses/i2c-s3c2410.c | 3 +-
drivers/i2c/busses/i2c-s3c2410.h | 56 +++++++++++++++++++++++++++
5 files changed, 58 insertions(+), 59 deletions(-)
delete mode 100644 arch/arm/plat-samsung/include/plat/regs-iic.h
create mode 100644 drivers/i2c/busses/i2c-s3c2410.h
plat/regs-sdhci.h is not used anywhere but in the sdhci-s3c
driver, so it can become a local file there and all other
inclusions removed.
plat/sdhci.h is used only to define the platform devices,
and with the exception of the platform_data structure not
needed by the driver, so we can split out the platform_data
definition instead and leave the rest to platform code.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/mach-exynos/setup-sdhci-gpio.c | 2 +-
arch/arm/mach-s5pc100/setup-sdhci-gpio.c | 1 -
arch/arm/mach-s5pv210/setup-sdhci-gpio.c | 1 -
arch/arm/plat-samsung/include/plat/regs-sdhci.h | 87 -------------------------
arch/arm/plat-samsung/include/plat/sdhci.h | 56 +---------------
drivers/mmc/host/Kconfig | 2 +-
drivers/mmc/host/sdhci-s3c-regs.h | 87 +++++++++++++++++++++++++
drivers/mmc/host/sdhci-s3c.c | 5 +-
include/linux/platform_data/mmc-sdhci-s3c.h | 56 ++++++++++++++++
9 files changed, 148 insertions(+), 149 deletions(-)
delete mode 100644 arch/arm/plat-samsung/include/plat/regs-sdhci.h
create mode 100644 drivers/mmc/host/sdhci-s3c-regs.h
create mode 100644 include/linux/platform_data/mmc-sdhci-s3c.h
@@ -18,62 +18,9 @@#ifndef __PLAT_S3C_SDHCI_H#define __PLAT_S3C_SDHCI_H __FILE__+#include<linux/platform_data/mmc-sdhci-s3c.h>#include<plat/devs.h>-structplatform_device;-structmmc_host;-structmmc_card;-structmmc_ios;--enumcd_types{-S3C_SDHCI_CD_INTERNAL,/* use mmc internal CD line */-S3C_SDHCI_CD_EXTERNAL,/* use external callback */-S3C_SDHCI_CD_GPIO,/* use external gpio pin for CD line */-S3C_SDHCI_CD_NONE,/* no CD line, use polling to detect card */-S3C_SDHCI_CD_PERMANENT,/* no CD line, card permanently wired to host */-};--/**-*structs3c_sdhci_platdata()-PlatformdevicedataforSamsungSDHCI-*@max_width:Themaximumnumberofdatabitssupported.-*@host_caps:StandardMMChostcapabilitiesbitfield.-*@host_caps2:ThesecondstandardMMChostcapabilitiesbitfield.-*@cd_type:TypeofCardDetectionmethod(seecd_typesenumabove)-*@ext_cd_init:Initializeexternalcarddetectsubsystem.Calledon-*sdhci-s3cdriverprobewhencd_type==S3C_SDHCI_CD_EXTERNAL.-*notify_funcargumentisacallbacktothesdhci-s3cdriver-*thattriggersthecarddetectionevent.Callbackarguments:-*devispointertoplatformdeviceofthehostcontroller,-*stateisnewstateofthecard(0-removed,1-inserted).-*@ext_cd_cleanup:Cleanupexternalcarddetectsubsystem.Calledon-*sdhci-s3cdriverremovewhencd_type==S3C_SDHCI_CD_EXTERNAL.-*notify_funcargumentisthesamecallbackasforext_cd_init.-*@ext_cd_gpio:gpiopinusedforexternalCDline,validonlyif-*cd_type==S3C_SDHCI_CD_GPIO-*@ext_cd_gpio_invert:invertvaluesforexternalCDgpioline-*@cfg_gpio:ConfiguretheGPIOforaspecificcardbit-width-*-*Initialisationdataspecifictoeitherthemachineortheplatform-*forthedevicedrivertouseorcall-backwhenconfiguringgpioor-*cardspeedinformation.-*/-structs3c_sdhci_platdata{-unsignedintmax_width;-unsignedinthost_caps;-unsignedinthost_caps2;-unsignedintpm_caps;-enumcd_typescd_type;--intext_cd_gpio;-boolext_cd_gpio_invert;-int(*ext_cd_init)(void(*notify_func)(structplatform_device*,-intstate));-int(*ext_cd_cleanup)(void(*notify_func)(structplatform_device*,-intstate));--void(*cfg_gpio)(structplatform_device*dev,intwidth);-};-/* s3c_sdhci_set_platdata() - common helper for setting SDHCI platform data*@pd:Thedefaultplatformdataforthisdevice.*@set:Pointertotheplatformdatatofillin.
@@ -0,0 +1,56 @@+#ifndef __PLATFORM_DATA_SDHCI_S3C_H+#define __PLATFORM_DATA_SDHCI_S3C_H++structplatform_device;++enumcd_types{+S3C_SDHCI_CD_INTERNAL,/* use mmc internal CD line */+S3C_SDHCI_CD_EXTERNAL,/* use external callback */+S3C_SDHCI_CD_GPIO,/* use external gpio pin for CD line */+S3C_SDHCI_CD_NONE,/* no CD line, use polling to detect card */+S3C_SDHCI_CD_PERMANENT,/* no CD line, card permanently wired to host */+};++/**+*structs3c_sdhci_platdata()-PlatformdevicedataforSamsungSDHCI+*@max_width:Themaximumnumberofdatabitssupported.+*@host_caps:StandardMMChostcapabilitiesbitfield.+*@host_caps2:ThesecondstandardMMChostcapabilitiesbitfield.+*@cd_type:TypeofCardDetectionmethod(seecd_typesenumabove)+*@ext_cd_init:Initializeexternalcarddetectsubsystem.Calledon+*sdhci-s3cdriverprobewhencd_type==S3C_SDHCI_CD_EXTERNAL.+*notify_funcargumentisacallbacktothesdhci-s3cdriver+*thattriggersthecarddetectionevent.Callbackarguments:+*devispointertoplatformdeviceofthehostcontroller,+*stateisnewstateofthecard(0-removed,1-inserted).+*@ext_cd_cleanup:Cleanupexternalcarddetectsubsystem.Calledon+*sdhci-s3cdriverremovewhencd_type==S3C_SDHCI_CD_EXTERNAL.+*notify_funcargumentisthesamecallbackasforext_cd_init.+*@ext_cd_gpio:gpiopinusedforexternalCDline,validonlyif+*cd_type==S3C_SDHCI_CD_GPIO+*@ext_cd_gpio_invert:invertvaluesforexternalCDgpioline+*@cfg_gpio:ConfiguretheGPIOforaspecificcardbit-width+*+*Initialisationdataspecifictoeitherthemachineortheplatform+*forthedevicedrivertouseorcall-backwhenconfiguringgpioor+*cardspeedinformation.+*/+structs3c_sdhci_platdata{+unsignedintmax_width;+unsignedinthost_caps;+unsignedinthost_caps2;+unsignedintpm_caps;+enumcd_typescd_type;++intext_cd_gpio;+boolext_cd_gpio_invert;+int(*ext_cd_init)(void(*notify_func)(structplatform_device*,+intstate));+int(*ext_cd_cleanup)(void(*notify_func)(structplatform_device*,+intstate));++void(*cfg_gpio)(structplatform_device*dev,intwidth);+};+++#endif /* __PLATFORM_DATA_SDHCI_S3C_H */
The definitions have moved to include/linux/usb/samsung-usb-phy.h,
and plat/usb-phy.h is unavailable from drivers in a multiplatform
configuration.
Also fix up the plat/usb-phy.h header file to use the definitions
from the new header instead of providing a separate copy.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/mach-exynos/setup-usb-phy.c | 8 ++++----
arch/arm/mach-s3c64xx/setup-usb-phy.c | 4 ++--
arch/arm/mach-s5pv210/setup-usb-phy.c | 4 ++--
arch/arm/plat-samsung/include/plat/usb-phy.h | 5 +----
drivers/usb/host/ehci-s5p.c | 1 -
drivers/usb/host/ohci-exynos.c | 1 -
6 files changed, 9 insertions(+), 14 deletions(-)
@@ -204,9 +204,9 @@ static int exynos4210_usb_phy1_exit(struct platform_device *pdev)ints5p_usb_phy_init(structplatform_device*pdev,inttype){-if(type==S5P_USB_PHY_DEVICE)+if(type==USB_PHY_TYPE_DEVICE)returnexynos4210_usb_phy0_init(pdev);-elseif(type==S5P_USB_PHY_HOST)+elseif(type==USB_PHY_TYPE_HOST)returnexynos4210_usb_phy1_init(pdev);return-EINVAL;
@@ -214,9 +214,9 @@ int s5p_usb_phy_init(struct platform_device *pdev, int type)ints5p_usb_phy_exit(structplatform_device*pdev,inttype){-if(type==S5P_USB_PHY_DEVICE)+if(type==USB_PHY_TYPE_DEVICE)returnexynos4210_usb_phy0_exit(pdev);-elseif(type==S5P_USB_PHY_HOST)+elseif(type==USB_PHY_TYPE_HOST)returnexynos4210_usb_phy1_exit(pdev);return-EINVAL;
@@ -76,7 +76,7 @@ static int s3c_usb_otgphy_exit(struct platform_device *pdev)ints5p_usb_phy_init(structplatform_device*pdev,inttype){-if(type==S5P_USB_PHY_DEVICE)+if(type==USB_PHY_TYPE_DEVICE)returns3c_usb_otgphy_init(pdev);return-EINVAL;
@@ -84,7 +84,7 @@ int s5p_usb_phy_init(struct platform_device *pdev, int type)ints5p_usb_phy_exit(structplatform_device*pdev,inttype){-if(type==S5P_USB_PHY_DEVICE)+if(type==USB_PHY_TYPE_DEVICE)returns3c_usb_otgphy_exit(pdev);return-EINVAL;
@@ -80,7 +80,7 @@ static int s5pv210_usb_otgphy_exit(struct platform_device *pdev)ints5p_usb_phy_init(structplatform_device*pdev,inttype){-if(type==S5P_USB_PHY_DEVICE)+if(type==USB_PHY_TYPE_DEVICE)returns5pv210_usb_otgphy_init(pdev);return-EINVAL;
@@ -88,7 +88,7 @@ int s5p_usb_phy_init(struct platform_device *pdev, int type)ints5p_usb_phy_exit(structplatform_device*pdev,inttype){-if(type==S5P_USB_PHY_DEVICE)+if(type==USB_PHY_TYPE_DEVICE)returns5pv210_usb_otgphy_exit(pdev);return-EINVAL;
In multiplatform configurations, we cannot include headers
provided by only the exynos platform. Fortunately a number
of drivers that include those headers do not actually need
them, so we can just remove the inclusions.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/media/platform/exynos-gsc/gsc-regs.c | 1 -
drivers/media/platform/s5p-tv/sii9234_drv.c | 3 ---
2 files changed, 4 deletions(-)
In multiplatform configurations, we cannot include headers
provided by only the exynos platform. Fortunately a number
of drivers that include those headers do not actually need
them, so we can just remove the inclusions.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/video/exynos/exynos_mipi_dsi.c | 2 --
drivers/video/exynos/exynos_mipi_dsi_common.c | 2 --
drivers/video/exynos/exynos_mipi_dsi_lowlevel.c | 2 --
3 files changed, 6 deletions(-)
In multiplatform configurations, we cannot include headers
provided by only the exynos platform. Fortunately a number
of drivers that include those headers do not actually need
them, so we can just remove the inclusions.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/thermal/exynos_thermal.c | 2 --
1 file changed, 2 deletions(-)
Nothing uses the NAND register definitions other than the
actual driver, so we can move the header file into the
same local directory, which lets us build it in a multiplatform
configuration.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/plat-samsung/include/plat/regs-onenand.h | 63 -----------------------
drivers/mtd/onenand/samsung.c | 4 +-
drivers/mtd/onenand/samsung.h | 61 ++++++++++++++++++++++
3 files changed, 63 insertions(+), 65 deletions(-)
delete mode 100644 arch/arm/plat-samsung/include/plat/regs-onenand.h
create mode 100644 drivers/mtd/onenand/samsung.h
Nothing outside of the rtc driver includes plat/regs-rtc.h,
so we can simply move the file into the same directory,
which allows us to build the file as platform-independent
code.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/plat-samsung/include/plat/regs-rtc.h | 71 ---------------------------
drivers/rtc/rtc-s3c.c | 3 +-
drivers/rtc/rtc-s3c.h | 70 ++++++++++++++++++++++++++
3 files changed, 71 insertions(+), 73 deletions(-)
delete mode 100644 arch/arm/plat-samsung/include/plat/regs-rtc.h
create mode 100644 drivers/rtc/rtc-s3c.h
The spi-s3c64xx uses a Samsung proprietary interface for
talking to the DMA engine, which does not work with
multiplatform kernels. Since the driver can also operate
in PIO mode without any DMA, older platforms that do
not support the DMA engine API will still work, although
slower.
The conversion was rather mechanical, since the samsung
interface is just a shallow wrapper around the dmaengine
interface.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/plat-samsung/devs.c | 10 +++
drivers/spi/spi-s3c64xx.c | 107 ++++++++++++++----------------
include/linux/platform_data/spi-s3c64xx.h | 3 +
3 files changed, 62 insertions(+), 58 deletions(-)
@@ -713,9 +701,9 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,}/* Polling method for xfers not bigger than FIFO capacity */-if(xfer->len<=((FIFO_LVL_MASK(sdd)>>1)+1))-use_dma=0;-else+use_dma=0;+if(sdd->rx_dma.ch&&sdd->tx_dma.ch&&+(xfer->len>((FIFO_LVL_MASK(sdd)>>1)+1)))use_dma=1;spin_lock_irqsave(&sdd->lock,flags);
@@ -750,10 +738,10 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,if(use_dma){if(xfer->tx_buf!=NULL&&(sdd->state&TXBUSY))-sdd->ops->stop(sdd->tx_dma.ch);+dmaengine_terminate_all(sdd->tx_dma.ch);if(xfer->rx_buf!=NULL&&(sdd->state&RXBUSY))-sdd->ops->stop(sdd->rx_dma.ch);+dmaengine_terminate_all(sdd->rx_dma.ch);}gotoout;
@@ -1207,15 +1200,15 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)}sdd->cur_bpw=8;-if(!sdd->pdev->dev.of_node){+structresource*res;res=platform_get_resource(pdev,IORESOURCE_DMA,0);if(!res){dev_err(&pdev->dev,"Unable to get SPI tx dma ""resource\n");return-ENXIO;}-sdd->tx_dma.dmach=res->start;+sdd->tx_dma.request=res->start;res=platform_get_resource(pdev,IORESOURCE_DMA,1);if(!res){
@@ -1223,12 +1216,11 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)"resource\n");return-ENXIO;}-sdd->rx_dma.dmach=res->start;+sdd->rx_dma.request=res->start;}sdd->tx_dma.direction=DMA_MEM_TO_DEV;sdd->rx_dma.direction=DMA_DEV_TO_MEM;-master->dev.of_node=pdev->dev.of_node;master->bus_num=sdd->port_id;master->setup=s3c64xx_spi_setup;
@@ -1314,8 +1306,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)sdd->port_id,master->num_chipselect);dev_dbg(&pdev->dev,"\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",mem_res->end,mem_res->start,-sdd->rx_dma.dmach,sdd->tx_dma.dmach);-+sdd->rx_dma.request,sdd->tx_dma.request);pm_runtime_enable(&pdev->dev);return0;
The Samsung PWM driver uses "magic" pointers that are mapped
at boot time to point its MMIO registers. This fails horribly
with a multiplatform kernel, which can not rely on platform
specific header files to contain the right values, aside from
this being a really bad idea in general.
This changes the driver to at least pass an __iomem token
around in the device structure to dereference that. Fixing
the platform code is much harder, so we'll leave that
until we have a DT binding for pwm-samsung, which may require
other changes in this area. Since we are already touching
every MMIO accessor in this driver, let's also use the
proper readl_relaxed variant rather than __raw_readl.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/pwm/pwm-samsung.c | 60 +++++++++++++++++++++++++++++++++--------------
1 file changed, 42 insertions(+), 18 deletions(-)
@@ -133,8 +150,8 @@ static int s3c_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,/* The TCMP and TCNT can be read without a lock, they're not*sharedbetweenthetimers.*/-tcmp=__raw_readl(S3C2410_TCMPB(s3c->pwm_id));-tcnt=__raw_readl(S3C2410_TCNTB(s3c->pwm_id));+tcmp=readl_relaxed(s3c->base+S3C2410_TCMPB(s3c->pwm_id));+tcnt=readl_relaxed(s3c->base+S3C2410_TCNTB(s3c->pwm_id));period=NS_IN_HZ/period_ns;
@@ -207,6 +224,7 @@ static int s3c_pwm_probe(struct platform_device *pdev)unsignedlongflags;unsignedlongtcon;unsignedintid=pdev->id;+structresource*res;intret;if(id==4){
@@ -220,6 +238,12 @@ static int s3c_pwm_probe(struct platform_device *pdev)return-ENOMEM;}+/* try to get a proper base address, fall back to S3C_VA_TIMER */+s3c->base=S3C_VA_TIMER;+res=platform_get_resource(pdev,IORESOURCE_MEM,0);+if(res)+s3c->base=devm_ioremap(dev,res->start,resource_size(res));+/* calculate base of control bits in TCON */s3c->tcon_base=id==0?0:(id*4)+4;s3c->pwm_id=id;
@@ -245,9 +269,9 @@ static int s3c_pwm_probe(struct platform_device *pdev)local_irq_save(flags);-tcon=__raw_readl(S3C2410_TCON);+tcon=readl_relaxed(s3c->base+S3C2410_TCON);tcon|=pwm_tcon_invert(s3c);-__raw_writel(tcon,S3C2410_TCON);+writel_relaxed(tcon,s3c->base+S3C2410_TCON);local_irq_restore(flags);
@@ -258,7 +282,7 @@ static int s3c_pwm_probe(struct platform_device *pdev)}pwm_dbg(s3c,"config bits %02x\n",-(__raw_readl(S3C2410_TCON)>>s3c->tcon_base)&0x0f);+(readl_relaxed(s3c->base+S3C2410_TCON)>>s3c->tcon_base)&0x0f);dev_info(dev,"tin at %lu, tdiv at %lu, tin=%sclk, base %d\n",clk_get_rate(s3c->clk),
In order to build the exynos kernel with CONFIG_ARCH_MULTIPLATFORM,
we must convert all users of the Samsung private DMA interface to
the generic dmaengine API. This converts the sound/soc drivers,
breaking the older s3c platforms in the process, since they do not
support the dmaengine interface yet.
This patch must not get mainlined until mach-s3c* is also converted,
but can be used for testing in the meantime.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
sound/soc/samsung/ac97.c | 15 ------
sound/soc/samsung/dma.c | 104 +++++++++++++++++++++-------------------
sound/soc/samsung/dma.h | 4 +-
sound/soc/samsung/i2s.c | 9 +---
sound/soc/samsung/pcm.c | 13 -----
sound/soc/samsung/s3c2412-i2s.c | 10 ----
sound/soc/samsung/s3c24xx-i2s.c | 10 ----
sound/soc/samsung/spdif.c | 6 ---
8 files changed, 57 insertions(+), 114 deletions(-)
@@ -144,8 +142,6 @@ static int dma_hw_params(struct snd_pcm_substream *substream,unsignedlongtotbytes=params_buffer_bytes(params);structs3c_dma_params*dma=snd_soc_dai_get_dma_data(rtd->cpu_dai,substream);-structsamsung_dma_reqreq;-structsamsung_dma_configconfig;pr_debug("Entered %s\n",__func__);
@@ -157,26 +153,37 @@ static int dma_hw_params(struct snd_pcm_substream *substream,/* this may get called several times by oss emulation*withdifferentparams-HW*/if(prtd->params==NULL){+structdma_slave_configconfig;+dma_cap_mask_tmask;+/* prepare DMA */prtd->params=dma;-pr_debug("params %p, client %p, channel %d\n",prtd->params,-prtd->params->client,prtd->params->channel);--prtd->params->ops=samsung_dma_get_ops();--req.cap=(samsung_dma_has_circular()?-DMA_CYCLIC:DMA_SLAVE);-req.client=prtd->params->client;-config.direction=-(substream->stream==SNDRV_PCM_STREAM_PLAYBACK-?DMA_MEM_TO_DEV:DMA_DEV_TO_MEM);-config.width=prtd->params->dma_size;-config.fifo=prtd->params->dma_addr;-prtd->params->ch=prtd->params->ops->request(-prtd->params->channel,&req,rtd->cpu_dai->dev,-prtd->params->ch_name);-prtd->params->ops->config(prtd->params->ch,&config);+pr_debug("params %p, channel %d\n",prtd->params,+prtd->params->channel);++dma_cap_zero(mask);+dma_cap_set(DMA_CYCLIC,mask);++prtd->params->ch=dma_request_slave_channel_compat(mask,+pl330_filter,(void*)prtd->params->channel,+rtd->cpu_dai->dev,prtd->params->ch_name);++memset(&config,0,sizeof(structdma_slave_config));++if(substream->stream==SNDRV_PCM_STREAM_PLAYBACK){+config.direction=DMA_MEM_TO_DEV;+config.dst_addr=prtd->params->dma_size;+config.dst_addr_width=prtd->params->dma_addr;+config.dst_maxburst=1;+dmaengine_slave_config(prtd->params->ch,&config);+}else{+config.direction=DMA_DEV_TO_MEM;+config.src_addr=prtd->params->dma_addr;+config.src_addr_width=prtd->params->dma_size;+config.src_maxburst=1;+dmaengine_slave_config(prtd->params->ch,&config);+}}snd_pcm_set_runtime_buffer(substream,&substream->dma_buffer);
@@ -203,9 +210,8 @@ static int dma_hw_free(struct snd_pcm_substream *substream)snd_pcm_set_runtime_buffer(substream,NULL);if(prtd->params){-prtd->params->ops->flush(prtd->params->ch);-prtd->params->ops->release(prtd->params->ch,-prtd->params->client);+dmaengine_terminate_all(prtd->params->ch);+dma_release_channel(prtd->params->ch);prtd->params=NULL;}
@@ -225,7 +231,7 @@ static int dma_prepare(struct snd_pcm_substream *substream)return0;/* flush the DMA channel */-prtd->params->ops->flush(prtd->params->ch);+dmaengine_terminate_all(prtd->params->ch);prtd->dma_loaded=0;prtd->dma_pos=prtd->dma_start;
@@ -248,12 +254,12 @@ static int dma_trigger(struct snd_pcm_substream *substream, int cmd)switch(cmd){caseSNDRV_PCM_TRIGGER_START:prtd->state|=ST_RUNNING;-prtd->params->ops->trigger(prtd->params->ch);+dma_async_issue_pending(prtd->params->ch);break;caseSNDRV_PCM_TRIGGER_STOP:prtd->state&=~ST_RUNNING;-prtd->params->ops->stop(prtd->params->ch);+dmaengine_terminate_all(prtd->params->ch);break;default:
@@ -13,12 +13,10 @@#define _S3C_AUDIO_Hstructs3c_dma_params{-structs3c2410_dma_client*client;/* stream identifier */intchannel;/* Channel ID */dma_addr_tdma_addr;intdma_size;/* Size of the DMA transfer */-unsignedch;-structsamsung_dma_ops*ops;+structdma_chan*ch;char*ch_name;};
With multiplatform kernels, we cannot use hardwired IRQ
numbers in device drivers. This changes the idma driver
to use a proper resource, like all other drivers do.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/plat-samsung/devs.c | 6 ++++++
sound/soc/samsung/idma.c | 10 ++++++++--
2 files changed, 14 insertions(+), 2 deletions(-)
@@ -305,7 +307,7 @@ static int idma_open(struct snd_pcm_substream *substream)if(prtd==NULL)return-ENOMEM;-ret=request_irq(IRQ_I2S0,iis_irq,0,"i2s",prtd);+ret=request_irq(idma_irq,iis_irq,0,"i2s",prtd);if(ret<0){pr_err("fail to claim i2s irq , ret = %d\n",ret);kfree(prtd);
@@ -324,7 +326,7 @@ static int idma_close(struct snd_pcm_substream *substream)structsnd_pcm_runtime*runtime=substream->runtime;structidma_ctrl*prtd=runtime->private_data;-free_irq(IRQ_I2S0,prtd);+free_irq(idma_irq,prtd);if(!prtd)pr_err("idma_close called with prtd == NULL\n");
When we enable CONFIG_SPARSE_IRQ, we have to set the
value of NR_IRQS in the machine_desc for legacy IRQ
domains, and any file referring to the number of
interrupts or a specific number must include the
mach/irqs.h header file explicitly.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/mach-exynos/dev-uart.c | 1 +
arch/arm/mach-exynos/include/mach/irqs.h | 5 ++++-
arch/arm/mach-exynos/mach-armlex4210.c | 2 ++
arch/arm/mach-exynos/mach-exynos4-dt.c | 2 ++
arch/arm/mach-exynos/mach-exynos5-dt.c | 2 ++
arch/arm/mach-exynos/mach-nuri.c | 2 ++
arch/arm/mach-exynos/mach-origen.c | 2 ++
arch/arm/mach-exynos/mach-smdk4x12.c | 2 ++
arch/arm/mach-exynos/mach-smdkv310.c | 3 +++
arch/arm/plat-samsung/irq-vic-timer.c | 1 +
arch/arm/plat-samsung/pm.c | 1 +
arch/arm/plat-samsung/s5p-irq.c | 1 +
12 files changed, 23 insertions(+), 1 deletion(-)
Multiplatform kernels rely on the common clock implementation,
which conflicts with Samsung's own implementation of the same
interface. This disables all code that provides or requires
the nonstandard version.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/mach-exynos/Makefile | 2 ++
arch/arm/mach-exynos/common.c | 6 ++++++
arch/arm/plat-samsung/clock-clksrc.c | 3 +++
arch/arm/plat-samsung/s5p-clock.c | 3 +++
drivers/cpufreq/Kconfig.arm | 4 +++-
drivers/devfreq/Kconfig | 1 +
6 files changed, 18 insertions(+), 1 deletion(-)
@@ -425,6 +428,9 @@ static void __init exynos5440_map_io(void)staticvoid__initexynos5_init_clocks(intxtal){+if(!IS_ENABLED(CONFIG_SAMSUNG_CLOCK))+return;+printk(KERN_DEBUG"%s: initializing clocks\n",__func__);/* EXYNOS5440 can support only common clock framework */
With CONFIG_ARCH_MULTIPLATFORM, we can no longer have
our own mach/gpio.h included by the kernel-wide linux/gpio.h
header, and disabling the gpio-samsung driver means we cannot
use any of the private interfaces. This patch disables
all code referring to the driver and gets things to build
again, but surely breaks a lot of stuff in the process.
Thomas Abraham alrady has a proper set of patches to
address this.
Do not apply.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/mach-exynos/Makefile | 2 ++
arch/arm/mach-exynos/common.c | 3 +++
arch/arm/mach-exynos/dev-audio.c | 1 +
arch/arm/mach-exynos/include/mach/gpio.h | 2 ++
arch/arm/mach-exynos/mach-armlex4210.c | 1 +
arch/arm/mach-exynos/mach-origen.c | 1 +
arch/arm/mach-exynos/setup-i2c0.c | 3 ++-
arch/arm/mach-s3c64xx/include/mach/gpio.h | 4 ++++
arch/arm/plat-samsung/include/plat/gpio-core.h | 3 +++
arch/arm/plat-samsung/pm-gpio.c | 1 +
drivers/gpio/Makefile | 2 +-
11 files changed, 21 insertions(+), 2 deletions(-)
@@ -17,10 +17,11 @@ struct platform_device; /* don't need the contents */#include<linux/platform_data/i2c-s3c2410.h>#include<plat/gpio-cfg.h>#include<plat/cpu.h>+#include<mach/gpio.h>voids3c_i2c0_cfg_gpio(structplatform_device*dev){-if(soc_is_exynos5250()||soc_is_exynos5440())+if(soc_is_exynos5250()||soc_is_exynos5440()||!IS_ENABLED(CONFIG_ARCH_EXYNOS_SINGLE))/* will be implemented with gpio function */return;
This enables the exynos platform to be selected as part
of a CONFIG_ARCH_MULTIPLATFORM kernel. This still
breaks a number of drivers, which we will have to
enable again one by one. Single-platform configurations
should not be impacted by this.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/Kconfig | 11 ++---------
arch/arm/mach-exynos/Kconfig | 21 +++++++++++++++++----
arch/arm/mach-exynos/Makefile | 1 +
arch/arm/plat-samsung/Kconfig | 5 +++++
arch/arm/plat-samsung/Makefile | 3 +++
drivers/video/Kconfig | 2 +-
drivers/watchdog/Kconfig | 1 +
7 files changed, 30 insertions(+), 14 deletions(-)
Hi everyone,
Although I'm not present at the Linaro Connect hacking
sessions, I am participating remotely and have tried
hacking on multiplatform support for Exynos. This patch
set is far from complete, but I think the patches
can be useful anyway.
The series gets increasingly fishy towards the end,
and we should probably not apply any of the last nine
patches as-is, nor do I expect everything to work, since
I have not tested them at all.
With this patch set, we can build mach-exynos as part
of a multiplatform kernel, with the following caveats:
* Only DT based boards are supported
* Moving to common-clk breaks things including cpufreq
and others. Thomas is working on a patch for this
* We disable the gpio implementation, which also breaks
stuff, but Thomas has a patch already
* Using the generic DMA engine API in SPI and ASoC
means they no longer work on S3C
* I did not like the solution for the UART driver, but
could also not think of a better one.
* The FB_S3C, S3C2410_WATCHDOG and S3C_ADC drivers
are left as an exercise to the reader, they are
currently disabled with multiplatform
* sparsemem support is not available on multiplatform
For booting, you might want to add fixing up of the initcalls
to your checklist too as that can easily cause surprises to
other SoCs.
Regards,
Tony
From: Tomasz Figa <hidden> Date: 2013-03-05 18:28:01
Hi Arnd,
First of all, thanks for your great effort on making Exynos multiplatform-
friendly.
I have added my two cents inline.
On Tuesday 05 of March 2013 18:42:10 Arnd Bergmann wrote:
Hi everyone,
Although I'm not present at the Linaro Connect hacking
sessions, I am participating remotely and have tried
hacking on multiplatform support for Exynos. This patch
set is far from complete, but I think the patches
can be useful anyway.
The series gets increasingly fishy towards the end,
and we should probably not apply any of the last nine
patches as-is, nor do I expect everything to work, since
I have not tested them at all.
With this patch set, we can build mach-exynos as part
of a multiplatform kernel, with the following caveats:
* Only DT based boards are supported
As far as I'm aware, there are plans to drop non-DT Exynos support. Kgene
should know more on this.
* Moving to common-clk breaks things including cpufreq
and others. Thomas is working on a patch for this
We have several patches internally for fixing things up to run correclty with
common-clk. I'll see if we can post some patches.
* We disable the gpio implementation, which also breaks
stuff, but Thomas has a patch already
The legacy GPIO code is needed only for non-DT case. DT-case uses the new
pinctrl-samsung driver, which is (AFAIK) multiplatform-aware.
* Using the generic DMA engine API in SPI and ASoC
means they no longer work on S3C
* I did not like the solution for the UART driver, but
could also not think of a better one.
* The FB_S3C, S3C2410_WATCHDOG and S3C_ADC drivers
are left as an exercise to the reader, they are
currently disabled with multiplatform
* sparsemem support is not available on multiplatform
There was some discussion some time ago whether we really need sparsemem on
Exynos. If I remember correctly, it turned out that we don't. So this is not
really an issue.
The patches are based on v3.9-rc1 and I have pushed
the git branch to
git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git
testing/exynos-multiplatform
I have not yet added subsystem maintainers to Cc on the
patches, I'd like to coordinate with the other people
involved first, so see if they already have patches
for the same drivers.
Arnd
Arnd Bergmann (23):
ARM: exynos: introduce EXYNOS_ATAGS symbol
irqchip: exynos: remove dependency on mach/irqs.h
tty: serial/samsung: prepare for common clock API
tty: serial/samsung: make register definitions global
tty: serial/samsung: fix modular build
ARM: exynos: move debug-macro.S to include/debug/
i2c: s3c2410: make header file local
mmc: sdhci-s3c: remove platform dependencies
usb: exynos: do not include plat/usb-phy.h
[media] exynos: remove unnecessary header inclusions
video/exynos: remove unnecessary header inclusions
thermal/exynos: remove unnecessary header inclusions
mtd: onenand/samsung: make regs-onenand.h file local
rtc: s3c: make header file local
spi: s3c64xx: move to generic dmaengine API
pwm: samsung: repair the worst MMIO abuses
I'm currently working (in my free time) on a series of cleanup patches
sanitizing Samsung PWM code for S3C64xx and S5PV210 DT (and multiplatform)
support.
On those platforms it is a bit more complex case as there are two blocks of
code that access the same hardware - samsung-time (using two PWM channels for
clocksource and clock events) and pwm-samsung.
Hopefully, I will have some patches ready soon.
Best regards,
--
Tomasz Figa
Samsung Poland R&D Center
SW Solution Development, Kernel and System Framework
With this patch set, we can build mach-exynos as part
of a multiplatform kernel, with the following caveats:
* Only DT based boards are supported
As far as I'm aware, there are plans to drop non-DT Exynos support. Kgene
should know more on this.
Yes, that was my understanding as well. It might not actually be too
hard to get multiplatform working with the ATAGS based board files
(we do that on some of the other platforms), but there is probably
no reason to try hard.
quoted
* Moving to common-clk breaks things including cpufreq
and others. Thomas is working on a patch for this
We have several patches internally for fixing things up to run correclty with
common-clk. I'll see if we can post some patches.
Ok, excellent.
quoted
* We disable the gpio implementation, which also breaks
stuff, but Thomas has a patch already
The legacy GPIO code is needed only for non-DT case. DT-case uses the new
pinctrl-samsung driver, which is (AFAIK) multiplatform-aware.
Please have a closer look at the "ARM: exynos: work around missing gpio
code on multiplatform" patch, I think there a few files I had to touch
that actually rely on the legacy gpio code:
* the pm-gpio.c file
* the s3c_i2c0_cfg_gpio function
* the eint irqchip
If none of these are needed for DT-based systems, we should probably
build that code conditionally based on the CONFIG_EXYNOS_ATAGS symbol
I introduced.
quoted
* sparsemem support is not available on multiplatform
There was some discussion some time ago whether we really need sparsemem on
Exynos. If I remember correctly, it turned out that we don't. So this is not
really an issue.
Ok, good.
quoted
Arnd Bergmann (23):
ARM: exynos: introduce EXYNOS_ATAGS symbol
irqchip: exynos: remove dependency on mach/irqs.h
tty: serial/samsung: prepare for common clock API
tty: serial/samsung: make register definitions global
tty: serial/samsung: fix modular build
ARM: exynos: move debug-macro.S to include/debug/
i2c: s3c2410: make header file local
mmc: sdhci-s3c: remove platform dependencies
usb: exynos: do not include plat/usb-phy.h
[media] exynos: remove unnecessary header inclusions
video/exynos: remove unnecessary header inclusions
thermal/exynos: remove unnecessary header inclusions
mtd: onenand/samsung: make regs-onenand.h file local
rtc: s3c: make header file local
spi: s3c64xx: move to generic dmaengine API
pwm: samsung: repair the worst MMIO abuses
I'm currently working (in my free time) on a series of cleanup patches
sanitizing Samsung PWM code for S3C64xx and S5PV210 DT (and multiplatform)
support.
Ah, nice.
On those platforms it is a bit more complex case as there are two blocks of
code that access the same hardware - samsung-time (using two PWM channels for
clocksource and clock events) and pwm-samsung.
Hopefully, I will have some patches ready soon.
How are you planning to solve this? Do you want to have a combined driver that
registers both a clocksource and a pwm?
Arnd
Am Dienstag, 5. M?rz 2013, 18:42:10 schrieb Arnd Bergmann:
Hi everyone,
Although I'm not present at the Linaro Connect hacking
sessions, I am participating remotely and have tried
hacking on multiplatform support for Exynos. This patch
set is far from complete, but I think the patches
can be useful anyway.
The series gets increasingly fishy towards the end,
and we should probably not apply any of the last nine
patches as-is, nor do I expect everything to work, since
I have not tested them at all.
With this patch set, we can build mach-exynos as part
of a multiplatform kernel, with the following caveats:
* Only DT based boards are supported
* Moving to common-clk breaks things including cpufreq
and others. Thomas is working on a patch for this
* We disable the gpio implementation, which also breaks
stuff, but Thomas has a patch already
* Using the generic DMA engine API in SPI and ASoC
means they no longer work on S3C
If I remember correctly Kgene mentioning some time back, that someone was
working on converting the s3c dma to dmaengine, but I never heard anything
more about it.
So personally I would be grateful, for people not breaking my devices :-) .
On an unrelated note, exists some sort of documentation for creating dmaengine
drivers somewhere? Documentation/* seems to always be only targetted at device
driver writers and my own DMA knowledge is still stuck at the theoretical
level they teach in generic operating-systems university courses.
Heiko
* I did not like the solution for the UART driver, but
could also not think of a better one.
* The FB_S3C, S3C2410_WATCHDOG and S3C_ADC drivers
are left as an exercise to the reader, they are
currently disabled with multiplatform
* sparsemem support is not available on multiplatform
The patches are based on v3.9-rc1 and I have pushed
the git branch to
git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git
testing/exynos-multiplatform
I have not yet added subsystem maintainers to Cc on the
patches, I'd like to coordinate with the other people
involved first, so see if they already have patches
for the same drivers.
Arnd
Arnd Bergmann (23):
ARM: exynos: introduce EXYNOS_ATAGS symbol
irqchip: exynos: remove dependency on mach/irqs.h
tty: serial/samsung: prepare for common clock API
tty: serial/samsung: make register definitions global
tty: serial/samsung: fix modular build
ARM: exynos: move debug-macro.S to include/debug/
i2c: s3c2410: make header file local
mmc: sdhci-s3c: remove platform dependencies
usb: exynos: do not include plat/usb-phy.h
[media] exynos: remove unnecessary header inclusions
video/exynos: remove unnecessary header inclusions
thermal/exynos: remove unnecessary header inclusions
mtd: onenand/samsung: make regs-onenand.h file local
rtc: s3c: make header file local
spi: s3c64xx: move to generic dmaengine API
pwm: samsung: repair the worst MMIO abuses
ASoC: samsung: move plat/ headers to local directory
ASoC: samsung: convert to dmaengine API
ASoC: samsung: use irq resource for idma
ARM: exynos: prepare for sparse IRQ
ARM: exynos: hack to disable private clock code
ARM: exynos: work around missing gpio code on multiplatform
ARM: exynos: experimental multiplatform support
arch/arm/Kconfig | 11 +-
arch/arm/Kconfig.debug | 8 +
arch/arm/include/debug/exynos.S | 39 +++
arch/arm/include/debug/samsung.S | 87 +++++++
arch/arm/mach-exynos/Kconfig | 36 ++-
arch/arm/mach-exynos/Makefile | 5 +
arch/arm/mach-exynos/common.c | 14 +-
arch/arm/mach-exynos/common.h | 2 +-
arch/arm/mach-exynos/dev-audio.c | 1 +
arch/arm/mach-exynos/dev-uart.c | 1 +
arch/arm/mach-exynos/include/mach/debug-macro.S | 39 ---
arch/arm/mach-exynos/include/mach/gpio.h | 2 +
arch/arm/mach-exynos/include/mach/irqs.h | 5 +-
arch/arm/mach-exynos/mach-armlex4210.c | 3 +
arch/arm/mach-exynos/mach-exynos4-dt.c | 2 +
arch/arm/mach-exynos/mach-exynos5-dt.c | 2 +
arch/arm/mach-exynos/mach-nuri.c | 2 +
arch/arm/mach-exynos/mach-origen.c | 3 +
arch/arm/mach-exynos/mach-smdk4x12.c | 2 +
arch/arm/mach-exynos/mach-smdkv310.c | 3 +
arch/arm/mach-exynos/setup-i2c0.c | 3 +-
arch/arm/mach-exynos/setup-sdhci-gpio.c | 2 +-
arch/arm/mach-exynos/setup-usb-phy.c | 8 +-
arch/arm/mach-s3c24xx/clock-s3c2440.c | 5 +
arch/arm/mach-s3c24xx/common.c | 5 +
arch/arm/mach-s3c24xx/dma-s3c2410.c | 2 -
arch/arm/mach-s3c24xx/dma-s3c2412.c | 2 -
arch/arm/mach-s3c24xx/dma-s3c2440.c | 2 -
arch/arm/mach-s3c24xx/dma-s3c2443.c | 2 -
arch/arm/mach-s3c24xx/include/mach/debug-macro.S | 2 +-
arch/arm/mach-s3c24xx/mach-rx1950.c | 1 -
arch/arm/mach-s3c64xx/include/mach/debug-macro.S | 2 +-
arch/arm/mach-s3c64xx/include/mach/gpio.h | 4 +
arch/arm/mach-s3c64xx/setup-usb-phy.c | 4 +-
arch/arm/mach-s5p64x0/include/mach/debug-macro.S | 2 +-
arch/arm/mach-s5pc100/include/mach/debug-macro.S | 2 +-
arch/arm/mach-s5pc100/setup-sdhci-gpio.c | 1 -
arch/arm/mach-s5pv210/include/mach/debug-macro.S | 2 +-
arch/arm/mach-s5pv210/setup-sdhci-gpio.c | 1 -
arch/arm/mach-s5pv210/setup-usb-phy.c | 4 +-
arch/arm/plat-samsung/Kconfig | 5 +
arch/arm/plat-samsung/Makefile | 3 +
arch/arm/plat-samsung/clock-clksrc.c | 3 +
arch/arm/plat-samsung/devs.c | 17 +-
arch/arm/plat-samsung/include/plat/debug-macro.S | 87 -------
arch/arm/plat-samsung/include/plat/gpio-core.h | 3 +
arch/arm/plat-samsung/include/plat/regs-ac97.h | 67 -----
arch/arm/plat-samsung/include/plat/regs-iic.h | 56 -----
arch/arm/plat-samsung/include/plat/regs-iis.h | 70 ------
arch/arm/plat-samsung/include/plat/regs-onenand.h | 63 -----
arch/arm/plat-samsung/include/plat/regs-rtc.h | 71 ------
arch/arm/plat-samsung/include/plat/regs-sdhci.h | 87 -------
arch/arm/plat-samsung/include/plat/regs-serial.h | 282
+--------------------- arch/arm/plat-samsung/include/plat/sdhci.h |
56 +----
arch/arm/plat-samsung/include/plat/usb-phy.h | 5 +-
arch/arm/plat-samsung/irq-vic-timer.c | 1 +
arch/arm/plat-samsung/pm-gpio.c | 1 +
arch/arm/plat-samsung/pm.c | 1 +
arch/arm/plat-samsung/s5p-clock.c | 3 +
arch/arm/plat-samsung/s5p-irq.c | 1 +
drivers/cpufreq/Kconfig.arm | 4 +-
drivers/devfreq/Kconfig | 1 +
drivers/gpio/Makefile | 2 +-
drivers/i2c/busses/i2c-s3c2410.c | 3 +-
drivers/i2c/busses/i2c-s3c2410.h | 56 +++++
drivers/irqchip/exynos-combiner.c | 113 +++++----
drivers/media/platform/exynos-gsc/gsc-regs.c | 1 -
drivers/media/platform/s5p-tv/sii9234_drv.c | 3 -
drivers/mmc/host/Kconfig | 2 +-
drivers/mmc/host/sdhci-s3c-regs.h | 87 +++++++
drivers/mmc/host/sdhci-s3c.c | 5 +-
drivers/mtd/onenand/samsung.c | 4 +-
drivers/mtd/onenand/samsung.h | 61 +++++
drivers/pwm/pwm-samsung.c | 60 +++--
drivers/rtc/rtc-s3c.c | 3 +-
drivers/rtc/rtc-s3c.h | 70 ++++++
drivers/spi/spi-s3c64xx.c | 107 ++++----
drivers/thermal/exynos_thermal.c | 2 -
drivers/tty/serial/samsung.c | 17 +-
drivers/tty/serial/samsung.h | 4 +-
drivers/usb/host/ehci-s5p.c | 1 -
drivers/usb/host/ohci-exynos.c | 1 -
drivers/video/Kconfig | 2 +-
drivers/video/exynos/exynos_mipi_dsi.c | 2 -
drivers/video/exynos/exynos_mipi_dsi_common.c | 2 -
drivers/video/exynos/exynos_mipi_dsi_lowlevel.c | 2 -
drivers/watchdog/Kconfig | 1 +
include/linux/platform_data/mmc-sdhci-s3c.h | 56 +++++
include/linux/platform_data/spi-s3c64xx.h | 3 +
include/linux/serial_s3c.h | 260
++++++++++++++++++++ sound/soc/samsung/ac97.c |
17 +-
sound/soc/samsung/dma.c | 104 ++++----
sound/soc/samsung/dma.h | 4 +-
sound/soc/samsung/h1940_uda1380.c | 2 +-
sound/soc/samsung/i2s.c | 9 +-
sound/soc/samsung/idma.c | 10 +-
sound/soc/samsung/neo1973_wm8753.c | 2 +-
sound/soc/samsung/pcm.c | 13 -
sound/soc/samsung/regs-ac97.h | 67 +++++
sound/soc/samsung/regs-iis.h | 70 ++++++
sound/soc/samsung/rx1950_uda1380.c | 2 +-
sound/soc/samsung/s3c2412-i2s.c | 10 -
sound/soc/samsung/s3c24xx-i2s.c | 12 +-
sound/soc/samsung/s3c24xx_uda134x.c | 2 +-
sound/soc/samsung/spdif.c | 6 -
105 files changed, 1262 insertions(+), 1208 deletions(-)
create mode 100644 arch/arm/include/debug/exynos.S
create mode 100644 arch/arm/include/debug/samsung.S
delete mode 100644 arch/arm/mach-exynos/include/mach/debug-macro.S
delete mode 100644 arch/arm/plat-samsung/include/plat/debug-macro.S
delete mode 100644 arch/arm/plat-samsung/include/plat/regs-ac97.h
delete mode 100644 arch/arm/plat-samsung/include/plat/regs-iic.h
delete mode 100644 arch/arm/plat-samsung/include/plat/regs-iis.h
delete mode 100644 arch/arm/plat-samsung/include/plat/regs-onenand.h
delete mode 100644 arch/arm/plat-samsung/include/plat/regs-rtc.h
delete mode 100644 arch/arm/plat-samsung/include/plat/regs-sdhci.h
create mode 100644 drivers/i2c/busses/i2c-s3c2410.h
create mode 100644 drivers/mmc/host/sdhci-s3c-regs.h
create mode 100644 drivers/mtd/onenand/samsung.h
create mode 100644 drivers/rtc/rtc-s3c.h
create mode 100644 include/linux/platform_data/mmc-sdhci-s3c.h
create mode 100644 include/linux/serial_s3c.h
create mode 100644 sound/soc/samsung/regs-ac97.h
create mode 100644 sound/soc/samsung/regs-iis.h
If I remember correctly Kgene mentioning some time back, that someone was
working on converting the s3c dma to dmaengine, but I never heard anything
more about it.
Ok, let's see if we can find out what happened to that.
So personally I would be grateful, for people not breaking my devices :-) .
I'm sure we can find a way. It's also clear that the current s3c_dma
does not have a bright future.
On an unrelated note, exists some sort of documentation for creating dmaengine
drivers somewhere? Documentation/* seems to always be only targetted at device
driver writers and my own DMA knowledge is still stuck at the theoretical
level they teach in generic operating-systems university courses.
I think we only have Documentation/dmaengine.txt, which is targetted at
people using the dmaengine API, not at someone writing a driver.
I have only limited experience myself, but I know that it comes down
to filling the operations of a struct dma_device. A slight complication
is that the dmaengine interface handles both memory-to-memory transfers
and slave device transfers (the slave being the device that you are
talking to), and you have to know which parts are relevant for your
use case. You probably only need the slave interface, but it can seem
like it's bolted to the side of the original API.
drivers/dma/mxs-dma.c looks like a reasonable driver that one can
use as an example. The s3c64xx_dma code is also interesting because
it has both an implementation of the s3c_dma interface in
arch/arm/mach-s3c64xx/dma.c and one using the generic interface in
drivers/dma/amba-pl08x.c. The latter also implements a "virtual
channel" concept that you probably don't need.
Arnd
The s3c64xx_dma code is also interesting because
it has both an implementation of the s3c_dma interface in
arch/arm/mach-s3c64xx/dma.c and one using the generic interface in
drivers/dma/amba-pl08x.c.
This actually brings me to an interesting idea: the s3c64xx SPI driver
is used with the regular dmaengine API and pl330 on S5P and Exynos,
but with the s3c-dma interface and pl080 on S3C64xx.
If we just convert S3C64xx to use the pl080 dmaengine driver
instead, we can apply my SPI patch without breaking anything.
We still need a solution for the ASoC drivers, but they are
not as essential. We could probably move the wrapper files
from plat-samsung/*dma*.c to sounds/soc/samsung when that becomes
the only remaining user.
There is also drivers/mmc/host/s3cmci.c, which uses the s3c-dma
interface, but it is only used on s3c24xx, not s3c64xx or later.
Arnd
From: Tomasz Figa <hidden> Date: 2013-03-05 22:12:31
On Tuesday 05 of March 2013 21:54:22 Arnd Bergmann wrote:
On Tuesday 05 March 2013, Arnd Bergmann wrote:
quoted
The s3c64xx_dma code is also interesting because
it has both an implementation of the s3c_dma interface in
arch/arm/mach-s3c64xx/dma.c and one using the generic interface in
drivers/dma/amba-pl08x.c.
This actually brings me to an interesting idea: the s3c64xx SPI driver
is used with the regular dmaengine API and pl330 on S5P and Exynos,
but with the s3c-dma interface and pl080 on S3C64xx.
If we just convert S3C64xx to use the pl080 dmaengine driver
instead, we can apply my SPI patch without breaking anything.
AFAIR, the PL080 in S3C64xx is a slightly customized variant and requires
some modifications to the driver. However I'm saying this only based on
what I remember from the past, as I haven't checked current version of the
driver yet, so it's possible that it has been modified already.
I believe I will eventually have to take a look at it anyway, as it's a
necessary step towards S3C64xx DT support.
Best regards,
Tomasz
We still need a solution for the ASoC drivers, but they are
not as essential. We could probably move the wrapper files
from plat-samsung/*dma*.c to sounds/soc/samsung when that becomes
the only remaining user.
There is also drivers/mmc/host/s3cmci.c, which uses the s3c-dma
interface, but it is only used on s3c24xx, not s3c64xx or later.
Arnd
--
To unsubscribe from this list: send the line "unsubscribe
linux-samsung-soc" in the body of a message to
majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
AFAIR, the PL080 in S3C64xx is a slightly customized variant and requires
some modifications to the driver. However I'm saying this only based on
what I remember from the past, as I haven't checked current version of the
driver yet, so it's possible that it has been modified already.
I believe I will eventually have to take a look at it anyway, as it's a
necessary step towards S3C64xx DT support.
Ok. Let me know if you need any help adding DT support to the pl08x driver.
It would be nice to have that for SPEAr, Versatile and lpce32xx as well.
All three currently have full DT support except for the DMA binding,
since the common code for that was only added in 3.9-rc1.
Arnd
Am Dienstag, 5. M?rz 2013, 22:54:22 schrieb Arnd Bergmann:
On Tuesday 05 March 2013, Arnd Bergmann wrote:
quoted
The s3c64xx_dma code is also interesting because
it has both an implementation of the s3c_dma interface in
arch/arm/mach-s3c64xx/dma.c and one using the generic interface in
drivers/dma/amba-pl08x.c.
This actually brings me to an interesting idea: the s3c64xx SPI driver
is used with the regular dmaengine API and pl330 on S5P and Exynos,
but with the s3c-dma interface and pl080 on S3C64xx.
If we just convert S3C64xx to use the pl080 dmaengine driver
instead, we can apply my SPI patch without breaking anything.
The S3C24XX starting from S3C2443 (including S3C2416 and S3C2450) also use the
s3c64xx-spi driver.
My argument has of course the problem of me seemingly being the only user of
it currently and it being stuff not in mainline yet [0] :-) .
But on the other hand, it's no use anyway staying attached to old cruft, so
it also wouldn't be a problem to go your way. I'll just try to come up with
a dmaengine driver for s3c24xx after common-clk and pinctrl ;-) .
[0] https://github.com/mmind/linux-es600/blob/topic/es600-devel/arch/arm/mach-
s3c24xx/mach-as090.c#L138
We still need a solution for the ASoC drivers, but they are
not as essential. We could probably move the wrapper files
from plat-samsung/*dma*.c to sounds/soc/samsung when that becomes
the only remaining user.
In ASoC there is also a clear distinction between the different SoC
generations. SND_SAMSUNG_I2S /_PCM /_AC97 ... is only used by newer SoCs
while SND_S3C24XX_I2S and SND_S3C_I2SV2_SOC is used by the legacy SoCs.
Of course "my subarch" is bitten again, as it's using the new sound
interface, but the same as above applies.
Heiko
Am Dienstag, 5. M?rz 2013, 22:54:22 schrieb Arnd Bergmann:
quoted
On Tuesday 05 March 2013, Arnd Bergmann wrote:
quoted
We still need a solution for the ASoC drivers, but they are
not as essential. We could probably move the wrapper files
from plat-samsung/*dma*.c to sounds/soc/samsung when that becomes
the only remaining user.
In ASoC there is also a clear distinction between the different SoC
generations. SND_SAMSUNG_I2S /_PCM /_AC97 ... is only used by newer SoCs
while SND_S3C24XX_I2S and SND_S3C_I2SV2_SOC is used by the legacy SoCs.
Well, the only file that really needs to get changed is dma.c, which
seems to be used by both the old and the new drivers.
Arnd
From: Tomasz Figa <hidden> Date: 2013-03-05 22:48:45
On Tuesday 05 of March 2013 19:19:02 Arnd Bergmann wrote:
On Tuesday 05 March 2013, Tomasz Figa wrote:
quoted
quoted
With this patch set, we can build mach-exynos as part
of a multiplatform kernel, with the following caveats:
* Only DT based boards are supported
As far as I'm aware, there are plans to drop non-DT Exynos support.
Kgene should know more on this.
Yes, that was my understanding as well. It might not actually be too
hard to get multiplatform working with the ATAGS based board files
(we do that on some of the other platforms), but there is probably
no reason to try hard.
quoted
quoted
* Moving to common-clk breaks things including cpufreq
and others. Thomas is working on a patch for this
We have several patches internally for fixing things up to run
correclty with common-clk. I'll see if we can post some patches.
Ok, excellent.
quoted
quoted
* We disable the gpio implementation, which also breaks
stuff, but Thomas has a patch already
The legacy GPIO code is needed only for non-DT case. DT-case uses the
new pinctrl-samsung driver, which is (AFAIK) multiplatform-aware.
Please have a closer look at the "ARM: exynos: work around missing gpio
code on multiplatform" patch, I think there a few files I had to touch
that actually rely on the legacy gpio code:
* the pm-gpio.c file
* the s3c_i2c0_cfg_gpio function
* the eint irqchip
If none of these are needed for DT-based systems, we should probably
build that code conditionally based on the CONFIG_EXYNOS_ATAGS symbol
I introduced.
Yes, none of them are needed for DT-based systems.
quoted
quoted
* sparsemem support is not available on multiplatform
There was some discussion some time ago whether we really need
sparsemem on Exynos. If I remember correctly, it turned out that we
don't. So this is not really an issue.
Ok, good.
quoted
quoted
Arnd Bergmann (23):
ARM: exynos: introduce EXYNOS_ATAGS symbol
irqchip: exynos: remove dependency on mach/irqs.h
tty: serial/samsung: prepare for common clock API
tty: serial/samsung: make register definitions global
tty: serial/samsung: fix modular build
ARM: exynos: move debug-macro.S to include/debug/
i2c: s3c2410: make header file local
mmc: sdhci-s3c: remove platform dependencies
usb: exynos: do not include plat/usb-phy.h
[media] exynos: remove unnecessary header inclusions
video/exynos: remove unnecessary header inclusions
thermal/exynos: remove unnecessary header inclusions
mtd: onenand/samsung: make regs-onenand.h file local
rtc: s3c: make header file local
spi: s3c64xx: move to generic dmaengine API
pwm: samsung: repair the worst MMIO abuses
I'm currently working (in my free time) on a series of cleanup patches
sanitizing Samsung PWM code for S3C64xx and S5PV210 DT (and
multiplatform) support.
Ah, nice.
quoted
On those platforms it is a bit more complex case as there are two
blocks of code that access the same hardware - samsung-time (using
two PWM channels for clocksource and clock events) and pwm-samsung.
Hopefully, I will have some patches ready soon.
How are you planning to solve this? Do you want to have a combined
driver that registers both a clocksource and a pwm?
Let's start with a quick introduction to the s3c-pwm hardware. Each
channel has its own timer value, compare and reload value registers, so
they don't need any extra locking. However there are additional shared
configuration registers, containing things such as start and reload bits
for all channels, prescaler and main divisor values, etc. Those registers
needs synchronization.
Now there are several possible approaches:
1) A brute force one - two separate drivers, based on the fact that the
clocksource driver will be used only on uniprocessor systems, so
a simple _irqsave when accessing a shared register in both will
guarantee correct synchronization.
2) Two separate drivers with some synchronized shared code accessing
registers (_start, _stop, _set_reload, _set_prescaler, _set_divisor,
etc.; all using a shared spinlock).
3) Single driver registering PWM channels, clocksource and clock event
device. This does not seem like a bad idea, since the whole code for
configuration of the PWM block would reside in one location and there
would be no redundancy. However there is a question where such driver
should be placed - drivers/clocksource, drivers/pwm, or maybe somewhere
else?
Personally I wanted to go with first option, which would require least
amount of changes to existing code, at a cost of some code duplication
(but some PWM code is duplicated already).
Best regards,
Tomasz
Hi Arnd,
On Tue, Mar 5, 2013 at 11:12 PM, Arnd Bergmann [off-list ref] wrote:
quoted hunk
In order to build the exynos kernel with CONFIG_ARCH_MULTIPLATFORM,
we must convert all users of the Samsung private DMA interface to
the generic dmaengine API. This converts the sound/soc drivers,
breaking the older s3c platforms in the process, since they do not
support the dmaengine interface yet.
This patch must not get mainlined until mach-s3c* is also converted,
but can be used for testing in the meantime.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
sound/soc/samsung/ac97.c | 15 ------
sound/soc/samsung/dma.c | 104 +++++++++++++++++++++-------------------
sound/soc/samsung/dma.h | 4 +-
sound/soc/samsung/i2s.c | 9 +---
sound/soc/samsung/pcm.c | 13 -----
sound/soc/samsung/s3c2412-i2s.c | 10 ----
sound/soc/samsung/s3c24xx-i2s.c | 10 ----
sound/soc/samsung/spdif.c | 6 ---
8 files changed, 57 insertions(+), 114 deletions(-)
@@ -144,8 +142,6 @@ static int dma_hw_params(struct snd_pcm_substream *substream,unsignedlongtotbytes=params_buffer_bytes(params);structs3c_dma_params*dma=snd_soc_dai_get_dma_data(rtd->cpu_dai,substream);-structsamsung_dma_reqreq;-structsamsung_dma_configconfig;pr_debug("Entered %s\n",__func__);
@@ -157,26 +153,37 @@ static int dma_hw_params(struct snd_pcm_substream *substream,/* this may get called several times by oss emulation*withdifferentparams-HW*/if(prtd->params==NULL){+structdma_slave_configconfig;+dma_cap_mask_tmask;+/* prepare DMA */prtd->params=dma;-pr_debug("params %p, client %p, channel %d\n",prtd->params,-prtd->params->client,prtd->params->channel);--prtd->params->ops=samsung_dma_get_ops();--req.cap=(samsung_dma_has_circular()?-DMA_CYCLIC:DMA_SLAVE);-req.client=prtd->params->client;-config.direction=-(substream->stream==SNDRV_PCM_STREAM_PLAYBACK-?DMA_MEM_TO_DEV:DMA_DEV_TO_MEM);-config.width=prtd->params->dma_size;-config.fifo=prtd->params->dma_addr;-prtd->params->ch=prtd->params->ops->request(-prtd->params->channel,&req,rtd->cpu_dai->dev,-prtd->params->ch_name);-prtd->params->ops->config(prtd->params->ch,&config);+pr_debug("params %p, channel %d\n",prtd->params,+prtd->params->channel);++dma_cap_zero(mask);+dma_cap_set(DMA_CYCLIC,mask);++prtd->params->ch=dma_request_slave_channel_compat(mask,+pl330_filter,(void*)prtd->params->channel,+rtd->cpu_dai->dev,prtd->params->ch_name);++memset(&config,0,sizeof(structdma_slave_config));++if(substream->stream==SNDRV_PCM_STREAM_PLAYBACK){+config.direction=DMA_MEM_TO_DEV;+config.dst_addr=prtd->params->dma_size;+config.dst_addr_width=prtd->params->dma_addr;
dma_addr and dma_size got interchanged.
Except the above one I tested this patch on 5250. It's working fine.
@@ -13,12 +13,10 @@#define _S3C_AUDIO_Hstructs3c_dma_params{-structs3c2410_dma_client*client;/* stream identifier */intchannel;/* Channel ID */dma_addr_tdma_addr;intdma_size;/* Size of the DMA transfer */-unsignedch;-structsamsung_dma_ops*ops;+structdma_chan*ch;char*ch_name;};
@@ -431,7 +426,6 @@ static int spdif_probe(struct platform_device *pdev)}spdif_stereo_out.dma_size=2;-spdif_stereo_out.client=&spdif_dma_client_out;spdif_stereo_out.dma_addr=mem_res->start+DATA_OUTBUF;spdif_stereo_out.channel=dma_res->start;--
1.8.1.2
--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Arnd,
On Tue, Mar 5, 2013 at 11:12 PM, Arnd Bergmann [off-list ref] wrote:
quoted hunk
The spi-s3c64xx uses a Samsung proprietary interface for
talking to the DMA engine, which does not work with
multiplatform kernels. Since the driver can also operate
in PIO mode without any DMA, older platforms that do
not support the DMA engine API will still work, although
slower.
The conversion was rather mechanical, since the samsung
interface is just a shallow wrapper around the dmaengine
interface.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm/plat-samsung/devs.c | 10 +++
drivers/spi/spi-s3c64xx.c | 107 ++++++++++++++----------------
include/linux/platform_data/spi-s3c64xx.h | 3 +
3 files changed, 62 insertions(+), 58 deletions(-)
@@ -713,9 +701,9 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,}/* Polling method for xfers not bigger than FIFO capacity */-if(xfer->len<=((FIFO_LVL_MASK(sdd)>>1)+1))-use_dma=0;-else+use_dma=0;+if(sdd->rx_dma.ch&&sdd->tx_dma.ch&&+(xfer->len>((FIFO_LVL_MASK(sdd)>>1)+1)))use_dma=1;spin_lock_irqsave(&sdd->lock,flags);
@@ -750,10 +738,10 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,if(use_dma){if(xfer->tx_buf!=NULL&&(sdd->state&TXBUSY))-sdd->ops->stop(sdd->tx_dma.ch);+dmaengine_terminate_all(sdd->tx_dma.ch);if(xfer->rx_buf!=NULL&&(sdd->state&RXBUSY))-sdd->ops->stop(sdd->rx_dma.ch);+dmaengine_terminate_all(sdd->rx_dma.ch);}gotoout;
@@ -1207,15 +1200,15 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)}sdd->cur_bpw=8;-if(!sdd->pdev->dev.of_node){+structresource*res;res=platform_get_resource(pdev,IORESOURCE_DMA,0);if(!res){dev_err(&pdev->dev,"Unable to get SPI tx dma ""resource\n");return-ENXIO;}-sdd->tx_dma.dmach=res->start;+sdd->tx_dma.request=res->start;res=platform_get_resource(pdev,IORESOURCE_DMA,1);if(!res){
@@ -1223,12 +1216,11 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)"resource\n");return-ENXIO;}-sdd->rx_dma.dmach=res->start;+sdd->rx_dma.request=res->start;}sdd->tx_dma.direction=DMA_MEM_TO_DEV;sdd->rx_dma.direction=DMA_DEV_TO_MEM;-master->dev.of_node=pdev->dev.of_node;master->bus_num=sdd->port_id;master->setup=s3c64xx_spi_setup;
@@ -1314,8 +1306,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)sdd->port_id,master->num_chipselect);dev_dbg(&pdev->dev,"\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",mem_res->end,mem_res->start,-sdd->rx_dma.dmach,sdd->tx_dma.dmach);-+sdd->rx_dma.request,sdd->tx_dma.request);pm_runtime_enable(&pdev->dev);return0;
This one also tested on exynos5250. It's working fine.
Thanks
Padma
/**
--
1.8.1.2
--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tuesday 05 of March 2013 19:19:02 Arnd Bergmann wrote:
quoted
If none of these are needed for DT-based systems, we should probably
build that code conditionally based on the CONFIG_EXYNOS_ATAGS symbol
I introduced.
Yes, none of them are needed for DT-based systems.
Ah, good. I'll try to make more code conditional then.
quoted
How are you planning to solve this? Do you want to have a combined
driver that registers both a clocksource and a pwm?
Let's start with a quick introduction to the s3c-pwm hardware. Each
channel has its own timer value, compare and reload value registers, so
they don't need any extra locking. However there are additional shared
configuration registers, containing things such as start and reload bits
for all channels, prescaler and main divisor values, etc. Those registers
needs synchronization.
Now there are several possible approaches:
1) A brute force one - two separate drivers, based on the fact that the
clocksource driver will be used only on uniprocessor systems, so
a simple _irqsave when accessing a shared register in both will
guarantee correct synchronization.
2) Two separate drivers with some synchronized shared code accessing
registers (_start, _stop, _set_reload, _set_prescaler, _set_divisor,
etc.; all using a shared spinlock).
3) Single driver registering PWM channels, clocksource and clock event
device. This does not seem like a bad idea, since the whole code for
configuration of the PWM block would reside in one location and there
would be no redundancy. However there is a question where such driver
should be placed - drivers/clocksource, drivers/pwm, or maybe somewhere
else?
Personally I wanted to go with first option, which would require least
amount of changes to existing code, at a cost of some code duplication
(but some PWM code is duplicated already).
I would prefer option 3. That is also easier to implement with a straightforward
DT binding that defines a single node with the clock registers. The location
doesn't have an obvious answer, but I would probably put them into
drivers/clocksource if the PWM maintainer agrees.
Option 2 would probably come down to having a trivial MFD driver exposing
a regmap. You can probably reuse drivers/mfd/syscon.c for this and make
the node compatible with "syscon" to designate the clock registers as
a system-wide resource, making the other device nodes register-less.
Arnd
On Wed, Mar 06, 2013 at 10:50:42AM +0000, Arnd Bergmann wrote:
On Tuesday 05 March 2013, Tomasz Figa wrote:
quoted
On Tuesday 05 of March 2013 19:19:02 Arnd Bergmann wrote:
quoted
quoted
If none of these are needed for DT-based systems, we should probably
build that code conditionally based on the CONFIG_EXYNOS_ATAGS symbol
I introduced.
Yes, none of them are needed for DT-based systems.
Ah, good. I'll try to make more code conditional then.
quoted
quoted
How are you planning to solve this? Do you want to have a combined
driver that registers both a clocksource and a pwm?
Let's start with a quick introduction to the s3c-pwm hardware. Each
channel has its own timer value, compare and reload value registers, so
they don't need any extra locking. However there are additional shared
configuration registers, containing things such as start and reload bits
for all channels, prescaler and main divisor values, etc. Those registers
needs synchronization.
Now there are several possible approaches:
1) A brute force one - two separate drivers, based on the fact that the
clocksource driver will be used only on uniprocessor systems, so
a simple _irqsave when accessing a shared register in both will
guarantee correct synchronization.
2) Two separate drivers with some synchronized shared code accessing
registers (_start, _stop, _set_reload, _set_prescaler, _set_divisor,
etc.; all using a shared spinlock).
3) Single driver registering PWM channels, clocksource and clock event
device. This does not seem like a bad idea, since the whole code for
configuration of the PWM block would reside in one location and there
would be no redundancy. However there is a question where such driver
should be placed - drivers/clocksource, drivers/pwm, or maybe somewhere
else?
Personally I wanted to go with first option, which would require least
amount of changes to existing code, at a cost of some code duplication
(but some PWM code is duplicated already).
I would prefer option 3. That is also easier to implement with a straightforward
DT binding that defines a single node with the clock registers. The location
doesn't have an obvious answer, but I would probably put them into
drivers/clocksource if the PWM maintainer agrees.
Option 2 would probably come down to having a trivial MFD driver exposing
a regmap. You can probably reuse drivers/mfd/syscon.c for this and make
the node compatible with "syscon" to designate the clock registers as
a system-wide resource, making the other device nodes register-less.
I think option 2 is the standard method if one hardware block provides
several logical devices. I find it to be a pretty nice solution to this
problem. We also have precedent in the PWM subsystem. The TWL chips for
instance use it to create a platform device which is later driven by a
PWM driver.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130306/fdd76f07/attachment.sig>
Am Dienstag, 5. M?rz 2013, 23:48:45 schrieb Tomasz Figa:
On Tuesday 05 of March 2013 19:19:02 Arnd Bergmann wrote:
quoted
On Tuesday 05 March 2013, Tomasz Figa wrote:
quoted
quoted
With this patch set, we can build mach-exynos as part
of a multiplatform kernel, with the following caveats:
* Only DT based boards are supported
As far as I'm aware, there are plans to drop non-DT Exynos support.
Kgene should know more on this.
Yes, that was my understanding as well. It might not actually be too
hard to get multiplatform working with the ATAGS based board files
(we do that on some of the other platforms), but there is probably
no reason to try hard.
quoted
quoted
* Moving to common-clk breaks things including cpufreq
and others. Thomas is working on a patch for this
We have several patches internally for fixing things up to run
correclty with common-clk. I'll see if we can post some patches.
Ok, excellent.
quoted
quoted
* We disable the gpio implementation, which also breaks
stuff, but Thomas has a patch already
The legacy GPIO code is needed only for non-DT case. DT-case uses the
new pinctrl-samsung driver, which is (AFAIK) multiplatform-aware.
Please have a closer look at the "ARM: exynos: work around missing gpio
code on multiplatform" patch, I think there a few files I had to touch
that actually rely on the legacy gpio code:
* the pm-gpio.c file
* the s3c_i2c0_cfg_gpio function
* the eint irqchip
If none of these are needed for DT-based systems, we should probably
build that code conditionally based on the CONFIG_EXYNOS_ATAGS symbol
I introduced.
Yes, none of them are needed for DT-based systems.
quoted
quoted
quoted
* sparsemem support is not available on multiplatform
There was some discussion some time ago whether we really need
sparsemem on Exynos. If I remember correctly, it turned out that we
don't. So this is not really an issue.
Ok, good.
quoted
quoted
Arnd Bergmann (23):
ARM: exynos: introduce EXYNOS_ATAGS symbol
irqchip: exynos: remove dependency on mach/irqs.h
tty: serial/samsung: prepare for common clock API
tty: serial/samsung: make register definitions global
tty: serial/samsung: fix modular build
ARM: exynos: move debug-macro.S to include/debug/
i2c: s3c2410: make header file local
mmc: sdhci-s3c: remove platform dependencies
usb: exynos: do not include plat/usb-phy.h
[media] exynos: remove unnecessary header inclusions
video/exynos: remove unnecessary header inclusions
thermal/exynos: remove unnecessary header inclusions
mtd: onenand/samsung: make regs-onenand.h file local
rtc: s3c: make header file local
spi: s3c64xx: move to generic dmaengine API
pwm: samsung: repair the worst MMIO abuses
I'm currently working (in my free time) on a series of cleanup patches
sanitizing Samsung PWM code for S3C64xx and S5PV210 DT (and
multiplatform) support.
Ah, nice.
quoted
On those platforms it is a bit more complex case as there are two
blocks of code that access the same hardware - samsung-time (using
two PWM channels for clocksource and clock events) and pwm-samsung.
Hopefully, I will have some patches ready soon.
How are you planning to solve this? Do you want to have a combined
driver that registers both a clocksource and a pwm?
Let's start with a quick introduction to the s3c-pwm hardware. Each
channel has its own timer value, compare and reload value registers, so
they don't need any extra locking. However there are additional shared
configuration registers, containing things such as start and reload bits
for all channels, prescaler and main divisor values, etc. Those registers
needs synchronization.
Now there are several possible approaches:
1) A brute force one - two separate drivers, based on the fact that the
clocksource driver will be used only on uniprocessor systems, so
a simple _irqsave when accessing a shared register in both will
guarantee correct synchronization.
2) Two separate drivers with some synchronized shared code accessing
registers (_start, _stop, _set_reload, _set_prescaler, _set_divisor,
etc.; all using a shared spinlock).
3) Single driver registering PWM channels, clocksource and clock event
device. This does not seem like a bad idea, since the whole code for
configuration of the PWM block would reside in one location and there
would be no redundancy. However there is a question where such driver
should be placed - drivers/clocksource, drivers/pwm, or maybe somewhere
else?
Personally I wanted to go with first option, which would require least
amount of changes to existing code, at a cost of some code duplication
(but some PWM code is duplicated already).
Do you also want to include the prescaler and divider handling (that is
currently sitting pwm-clock.c in plat-samsung) into this new driver?
Because for my current common-clk work I ported the pwm-clock stuff to the
common-clk-fw to keep the timer running. Unfinished code below. The pwm and
time drivers do not use the TCFG registers at the beginning of the block.
Either way is fine with me, I just want to prevent me doing more cleanups
there, when the right way is thru your new driver :-)
Heiko
unfinished but working clk-pwm.c:
/*
* Copyright (c) 2007 Simtec Electronics
* Copyright (c) 2007, 2008 Ben Dooks
* Ben Dooks [off-list ref]
* Copyright (c) 2013 Heiko Stuebner [off-list ref]
*
* 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.
*
* Common Clock Framework support for Samsung pwm clocks
*/
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/syscore_ops.h>
#include <linux/io.h>
#include <plat/cpu.h>
#include <mach/map.h>
#include "clk.h"
/* Each of the timers 0 through 5 go through the following
* clock tree, with the inputs depending on the timers.
*
* pclk ---- [ prescaler 0 ] -+---> timer 0
* +---> timer 1
*
* pclk ---- [ prescaler 1 ] -+---> timer 2
* +---> timer 3
* \---> timer 4
*
* Which are fed into the timers as so:
*
* prescaled 0 ---- [ div 2,4,8,16 ] ---\
* [mux] -> timer 0
* tclk 0 ------------------------------/
*
* prescaled 0 ---- [ div 2,4,8,16 ] ---\
* [mux] -> timer 1
* tclk 0 ------------------------------/
*
*
* prescaled 1 ---- [ div 2,4,8,16 ] ---\
* [mux] -> timer 2
* tclk 1 ------------------------------/
*
* prescaled 1 ---- [ div 2,4,8,16 ] ---\
* [mux] -> timer 3
* tclk 1 ------------------------------/
*
* prescaled 1 ---- [ div 2,4,8, 16 ] --\
* [mux] -> timer 4
* tclk 1 ------------------------------/
*
* Since the mux and the divider are tied together in the
* same register space, it is impossible to set the parent
* and the rate at the same time. To avoid this, we add an
* intermediate 'prescaled-and-divided' clock to select
* as the parent for the timer input clock called tdiv.
*
* prescaled clk --> pwm-tdiv ---\
* [ mux ] --> timer X
* tclk -------------------------/
*/
enum pwm_clks {
none,
tclk0, tclk1, tdiv0, tdiv1, tdiv2, tdiv3, tdiv4,
tin0, tin1, tin2, tin3, tin4,
nr_clks,
};
/* the soc types */
enum supported_socs {
S3C24XX,
S3C64XX, /* also S5PC100 */
S5P64XX,
};
/* clock controller register offsets */
#define TCFG0 0
#define TCFG1 0x4
static DEFINE_SPINLOCK(lock);
static int current_soc;
static void __iomem *reg_base;
static struct clk **clk_table;
#ifdef CONFIG_OF
static struct clk_onecell_data clk_data;
#endif
#ifdef CONFIG_PM_SLEEP
static struct samsung_clk_reg_dump reg_dump[2] = {
{ .offset = TCFG0 },
{ .offset = TCFG1 },
};
static int samsung_clk_pwm_suspend(void)
{
reg_dump[0].value = readl_relaxed(reg_base + reg_dump[0].offset);
reg_dump[1].value = readl_relaxed(reg_base + reg_dump[1].offset);
return 0;
}
static void samsung_clk_pwm_resume(void)
{
writel_relaxed(reg_dump[0].value, reg_base + reg_dump[0].offset);
writel_relaxed(reg_dump[1].value, reg_base + reg_dump[1].offset);
}
static struct syscore_ops samsung_clk_pwm_syscore_ops = {
.suspend = samsung_clk_pwm_suspend,
.resume = samsung_clk_pwm_resume,
};
#endif /* CONFIG_PM_SLEEP */
#define S3C2410_TCFG1_MUX_TCLK (4 << 0)
#define S3C64XX_TCFG1_MUX_TCLK (5 << 0)
/**
* pwm_cfg_src_is_tclk() - return whether the given mux config is a tclk
* @tcfg: The timer TCFG1 register bits shifted down to 0.
*
* Return true if the given configuration from TCFG1 is a TCLK instead
* any of the TDIV clocks.
*/
static inline int pwm_cfg_src_is_tclk(unsigned long tcfg)
{
if (current_soc == S3C24XX)
return tcfg == S3C2410_TCFG1_MUX_TCLK;
else if (current_soc == S3C64XX)
return tcfg >= S3C64XX_TCFG1_MUX_TCLK;
else if (current_soc == S5P64XX)
return 0;
else
return tcfg == S3C64XX_TCFG1_MUX_TCLK;
}
struct clk_tdiv {
struct clk_divider divider;
const struct clk_ops *ops;
void __iomem *reg;
unsigned int divisor;
};
static inline struct clk_tdiv *to_clk_tdiv(struct clk_hw *hw)
{
struct clk_divider *divider = container_of(hw, struct clk_divider, hw);
return container_of(divider, struct clk_tdiv, divider);
}
static unsigned long clk_tdiv_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_tdiv *tdiv = to_clk_tdiv(hw);
unsigned long tcfg1 = readl_relaxed(tdiv->reg);
tcfg1 >>= tdiv->divider.shift;
tcfg1 &= ((1 << (tdiv->divider.width)) - 1);
if (pwm_cfg_src_is_tclk(tcfg1))
return parent_rate / tdiv->divisor;
else
return tdiv->ops->recalc_rate(&tdiv->divider.hw, parent_rate);
}
static long clk_tdiv_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
struct clk_tdiv *tdiv = to_clk_tdiv(hw);
return tdiv->ops->round_rate(&tdiv->divider.hw, rate, parent_rate);
}
static int clk_tdiv_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_tdiv *tdiv = to_clk_tdiv(hw);
unsigned long tcfg1 = readl_relaxed(tdiv->reg);
unsigned long divisor;
int ret = 0;
tcfg1 >>= tdiv->divider.shift;
tcfg1 &= ((1 << (tdiv->divider.width)) - 1);
rate = tdiv->ops->round_rate(&tdiv->divider.hw, rate, &parent_rate);
divisor = parent_rate / rate;
if (divisor > 16)
return -EINVAL;
tdiv->divisor = divisor;
/* Update the current MUX settings if we are currently
* selected as the clock source for this clock. */
if (!pwm_cfg_src_is_tclk(tcfg1))
ret = tdiv->ops->set_rate(&tdiv->divider.hw, rate, parent_rate);
return ret;
}
static struct clk_ops clk_tdiv_ops = {
.recalc_rate = clk_tdiv_recalc_rate,
.round_rate = clk_tdiv_round_rate,
.set_rate = clk_tdiv_set_rate,
};
static struct clk *samsung_clk_register_tdiv(const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift,
u8 clk_divider_flags, const struct clk_div_table *table)
{
unsigned long tcfg1;
const struct clk_div_table *clkt;
struct clk_tdiv *tdiv;
struct clk *clk;
struct clk_init_data init;
tdiv = kzalloc(sizeof(struct clk_tdiv), GFP_KERNEL);
if (!tdiv)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &clk_tdiv_ops;
init.flags = flags;
init.parent_names = (parent_name ? &parent_name: NULL);
init.num_parents = (parent_name ? 1 : 0);
/* struct clk_divider assignments */
tdiv->divider.reg = reg;
tdiv->divider.shift = shift;
tdiv->divider.width = 4;
tdiv->divider.flags = clk_divider_flags;
tdiv->divider.lock = &lock;
tdiv->divider.hw.init = &init;
tdiv->divider.table = table;
tdiv->ops = &clk_divider_ops;
tcfg1 = readl_relaxed(reg);
tcfg1 >>= tdiv->divider.shift;
tcfg1 &= ((1 << (tdiv->divider.width)) - 1);
tdiv->reg = reg;
tdiv->divisor = 1;
for (clkt = table; clkt->div; clkt++)
if (clkt->val == tcfg1)
tdiv->divisor = clkt->div;
clk = clk_register(NULL, &tdiv->divider.hw);
if (IS_ERR(clk))
kfree(tdiv);
return clk;
}
struct clk_tin {
struct clk_hw hw;
void __iomem *reg;
u8 shift;
u8 width;
spinlock_t *lock;
};
#define to_clk_tin(_hw) container_of(_hw, struct clk_tin, hw)
static u8 clk_tin_get_parent(struct clk_hw *hw)
{
struct clk_tin *tin = to_clk_tin(hw);
unsigned long tcfg1 = readl_relaxed(tin->reg);
tcfg1 >>= tin->shift;
tcfg1 &= ((1 << (tin->width)) - 1);
/* assume tclk is parent 0 and tdiv is parent 1 */
return pwm_cfg_src_is_tclk(tcfg1) ? 0 : 1;
}
static int clk_tin_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_tin *tin = to_clk_tin(hw);
struct clk *tdiv;
struct clk *prescaler;
unsigned long tcfg1;
unsigned long flags = 0;
unsigned long div;
int bits;
switch (index) {
case 0:
if (current_soc == S3C24XX)
bits = S3C2410_TCFG1_MUX_TCLK << tin->shift;
else if (current_soc == S5P64XX)
bits = 0;
else
bits = S3C64XX_TCFG1_MUX_TCLK << tin->shift;
break;
case 1:
tdiv = clk_get(NULL, hw->init->parent_names[0]);
prescaler = clk_get_parent(tdiv);
div = clk_get_rate(prescaler) / clk_get_rate(tdiv);
bits = (current_soc == S3C24XX) ? (ilog2(div) - 1) : ilog2(div);
bits &= ((1 << (tin->width)) - 1);
bits <<= tin->shift;
clk_put(tdiv);
break;
default:
return -EINVAL;
}
spin_lock_irqsave(tin->lock, flags);
tcfg1 = readl_relaxed(tin->reg);
tcfg1 &= ~(((1 << tin->width) - 1) << tin->shift);
tcfg1 |= bits;
writel_relaxed(tcfg1, tin->reg);
spin_unlock_irqrestore(tin->lock, flags);
return 0;
}
static const struct clk_ops clk_tin_ops = {
.get_parent = clk_tin_get_parent,
.set_parent = clk_tin_set_parent,
};
static struct clk *samsung_clk_register_tin(const char *name,
const char **parent_names, u8 num_parents,
void __iomem *reg, u8 shift, u8 width)
{
struct clk_tin *tin;
struct clk *clk;
struct clk_init_data init;
/* allocate the mux */
tin = kzalloc(sizeof(struct clk_tin), GFP_KERNEL);
if (!tin) {
pr_err("%s: could not allocate tin clk\n", __func__);
return ERR_PTR(-ENOMEM);
}
init.name = name;
init.ops = &clk_tin_ops;
init.parent_names = parent_names;
init.num_parents = num_parents;
/* struct clk_mux assignments */
tin->reg = reg;
tin->shift = shift;
tin->width = width;
tin->lock = &lock;
tin->hw.init = &init;
clk = clk_register(NULL, &tin->hw);
if (IS_ERR(clk))
kfree(tin);
return clk;
}
PNAME(tin0_p) = { "pwm-tclk0", "pwm-tdiv0" };
PNAME(tin1_p) = { "pwm-tclk0", "pwm-tdiv1" };
PNAME(tin2_p) = { "pwm-tclk1", "pwm-tdiv2" };
PNAME(tin3_p) = { "pwm-tclk1", "pwm-tdiv3" };
PNAME(tin4_p) = { "pwm-tclk1", "pwm-tdiv4" };
static struct clk_div_table tdiv_s3c24xx_d[] = {
{ .val = 0, .div = 2 },
{ .val = 1, .div = 4 },
{ .val = 2, .div = 8 },
{ .val = 3, .div = 16 },
{ .div = 0 },
};
struct samsung_div_clock pwm_s3c24xx_tdiv_dividers[] __initdata = {
DIV_T(tdiv0, "pwm-tdiv0", "pwm-scaler0", TCFG1, 0, 4, tdiv_s3c24xx_d),
DIV_T(tdiv1, "pwm-tdiv1", "pwm-scaler0", TCFG1, 4, 4, tdiv_s3c24xx_d),
DIV_T(tdiv2, "pwm-tdiv2", "pwm-scaler1", TCFG1, 8, 4, tdiv_s3c24xx_d),
DIV_T(tdiv3, "pwm-tdiv3", "pwm-scaler1", TCFG1, 12, 4, tdiv_s3c24xx_d),
DIV_T(tdiv4, "pwm-tdiv4", "pwm-scaler1", TCFG1, 16, 4, tdiv_s3c24xx_d),
};
static struct clk_div_table tdiv_s3c64xx_d[] = {
{ .val = 0, .div = 1 },
{ .val = 1, .div = 2 },
{ .val = 2, .div = 4 },
{ .val = 3, .div = 8 },
{ .val = 4, .div = 16 },
{ .div = 0 },
};
struct samsung_div_clock pwm_s3c64xx_tdiv_dividers[] __initdata = {
DIV_T(tdiv0, "pwm-tdiv0", "pwm-scaler0", TCFG1, 0, 4, tdiv_s3c64xx_d),
DIV_T(tdiv1, "pwm-tdiv1", "pwm-scaler0", TCFG1, 4, 4, tdiv_s3c64xx_d),
DIV_T(tdiv2, "pwm-tdiv2", "pwm-scaler1", TCFG1, 8, 4, tdiv_s3c64xx_d),
DIV_T(tdiv3, "pwm-tdiv3", "pwm-scaler1", TCFG1, 12, 4, tdiv_s3c64xx_d),
DIV_T(tdiv4, "pwm-tdiv4", "pwm-scaler1", TCFG1, 16, 4, tdiv_s3c64xx_d),
};
struct samsung_mux_clock pwm_tin[] __initdata = {
MUX(tin0, "pwm-tin0", tin0_p, TCFG1, 0, 4),
MUX(tin1, "pwm-tin1", tin1_p, TCFG1, 4, 4),
MUX(tin2, "pwm-tin2", tin2_p, TCFG1, 8, 4),
MUX(tin3, "pwm-tin3", tin3_p, TCFG1, 12, 4),
MUX(tin4, "pwm-tin4", tin4_p, TCFG1, 16, 4),
};
struct samsung_clock_alias pwm_aliases[] __initdata = {
ALIAS(tdiv0, "s3c24xx-pwm.0", "pwm-tdiv"),
ALIAS(tdiv1, "s3c24xx-pwm.1", "pwm-tdiv"),
ALIAS(tdiv2, "s3c24xx-pwm.2", "pwm-tdiv"),
ALIAS(tdiv3, "s3c24xx-pwm.3", "pwm-tdiv"),
ALIAS(tdiv4, "s3c24xx-pwm.4", "pwm-tdiv"),
ALIAS(tin0, "s3c24xx-pwm.0", "pwm-tin"),
ALIAS(tin1, "s3c24xx-pwm.1", "pwm-tin"),
ALIAS(tin2, "s3c24xx-pwm.2", "pwm-tin"),
ALIAS(tin3, "s3c24xx-pwm.3", "pwm-tin"),
ALIAS(tin4, "s3c24xx-pwm.4", "pwm-tin"),
};
#ifdef CONFIG_OF
static struct of_device_id pwm_clk_ids[] __initdata = {
{ .compatible = "samsung,s3c24xx-clock-pwm",
.data = (void *)S3C24XX, },
{ .compatible = "samsung,s3c64xx-clock-pwm",
.data = (void *)S3C64XX, },
{ .compatible = "samsung,s5p64xx-clock-pwm",
.data = (void *)S5P64XX, },
{ },
};
#endif
void __init samsung_pwm_clk_init(struct device_node *np)
{
struct clk *clk;
struct samsung_div_clock *tdiv_list;
struct samsung_mux_clock *tin_list;
struct samsung_clock_alias *alias_list;
unsigned int idx;
int ret;
if (np) {
const struct of_device_id *match;
match = of_match_node(pwm_clk_ids, np);
current_soc = (u32)match->data;
reg_base = of_iomap(np, 0);
if (!reg_base)
panic("%s: failed to map registers\n", __func__);
} else {
reg_base = S3C_VA_TIMER;
if (soc_is_s3c24xx())
current_soc = S3C24XX;
else if (soc_is_s3c64xx() || soc_is_s5pc100())
current_soc = S3C64XX;
else if (soc_is_s5p6440() || soc_is_s5p6450())
current_soc = S5P64XX;
else
panic("%s: unable to determine soc\n", __func__);
}
clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
if (!clk_table)
panic("could not allocate clock lookup table\n");
#ifdef CONFIG_OF
clk_data.clks = clk_table;
clk_data.clk_num = nr_clks;
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
#endif
#ifdef CONFIG_PM_SLEEP
register_syscore_ops(&samsung_clk_pwm_syscore_ops);
#endif
clk = clk_register_fixed_rate(NULL, "pwm-tclk0", NULL, CLK_IS_ROOT, 0);
clk = clk_register_fixed_rate(NULL, "pwm-tclk1", NULL, CLK_IS_ROOT, 0);
clk = clk_register_divider(NULL, "pwm-scaler0", "pwm", 0, reg_base + TCFG0, 0, 8, 0, &lock);
clk = clk_register_divider(NULL, "pwm-scaler1", "pwm", 0, reg_base + TCFG0, 8, 8, 0, &lock);
tdiv_list = (current_soc == S3C24XX) ? pwm_s3c24xx_tdiv_dividers
: pwm_s3c64xx_tdiv_dividers;
for (idx = 0; idx < 5; idx++, tdiv_list++) {
clk = samsung_clk_register_tdiv(tdiv_list->name, tdiv_list->parent_name,
tdiv_list->flags, reg_base + tdiv_list->offset,
tdiv_list->shift, tdiv_list->div_flags, tdiv_list->table);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n", __func__,
tdiv_list->name);
continue;
}
if (clk_table && tdiv_list->id)
clk_table[tdiv_list->id] = clk;
}
tin_list = pwm_tin;
for (idx = 0; idx < 5; idx++, tin_list++) {
clk = samsung_clk_register_tin(tin_list->name,
tin_list->parent_names, tin_list->num_parents,
reg_base + tin_list->offset, tin_list->shift,
tin_list->width);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n", __func__,
tin_list->name);
continue;
}
if (clk_table && tin_list->id)
clk_table[tin_list->id] = clk;
}
alias_list = pwm_aliases;
for (idx = 0; idx < ARRAY_SIZE(pwm_aliases); idx++, alias_list++) {
if (!alias_list->id) {
pr_err("%s: clock id missing for index %d\n", __func__,
idx);
continue;
}
clk = clk_table[alias_list->id];
if (!clk) {
pr_err("%s: failed to find clock %d\n", __func__,
alias_list->id);
continue;
}
ret = clk_register_clkdev(clk, alias_list->alias,
alias_list->dev_name);
if (ret)
pr_err("%s: failed to register lookup %s\n",
__func__, alias_list->alias);
}
}
From: Tomasz Figa <hidden> Date: 2013-03-06 22:55:17
On Wednesday 06 of March 2013 23:14:56 Heiko St?bner wrote:
Am Dienstag, 5. M?rz 2013, 23:48:45 schrieb Tomasz Figa:
quoted
On Tuesday 05 of March 2013 19:19:02 Arnd Bergmann wrote:
quoted
On Tuesday 05 March 2013, Tomasz Figa wrote:
quoted
quoted
With this patch set, we can build mach-exynos as part
of a multiplatform kernel, with the following caveats:
* Only DT based boards are supported
As far as I'm aware, there are plans to drop non-DT Exynos
support.
Kgene should know more on this.
Yes, that was my understanding as well. It might not actually be too
hard to get multiplatform working with the ATAGS based board files
(we do that on some of the other platforms), but there is probably
no reason to try hard.
quoted
quoted
* Moving to common-clk breaks things including cpufreq
and others. Thomas is working on a patch for this
We have several patches internally for fixing things up to run
correclty with common-clk. I'll see if we can post some patches.
Ok, excellent.
quoted
quoted
* We disable the gpio implementation, which also breaks
stuff, but Thomas has a patch already
The legacy GPIO code is needed only for non-DT case. DT-case uses
the
new pinctrl-samsung driver, which is (AFAIK) multiplatform-aware.
Please have a closer look at the "ARM: exynos: work around missing
gpio
code on multiplatform" patch, I think there a few files I had to
touch
that actually rely on the legacy gpio code:
* the pm-gpio.c file
* the s3c_i2c0_cfg_gpio function
* the eint irqchip
If none of these are needed for DT-based systems, we should probably
build that code conditionally based on the CONFIG_EXYNOS_ATAGS
symbol
I introduced.
Yes, none of them are needed for DT-based systems.
quoted
quoted
quoted
* sparsemem support is not available on multiplatform
There was some discussion some time ago whether we really need
sparsemem on Exynos. If I remember correctly, it turned out that
we
don't. So this is not really an issue.
Ok, good.
quoted
quoted
Arnd Bergmann (23):
ARM: exynos: introduce EXYNOS_ATAGS symbol
irqchip: exynos: remove dependency on mach/irqs.h
tty: serial/samsung: prepare for common clock API
tty: serial/samsung: make register definitions global
tty: serial/samsung: fix modular build
ARM: exynos: move debug-macro.S to include/debug/
i2c: s3c2410: make header file local
mmc: sdhci-s3c: remove platform dependencies
usb: exynos: do not include plat/usb-phy.h
[media] exynos: remove unnecessary header inclusions
video/exynos: remove unnecessary header inclusions
thermal/exynos: remove unnecessary header inclusions
mtd: onenand/samsung: make regs-onenand.h file local
rtc: s3c: make header file local
spi: s3c64xx: move to generic dmaengine API
pwm: samsung: repair the worst MMIO abuses
I'm currently working (in my free time) on a series of cleanup
patches
sanitizing Samsung PWM code for S3C64xx and S5PV210 DT (and
multiplatform) support.
Ah, nice.
quoted
On those platforms it is a bit more complex case as there are two
blocks of code that access the same hardware - samsung-time (using
two PWM channels for clocksource and clock events) and
pwm-samsung.
Hopefully, I will have some patches ready soon.
How are you planning to solve this? Do you want to have a combined
driver that registers both a clocksource and a pwm?
Let's start with a quick introduction to the s3c-pwm hardware. Each
channel has its own timer value, compare and reload value registers,
so
they don't need any extra locking. However there are additional shared
configuration registers, containing things such as start and reload
bits for all channels, prescaler and main divisor values, etc. Those
registers needs synchronization.
Now there are several possible approaches:
1) A brute force one - two separate drivers, based on the fact that
the
clocksource driver will be used only on uniprocessor systems, so
a simple _irqsave when accessing a shared register in both will
guarantee correct synchronization.
2) Two separate drivers with some synchronized shared code accessing
registers (_start, _stop, _set_reload, _set_prescaler,
_set_divisor,
etc.; all using a shared spinlock).
3) Single driver registering PWM channels, clocksource and clock event
device. This does not seem like a bad idea, since the whole code
for
configuration of the PWM block would reside in one location and
there
would be no redundancy. However there is a question where such
driver
should be placed - drivers/clocksource, drivers/pwm, or maybe
somewhere
else?
Personally I wanted to go with first option, which would require least
amount of changes to existing code, at a cost of some code duplication
(but some PWM code is duplicated already).
Do you also want to include the prescaler and divider handling (that is
currently sitting pwm-clock.c in plat-samsung) into this new driver?
Yes.
I don't think we need a full fledged clock driver for PWM prescalers and
dividers, because they don't provide any clocks to be used by other
peripherals, but rather simply control frequency of timers.
Because for my current common-clk work I ported the pwm-clock stuff to
the common-clk-fw to keep the timer running. Unfinished code below. The
pwm and time drivers do not use the TCFG registers at the beginning of
the block.
Either way is fine with me, I just want to prevent me doing more
cleanups there, when the right way is thru your new driver :-)
Heiko
OK. From my side, I hope I will manage to post first version of my patches
this week (or weekend).
Best regards,
Tomasz
unfinished but working clk-pwm.c:
/*
* Copyright (c) 2007 Simtec Electronics
* Copyright (c) 2007, 2008 Ben Dooks
* Ben Dooks [off-list ref]
* Copyright (c) 2013 Heiko Stuebner [off-list ref]
*
* 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.
*
* Common Clock Framework support for Samsung pwm clocks
*/
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/syscore_ops.h>
#include <linux/io.h>
#include <plat/cpu.h>
#include <mach/map.h>
#include "clk.h"
/* Each of the timers 0 through 5 go through the following
* clock tree, with the inputs depending on the timers.
*
* pclk ---- [ prescaler 0 ] -+---> timer 0
* +---> timer 1
*
* pclk ---- [ prescaler 1 ] -+---> timer 2
* +---> timer 3
* \---> timer 4
*
* Which are fed into the timers as so:
*
* prescaled 0 ---- [ div 2,4,8,16 ] ---\
* [mux] -> timer 0
* tclk 0 ------------------------------/
*
* prescaled 0 ---- [ div 2,4,8,16 ] ---\
* [mux] -> timer 1
* tclk 0 ------------------------------/
*
*
* prescaled 1 ---- [ div 2,4,8,16 ] ---\
* [mux] -> timer 2
* tclk 1 ------------------------------/
*
* prescaled 1 ---- [ div 2,4,8,16 ] ---\
* [mux] -> timer 3
* tclk 1 ------------------------------/
*
* prescaled 1 ---- [ div 2,4,8, 16 ] --\
* [mux] -> timer 4
* tclk 1 ------------------------------/
*
* Since the mux and the divider are tied together in the
* same register space, it is impossible to set the parent
* and the rate at the same time. To avoid this, we add an
* intermediate 'prescaled-and-divided' clock to select
* as the parent for the timer input clock called tdiv.
*
* prescaled clk --> pwm-tdiv ---\
* [ mux ] --> timer X
* tclk -------------------------/
*/
enum pwm_clks {
none,
tclk0, tclk1, tdiv0, tdiv1, tdiv2, tdiv3, tdiv4,
tin0, tin1, tin2, tin3, tin4,
nr_clks,
};
/* the soc types */
enum supported_socs {
S3C24XX,
S3C64XX, /* also S5PC100 */
S5P64XX,
};
/* clock controller register offsets */
#define TCFG0 0
#define TCFG1 0x4
static DEFINE_SPINLOCK(lock);
static int current_soc;
static void __iomem *reg_base;
static struct clk **clk_table;
#ifdef CONFIG_OF
static struct clk_onecell_data clk_data;
#endif
#ifdef CONFIG_PM_SLEEP
static struct samsung_clk_reg_dump reg_dump[2] = {
{ .offset = TCFG0 },
{ .offset = TCFG1 },
};
static int samsung_clk_pwm_suspend(void)
{
reg_dump[0].value = readl_relaxed(reg_base + reg_dump[0].offset);
reg_dump[1].value = readl_relaxed(reg_base + reg_dump[1].offset);
return 0;
}
static void samsung_clk_pwm_resume(void)
{
writel_relaxed(reg_dump[0].value, reg_base + reg_dump[0].offset);
writel_relaxed(reg_dump[1].value, reg_base + reg_dump[1].offset);
}
static struct syscore_ops samsung_clk_pwm_syscore_ops = {
.suspend = samsung_clk_pwm_suspend,
.resume = samsung_clk_pwm_resume,
};
#endif /* CONFIG_PM_SLEEP */
#define S3C2410_TCFG1_MUX_TCLK (4 << 0)
#define S3C64XX_TCFG1_MUX_TCLK (5 << 0)
/**
* pwm_cfg_src_is_tclk() - return whether the given mux config is a tclk
* @tcfg: The timer TCFG1 register bits shifted down to 0.
*
* Return true if the given configuration from TCFG1 is a TCLK instead
* any of the TDIV clocks.
*/
static inline int pwm_cfg_src_is_tclk(unsigned long tcfg)
{
if (current_soc == S3C24XX)
return tcfg == S3C2410_TCFG1_MUX_TCLK;
else if (current_soc == S3C64XX)
return tcfg >= S3C64XX_TCFG1_MUX_TCLK;
else if (current_soc == S5P64XX)
return 0;
else
return tcfg == S3C64XX_TCFG1_MUX_TCLK;
}
struct clk_tdiv {
struct clk_divider divider;
const struct clk_ops *ops;
void __iomem *reg;
unsigned int divisor;
};
static inline struct clk_tdiv *to_clk_tdiv(struct clk_hw *hw)
{
struct clk_divider *divider = container_of(hw, struct clk_divider,
hw);
return container_of(divider, struct clk_tdiv, divider);
}
static unsigned long clk_tdiv_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_tdiv *tdiv = to_clk_tdiv(hw);
unsigned long tcfg1 = readl_relaxed(tdiv->reg);
tcfg1 >>= tdiv->divider.shift;
tcfg1 &= ((1 << (tdiv->divider.width)) - 1);
if (pwm_cfg_src_is_tclk(tcfg1))
return parent_rate / tdiv->divisor;
else
return tdiv->ops->recalc_rate(&tdiv->divider.hw, parent_rate);
}
static long clk_tdiv_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
struct clk_tdiv *tdiv = to_clk_tdiv(hw);
return tdiv->ops->round_rate(&tdiv->divider.hw, rate, parent_rate);
}
static int clk_tdiv_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_tdiv *tdiv = to_clk_tdiv(hw);
unsigned long tcfg1 = readl_relaxed(tdiv->reg);
unsigned long divisor;
int ret = 0;
tcfg1 >>= tdiv->divider.shift;
tcfg1 &= ((1 << (tdiv->divider.width)) - 1);
rate = tdiv->ops->round_rate(&tdiv->divider.hw, rate, &parent_rate);
divisor = parent_rate / rate;
if (divisor > 16)
return -EINVAL;
tdiv->divisor = divisor;
/* Update the current MUX settings if we are currently
* selected as the clock source for this clock. */
if (!pwm_cfg_src_is_tclk(tcfg1))
ret = tdiv->ops->set_rate(&tdiv->divider.hw, rate,
From: Tomasz Figa <hidden> Date: 2013-03-06 22:57:51
On Wednesday 06 of March 2013 13:34:26 Thierry Reding wrote:
On Wed, Mar 06, 2013 at 10:50:42AM +0000, Arnd Bergmann wrote:
quoted
On Tuesday 05 March 2013, Tomasz Figa wrote:
quoted
On Tuesday 05 of March 2013 19:19:02 Arnd Bergmann wrote:
quoted
If none of these are needed for DT-based systems, we should
probably
build that code conditionally based on the CONFIG_EXYNOS_ATAGS
symbol
I introduced.
Yes, none of them are needed for DT-based systems.
Ah, good. I'll try to make more code conditional then.
quoted
quoted
How are you planning to solve this? Do you want to have a combined
driver that registers both a clocksource and a pwm?
Let's start with a quick introduction to the s3c-pwm hardware. Each
channel has its own timer value, compare and reload value registers,
so
they don't need any extra locking. However there are additional
shared
configuration registers, containing things such as start and reload
bits for all channels, prescaler and main divisor values, etc.
Those registers needs synchronization.
Now there are several possible approaches:
1) A brute force one - two separate drivers, based on the fact that
the
clocksource driver will be used only on uniprocessor systems, so
a simple _irqsave when accessing a shared register in both will
guarantee correct synchronization.
2) Two separate drivers with some synchronized shared code accessing
registers (_start, _stop, _set_reload, _set_prescaler,
_set_divisor,
etc.; all using a shared spinlock).
3) Single driver registering PWM channels, clocksource and clock
event
device. This does not seem like a bad idea, since the whole code
for
configuration of the PWM block would reside in one location and
there
would be no redundancy. However there is a question where such
driver
should be placed - drivers/clocksource, drivers/pwm, or maybe
somewhere
else?
Personally I wanted to go with first option, which would require
least
amount of changes to existing code, at a cost of some code
duplication
(but some PWM code is duplicated already).
I would prefer option 3. That is also easier to implement with a
straightforward DT binding that defines a single node with the clock
registers. The location doesn't have an obvious answer, but I would
probably put them into drivers/clocksource if the PWM maintainer
agrees.
Option 2 would probably come down to having a trivial MFD driver
exposing a regmap. You can probably reuse drivers/mfd/syscon.c for
this and make the node compatible with "syscon" to designate the
clock registers as a system-wide resource, making the other device
nodes register-less.
I think option 2 is the standard method if one hardware block provides
several logical devices. I find it to be a pretty nice solution to this
problem. We also have precedent in the PWM subsystem. The TWL chips for
instance use it to create a platform device which is later driven by a
PWM driver.
I prefer this option over 3), because current driver files could be easily
reused (just cleaned up and moved into appropriate directories), which
would minimize the amount of needed changes.
Another reason for having two separate drivers is that on Exynos SoCs the
PWM block is not used for timers at all, just for PWM outputs, so the
whole part responsible for clocksource would be useless.
Best regards,
Tomasz
Option 2 would probably come down to having a trivial MFD driver exposing
a regmap. You can probably reuse drivers/mfd/syscon.c for this and make
the node compatible with "syscon" to designate the clock registers as
a system-wide resource, making the other device nodes register-less.
I think option 2 is the standard method if one hardware block provides
several logical devices. I find it to be a pretty nice solution to this
problem. We also have precedent in the PWM subsystem. The TWL chips for
instance use it to create a platform device which is later driven by a
PWM driver.
One difference though is that the TWL chip is a heterogenous MFD that has
a lot of different sub-devices, where in case of Exynos the timer device
has a set of identical units, each of which can be used either as a PWM or
as a clocksource or other timer.
Arnd
On Thu, Mar 07, 2013 at 03:02:46AM +0000, Arnd Bergmann wrote:
On Wednesday 06 March 2013, Thierry Reding wrote:
quoted
quoted
Option 2 would probably come down to having a trivial MFD driver exposing
a regmap. You can probably reuse drivers/mfd/syscon.c for this and make
the node compatible with "syscon" to designate the clock registers as
a system-wide resource, making the other device nodes register-less.
I think option 2 is the standard method if one hardware block provides
several logical devices. I find it to be a pretty nice solution to this
problem. We also have precedent in the PWM subsystem. The TWL chips for
instance use it to create a platform device which is later driven by a
PWM driver.
One difference though is that the TWL chip is a heterogenous MFD that has
a lot of different sub-devices, where in case of Exynos the timer device
has a set of identical units, each of which can be used either as a PWM or
as a clocksource or other timer.
I didn't know that. However I still making this an MFD driver is a good
fit because it'll move the logic of defining the mode of each unit is
kept in a parent driver which can instantiate the proper child devices
for the corresponding subsystems.
One big disadvantage of this approach is that if this is continued there
is a risk that MFD will turn into a dump for all kinds of devices that
provide more than a single service.
So if people prefer option 3 I'm fine with it as well.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130307/44a92c5e/attachment.sig>
From: Tomasz Figa <hidden> Date: 2013-03-08 00:40:53
On Thursday 07 of March 2013 08:22:03 Thierry Reding wrote:
On Thu, Mar 07, 2013 at 03:02:46AM +0000, Arnd Bergmann wrote:
quoted
On Wednesday 06 March 2013, Thierry Reding wrote:
quoted
quoted
Option 2 would probably come down to having a trivial MFD driver
exposing a regmap. You can probably reuse drivers/mfd/syscon.c
for this and make the node compatible with "syscon" to designate
the clock registers as a system-wide resource, making the other
device nodes register-less.> >
I think option 2 is the standard method if one hardware block
provides
several logical devices. I find it to be a pretty nice solution to
this
problem. We also have precedent in the PWM subsystem. The TWL chips
for
instance use it to create a platform device which is later driven by
a
PWM driver.
One difference though is that the TWL chip is a heterogenous MFD that
has a lot of different sub-devices, where in case of Exynos the timer
device has a set of identical units, each of which can be used either
as a PWM or as a clocksource or other timer.
I didn't know that. However I still making this an MFD driver is a good
fit because it'll move the logic of defining the mode of each unit is
kept in a parent driver which can instantiate the proper child devices
for the corresponding subsystems.
One big disadvantage of this approach is that if this is continued there
is a risk that MFD will turn into a dump for all kinds of devices that
provide more than a single service.
So if people prefer option 3 I'm fine with it as well.
I have a question regarding making this an MFD driver.
As you know, the main clocksource driver must be initialized early, from
init_time callback of machine_desc. How does using the MFD subsystem fit
into this scheme?
P.S. I'm still not convinced about any benefits of options 2 and 3 over
option 1, which has the obvious advantage of requiring least amount of
changes to existing code and not binding the PWM and clocksource drivers
together (on Exynos SoCs only the PWM driver is used, clocksource is
handled by different hardware block - MCT).
Best regards,
Tomasz
I have a question regarding making this an MFD driver.
As you know, the main clocksource driver must be initialized early, from
init_time callback of machine_desc. How does using the MFD subsystem fit
into this scheme?
P.S. I'm still not convinced about any benefits of options 2 and 3 over
option 1, which has the obvious advantage of requiring least amount of
changes to existing code and not binding the PWM and clocksource drivers
together (on Exynos SoCs only the PWM driver is used, clocksource is
handled by different hardware block - MCT).
I think the main motivation for the MFD here is that you have a shared
register set, which would be described as a single device node in DT
as its natural representation, but it's not easy to have two drivers
be responsible for the same platform device. Similarly, the Linux
resource handling tries hard to ensure that multiple device drivers
do not share a single register set.
If you have an MFD driver, that could bind do the platform_device created
from the DT device node, and provide a simple interface for both the
timer and the pwm driver to talk to, without exposing those registers
directly. Or you could use the syscon regmap approach to expose
those registers in a more controlled way. With syscon, you don't actually
have to write an MFD driver but could just use the one that is already
there.
Since you want the timer driver to be available really early, you could
also make that timer driver the master and expose an interface for
the PWM driver to use.
Arnd
In multiplatform configurations, we cannot include headers
provided by only the exynos platform. Fortunately a number
of drivers that include those headers do not actually need
them, so we can just remove the inclusions.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/media/platform/exynos-gsc/gsc-regs.c | 1 -
drivers/media/platform/s5p-tv/sii9234_drv.c | 3 ---
Cc: linux-media at vger.kernel.org
Thanks Arnd. I have applied this patch to my tree for 3.10.
Am Dienstag, 5. M?rz 2013, 18:42:17 schrieb Arnd Bergmann:
No other file in the kernel besides i2c-s3c2410.c uses
the current plat/regs-iic.h, so we can simply move the
header file to live in the same directory as the driver,
as a preparation to multiplatform builds.