summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap1
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap1')
-rw-r--r--arch/arm/mach-omap1/Kconfig165
-rw-r--r--arch/arm/mach-omap1/Makefile41
-rw-r--r--arch/arm/mach-omap1/ams-delta-fiq-handler.S275
-rw-r--r--arch/arm/mach-omap1/ams-delta-fiq.c227
-rw-r--r--arch/arm/mach-omap1/ams-delta-fiq.h42
-rw-r--r--arch/arm/mach-omap1/board-ams-delta.c855
-rw-r--r--arch/arm/mach-omap1/board-ams-delta.h42
-rw-r--r--arch/arm/mach-omap1/board-nokia770.c351
-rw-r--r--arch/arm/mach-omap1/board-osk.c454
-rw-r--r--arch/arm/mach-omap1/board-palmte.c277
-rw-r--r--arch/arm/mach-omap1/board-sx1-mmc.c62
-rw-r--r--arch/arm/mach-omap1/board-sx1.c371
-rw-r--r--arch/arm/mach-omap1/board-sx1.h45
-rw-r--r--arch/arm/mach-omap1/clock.c840
-rw-r--r--arch/arm/mach-omap1/clock.h195
-rw-r--r--arch/arm/mach-omap1/clock_data.c834
-rw-r--r--arch/arm/mach-omap1/common.h78
-rw-r--r--arch/arm/mach-omap1/devices.c363
-rw-r--r--arch/arm/mach-omap1/dma.c394
-rw-r--r--arch/arm/mach-omap1/fb.c84
-rw-r--r--arch/arm/mach-omap1/flash.c26
-rw-r--r--arch/arm/mach-omap1/flash.h14
-rw-r--r--arch/arm/mach-omap1/gpio15xx.c116
-rw-r--r--arch/arm/mach-omap1/gpio16xx.c251
-rw-r--r--arch/arm/mach-omap1/hardware.h235
-rw-r--r--arch/arm/mach-omap1/i2c.c159
-rw-r--r--arch/arm/mach-omap1/i2c.h36
-rw-r--r--arch/arm/mach-omap1/id.c206
-rw-r--r--arch/arm/mach-omap1/io.c109
-rw-r--r--arch/arm/mach-omap1/iomap.h33
-rw-r--r--arch/arm/mach-omap1/irq.c259
-rw-r--r--arch/arm/mach-omap1/irqs.h240
-rw-r--r--arch/arm/mach-omap1/mcbsp.c345
-rw-r--r--arch/arm/mach-omap1/mmc.h19
-rw-r--r--arch/arm/mach-omap1/mtd-xip.h56
-rw-r--r--arch/arm/mach-omap1/mux.c459
-rw-r--r--arch/arm/mach-omap1/mux.h144
-rw-r--r--arch/arm/mach-omap1/ocpi.c98
-rw-r--r--arch/arm/mach-omap1/omap-dma.c882
-rw-r--r--arch/arm/mach-omap1/opp.h26
-rw-r--r--arch/arm/mach-omap1/opp_data.c51
-rw-r--r--arch/arm/mach-omap1/pm.c644
-rw-r--r--arch/arm/mach-omap1/pm.h241
-rw-r--r--arch/arm/mach-omap1/pm_bus.c42
-rw-r--r--arch/arm/mach-omap1/reset.c63
-rw-r--r--arch/arm/mach-omap1/serial.c246
-rw-r--r--arch/arm/mach-omap1/serial.h48
-rw-r--r--arch/arm/mach-omap1/sleep.S290
-rw-r--r--arch/arm/mach-omap1/soc.h6
-rw-r--r--arch/arm/mach-omap1/sram-init.c145
-rw-r--r--arch/arm/mach-omap1/sram.S58
-rw-r--r--arch/arm/mach-omap1/sram.h10
-rw-r--r--arch/arm/mach-omap1/tc.h74
-rw-r--r--arch/arm/mach-omap1/time.c234
-rw-r--r--arch/arm/mach-omap1/timer.c165
-rw-r--r--arch/arm/mach-omap1/timer32k.c282
-rw-r--r--arch/arm/mach-omap1/usb.c687
-rw-r--r--arch/arm/mach-omap1/usb.h25
58 files changed, 13019 insertions, 0 deletions
diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
new file mode 100644
index 0000000000..cbf703f0d8
--- /dev/null
+++ b/arch/arm/mach-omap1/Kconfig
@@ -0,0 +1,165 @@
+# SPDX-License-Identifier: GPL-2.0-only
+menuconfig ARCH_OMAP1
+ bool "TI OMAP1"
+ depends on ARCH_MULTI_V4T || ARCH_MULTI_V5
+ depends on CPU_LITTLE_ENDIAN
+ depends on ATAGS
+ select ARCH_OMAP
+ select ARCH_HAS_HOLES_MEMORYMODEL
+ select ARCH_OMAP
+ select CLKSRC_MMIO
+ select FORCE_PCI if PCCARD
+ select GPIOLIB
+ help
+ Support for older TI OMAP1 (omap7xx, omap15xx or omap16xx)
+
+if ARCH_OMAP1
+
+menu "TI OMAP1 specific features"
+
+comment "OMAP Core Type"
+
+config ARCH_OMAP15XX
+ depends on ARCH_MULTI_V4T
+ default y
+ bool "OMAP15xx Based System"
+ select CPU_ARM925T
+ select OMAP_MPU_TIMER
+
+config ARCH_OMAP16XX
+ depends on ARCH_MULTI_V5
+ bool "OMAP16xx Based System"
+ select ARCH_OMAP_OTG
+ select CPU_ARM926T
+ select OMAP_DM_TIMER
+
+config ARCH_OMAP
+ bool
+
+comment "OMAP Feature Selections"
+
+config OMAP_MUX
+ bool "OMAP multiplexing support"
+ default y
+ help
+ Pin multiplexing support for OMAP boards. If your bootloader
+ sets the multiplexing correctly, say N. Otherwise, or if unsure,
+ say Y.
+
+config OMAP_MUX_DEBUG
+ bool "Multiplexing debug output"
+ depends on OMAP_MUX
+ help
+ Makes the multiplexing functions print out a lot of debug info.
+ This is useful if you want to find out the correct values of the
+ multiplexing registers.
+
+config OMAP_MUX_WARNINGS
+ bool "Warn about pins the bootloader didn't set up"
+ depends on OMAP_MUX
+ default y
+ help
+ Choose Y here to warn whenever driver initialization logic needs
+ to change the pin multiplexing setup. When there are no warnings
+ printed, it's safe to deselect OMAP_MUX for your product.
+
+config OMAP_32K_TIMER
+ bool "Use 32KHz timer"
+ depends on ARCH_OMAP16XX
+ default ARCH_OMAP16XX
+ help
+ Select this option if you want to enable the OMAP 32KHz timer.
+ This timer saves power compared to the OMAP_MPU_TIMER, and has
+ support for no tick during idle. The 32KHz timer provides less
+ intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
+ currently only available for OMAP16XX, 24XX, 34XX, OMAP4/5 and DRA7XX.
+
+ On OMAP2PLUS this value is only used for CONFIG_HZ and
+ CLOCK_TICK_RATE compile time calculation.
+ The actual timer selection is done in the board file
+ through the (DT_)MACHINE_START structure.
+
+config OMAP_MPU_TIMER
+ bool "Use mpu timer"
+ depends on ARCH_OMAP1
+ help
+ Select this option if you want to use the OMAP mpu timer. This
+ timer provides more intra-tick resolution than the 32KHz timer,
+ but consumes more power.
+
+config OMAP_SERIAL_WAKE
+ bool "Enable wake-up events for serial ports"
+ depends on ARCH_OMAP1 && OMAP_MUX
+ default y
+ help
+ Select this option if you want to have your system wake up
+ to data on the serial RX line. This allows you to wake the
+ system from serial console.
+
+config OMAP_RESET_CLOCKS
+ bool "Reset unused clocks during boot"
+ depends on ARCH_OMAP
+ help
+ Say Y if you want to reset unused clocks during boot.
+ This option saves power, but assumes all drivers are
+ using the clock framework. Broken drivers that do not
+ yet use clock framework may not work with this option.
+ If you are booting from another operating system, you
+ probably do not want this option enabled until your
+ device drivers work properly.
+
+config ARCH_OMAP_OTG
+ bool
+
+comment "OMAP Board Type"
+
+config MACH_OMAP_OSK
+ bool "TI OSK Support"
+ depends on ARCH_OMAP16XX
+ help
+ TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here
+ if you have such a board.
+
+config MACH_OMAP_PALMTE
+ bool "Palm Tungsten E"
+ depends on ARCH_OMAP15XX
+ help
+ Support for the Palm Tungsten E PDA. To boot the kernel, you'll
+ need a PalmOS compatible bootloader; check out
+ http://palmtelinux.sourceforge.net/ for more information.
+ Say Y here if you have this PDA model, say N otherwise.
+
+config MACH_SX1
+ bool "Siemens SX1"
+ depends on ARCH_OMAP15XX
+ select I2C
+ help
+ Support for the Siemens SX1 phone. To boot the kernel,
+ you'll need a SX1 compatible bootloader; check out
+ http://forum.oslik.ru and
+ https://www.handhelds.org/moin/moin.cgi/SiemensSX1
+ for more information.
+ Say Y here if you have such a phone, say NO otherwise.
+
+config MACH_NOKIA770
+ bool "Nokia 770"
+ depends on ARCH_OMAP16XX
+ help
+ Support for the Nokia 770 Internet Tablet. Say Y here if you
+ have such a device.
+
+config MACH_AMS_DELTA
+ bool "Amstrad E3 (Delta)"
+ depends on ARCH_OMAP15XX
+ select FIQ
+ select GPIO_GENERIC_PLATFORM
+ select LEDS_GPIO_REGISTER
+ select REGULATOR
+ select REGULATOR_FIXED_VOLTAGE
+ help
+ Support for the Amstrad E3 (codename Delta) videophone. Say Y here
+ if you have such a device.
+
+endmenu
+
+endif
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
new file mode 100644
index 0000000000..d9e251ea47
--- /dev/null
+++ b/arch/arm/mach-omap1/Makefile
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the linux kernel.
+#
+
+# Common support
+obj-y := io.o id.o sram-init.o sram.o time.o irq.o mux.o flash.o \
+ serial.o devices.o dma.o omap-dma.o fb.o
+obj-y += clock.o clock_data.o opp_data.o reset.o pm_bus.o timer.o
+
+ifneq ($(CONFIG_SND_SOC_OMAP_MCBSP),)
+obj-y += mcbsp.o
+endif
+
+obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o
+
+# OCPI interconnect support for 1710, 1610 and 5912
+obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
+
+# Power Management
+obj-$(CONFIG_PM) += pm.o sleep.o
+
+i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o
+obj-y += $(i2c-omap-m) $(i2c-omap-y)
+
+led-y := leds.o
+
+usb-fs-$(CONFIG_USB_SUPPORT) := usb.o
+obj-y += $(usb-fs-m) $(usb-fs-y)
+
+# Specific board support
+obj-$(CONFIG_MACH_OMAP_OSK) += board-osk.o
+obj-$(CONFIG_MACH_OMAP_PALMTE) += board-palmte.o
+obj-$(CONFIG_MACH_NOKIA770) += board-nokia770.o
+obj-$(CONFIG_MACH_AMS_DELTA) += board-ams-delta.o ams-delta-fiq.o \
+ ams-delta-fiq-handler.o
+obj-$(CONFIG_MACH_SX1) += board-sx1.o board-sx1-mmc.o
+
+# GPIO
+obj-$(CONFIG_ARCH_OMAP15XX) += gpio15xx.o
+obj-$(CONFIG_ARCH_OMAP16XX) += gpio16xx.o
diff --git a/arch/arm/mach-omap1/ams-delta-fiq-handler.S b/arch/arm/mach-omap1/ams-delta-fiq-handler.S
new file mode 100644
index 0000000000..35c2f9574d
--- /dev/null
+++ b/arch/arm/mach-omap1/ams-delta-fiq-handler.S
@@ -0,0 +1,275 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * linux/arch/arm/mach-omap1/ams-delta-fiq-handler.S
+ *
+ * Based on linux/arch/arm/lib/floppydma.S
+ * Renamed and modified to work with 2.6 kernel by Matt Callow
+ * Copyright (C) 1995, 1996 Russell King
+ * Copyright (C) 2004 Pete Trapps
+ * Copyright (C) 2006 Matt Callow
+ * Copyright (C) 2010 Janusz Krzysztofik
+ */
+
+#include <linux/linkage.h>
+#include <linux/platform_data/ams-delta-fiq.h>
+#include <linux/platform_data/gpio-omap.h>
+#include <linux/soc/ti/omap1-io.h>
+
+#include <asm/assembler.h>
+#include <asm/irq.h>
+
+#include "hardware.h"
+#include "ams-delta-fiq.h"
+#include "board-ams-delta.h"
+#include "iomap.h"
+
+/*
+ * OMAP1510 GPIO related symbol copied from arch/arm/mach-omap1/gpio15xx.c.
+ * Unfortunately, it was not placed in a separate header file.
+ */
+#define OMAP1510_GPIO_BASE 0xFFFCE000
+
+/* GPIO register bitmasks */
+#define KEYBRD_DATA_MASK (0x1 << AMS_DELTA_GPIO_PIN_KEYBRD_DATA)
+#define KEYBRD_CLK_MASK (0x1 << AMS_DELTA_GPIO_PIN_KEYBRD_CLK)
+#define MODEM_IRQ_MASK (0x1 << AMS_DELTA_GPIO_PIN_MODEM_IRQ)
+#define HOOK_SWITCH_MASK (0x1 << AMS_DELTA_GPIO_PIN_HOOK_SWITCH)
+#define OTHERS_MASK (MODEM_IRQ_MASK | HOOK_SWITCH_MASK)
+
+/* IRQ handler register bitmasks */
+#define DEFERRED_FIQ_MASK OMAP_IRQ_BIT(INT_DEFERRED_FIQ)
+#define GPIO_BANK1_MASK OMAP_IRQ_BIT(INT_GPIO_BANK1)
+
+/* Driver buffer byte offsets */
+#define BUF_MASK (FIQ_MASK * 4)
+#define BUF_STATE (FIQ_STATE * 4)
+#define BUF_KEYS_CNT (FIQ_KEYS_CNT * 4)
+#define BUF_TAIL_OFFSET (FIQ_TAIL_OFFSET * 4)
+#define BUF_HEAD_OFFSET (FIQ_HEAD_OFFSET * 4)
+#define BUF_BUF_LEN (FIQ_BUF_LEN * 4)
+#define BUF_KEY (FIQ_KEY * 4)
+#define BUF_MISSED_KEYS (FIQ_MISSED_KEYS * 4)
+#define BUF_BUFFER_START (FIQ_BUFFER_START * 4)
+#define BUF_GPIO_INT_MASK (FIQ_GPIO_INT_MASK * 4)
+#define BUF_KEYS_HICNT (FIQ_KEYS_HICNT * 4)
+#define BUF_IRQ_PEND (FIQ_IRQ_PEND * 4)
+#define BUF_SIR_CODE_L1 (FIQ_SIR_CODE_L1 * 4)
+#define BUF_SIR_CODE_L2 (IRQ_SIR_CODE_L2 * 4)
+#define BUF_CNT_INT_00 (FIQ_CNT_INT_00 * 4)
+#define BUF_CNT_INT_KEY (FIQ_CNT_INT_KEY * 4)
+#define BUF_CNT_INT_MDM (FIQ_CNT_INT_MDM * 4)
+#define BUF_CNT_INT_03 (FIQ_CNT_INT_03 * 4)
+#define BUF_CNT_INT_HSW (FIQ_CNT_INT_HSW * 4)
+#define BUF_CNT_INT_05 (FIQ_CNT_INT_05 * 4)
+#define BUF_CNT_INT_06 (FIQ_CNT_INT_06 * 4)
+#define BUF_CNT_INT_07 (FIQ_CNT_INT_07 * 4)
+#define BUF_CNT_INT_08 (FIQ_CNT_INT_08 * 4)
+#define BUF_CNT_INT_09 (FIQ_CNT_INT_09 * 4)
+#define BUF_CNT_INT_10 (FIQ_CNT_INT_10 * 4)
+#define BUF_CNT_INT_11 (FIQ_CNT_INT_11 * 4)
+#define BUF_CNT_INT_12 (FIQ_CNT_INT_12 * 4)
+#define BUF_CNT_INT_13 (FIQ_CNT_INT_13 * 4)
+#define BUF_CNT_INT_14 (FIQ_CNT_INT_14 * 4)
+#define BUF_CNT_INT_15 (FIQ_CNT_INT_15 * 4)
+#define BUF_CIRC_BUFF (FIQ_CIRC_BUFF * 4)
+
+
+/*
+ * Register usage
+ * r8 - temporary
+ * r9 - the driver buffer
+ * r10 - temporary
+ * r11 - interrupts mask
+ * r12 - base pointers
+ * r13 - interrupts status
+ */
+
+ .text
+
+ .global qwerty_fiqin_end
+
+ENTRY(qwerty_fiqin_start)
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ @ FIQ intrrupt handler
+ ldr r12, omap_ih1_base @ set pointer to level1 handler
+
+ ldr r11, [r12, #IRQ_MIR_REG_OFFSET] @ fetch interrupts mask
+
+ ldr r13, [r12, #IRQ_ITR_REG_OFFSET] @ fetch interrupts status
+ bics r13, r13, r11 @ clear masked - any left?
+ beq exit @ none - spurious FIQ? exit
+
+ ldr r10, [r12, #IRQ_SIR_FIQ_REG_OFFSET] @ get requested interrupt number
+
+ mov r8, #2 @ reset FIQ agreement
+ str r8, [r12, #IRQ_CONTROL_REG_OFFSET]
+
+ cmp r10, #(INT_GPIO_BANK1 - NR_IRQS_LEGACY) @ is it GPIO interrupt?
+ beq gpio @ yes - process it
+
+ mov r8, #1
+ orr r8, r11, r8, lsl r10 @ mask spurious interrupt
+ str r8, [r12, #IRQ_MIR_REG_OFFSET]
+exit:
+ subs pc, lr, #4 @ return from FIQ
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
+
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@
+gpio: @ GPIO bank interrupt handler
+ ldr r12, omap1510_gpio_base @ set base pointer to GPIO bank
+
+ ldr r11, [r12, #OMAP1510_GPIO_INT_MASK] @ fetch GPIO interrupts mask
+restart:
+ ldr r13, [r12, #OMAP1510_GPIO_INT_STATUS] @ fetch status bits
+ bics r13, r13, r11 @ clear masked - any left?
+ beq exit @ no - spurious interrupt? exit
+
+ orr r11, r11, r13 @ mask all requested interrupts
+ str r11, [r12, #OMAP1510_GPIO_INT_MASK]
+
+ str r13, [r12, #OMAP1510_GPIO_INT_STATUS] @ ack all requested interrupts
+
+ ands r10, r13, #KEYBRD_CLK_MASK @ extract keyboard status - set?
+ beq hksw @ no - try next source
+
+
+ @@@@@@@@@@@@@@@@@@@@@@
+ @ Keyboard clock FIQ mode interrupt handler
+ @ r10 now contains KEYBRD_CLK_MASK, use it
+ bic r11, r11, r10 @ unmask it
+ str r11, [r12, #OMAP1510_GPIO_INT_MASK]
+
+ @ Process keyboard data
+ ldr r8, [r12, #OMAP1510_GPIO_DATA_INPUT] @ fetch GPIO input
+
+ ldr r10, [r9, #BUF_STATE] @ fetch kbd interface state
+ cmp r10, #0 @ are we expecting start bit?
+ bne data @ no - go to data processing
+
+ ands r8, r8, #KEYBRD_DATA_MASK @ check start bit - detected?
+ beq hksw @ no - try next source
+
+ @ r8 contains KEYBRD_DATA_MASK, use it
+ str r8, [r9, #BUF_STATE] @ enter data processing state
+ @ r10 already contains 0, reuse it
+ str r10, [r9, #BUF_KEY] @ clear keycode
+ mov r10, #2 @ reset input bit mask
+ str r10, [r9, #BUF_MASK]
+
+ @ Mask other GPIO line interrupts till key done
+ str r11, [r9, #BUF_GPIO_INT_MASK] @ save mask for later restore
+ mvn r11, #KEYBRD_CLK_MASK @ prepare all except kbd mask
+ str r11, [r12, #OMAP1510_GPIO_INT_MASK] @ store into the mask register
+
+ b restart @ restart
+
+data: ldr r10, [r9, #BUF_MASK] @ fetch current input bit mask
+
+ @ r8 still contains GPIO input bits
+ ands r8, r8, #KEYBRD_DATA_MASK @ is keyboard data line low?
+ ldreq r8, [r9, #BUF_KEY] @ yes - fetch collected so far,
+ orreq r8, r8, r10 @ set 1 at current mask position
+ streq r8, [r9, #BUF_KEY] @ and save back
+
+ mov r10, r10, lsl #1 @ shift mask left
+ bics r10, r10, #0x800 @ have we got all the bits?
+ strne r10, [r9, #BUF_MASK] @ not yet - store the mask
+ bne restart @ and restart
+
+ @ r10 already contains 0, reuse it
+ str r10, [r9, #BUF_STATE] @ reset state to start
+
+ @ Key done - restore interrupt mask
+ ldr r10, [r9, #BUF_GPIO_INT_MASK] @ fetch saved mask
+ and r11, r11, r10 @ unmask all saved as unmasked
+ str r11, [r12, #OMAP1510_GPIO_INT_MASK] @ restore into the mask register
+
+ @ Try appending the keycode to the circular buffer
+ ldr r10, [r9, #BUF_KEYS_CNT] @ get saved keystrokes count
+ ldr r8, [r9, #BUF_BUF_LEN] @ get buffer size
+ cmp r10, r8 @ is buffer full?
+ beq hksw @ yes - key lost, next source
+
+ add r10, r10, #1 @ incremet keystrokes counter
+ str r10, [r9, #BUF_KEYS_CNT]
+
+ ldr r10, [r9, #BUF_TAIL_OFFSET] @ get buffer tail offset
+ @ r8 already contains buffer size
+ cmp r10, r8 @ end of buffer?
+ moveq r10, #0 @ yes - rewind to buffer start
+
+ ldr r12, [r9, #BUF_BUFFER_START] @ get buffer start address
+ add r12, r12, r10, LSL #2 @ calculate buffer tail address
+ ldr r8, [r9, #BUF_KEY] @ get last keycode
+ str r8, [r12] @ append it to the buffer tail
+
+ add r10, r10, #1 @ increment buffer tail offset
+ str r10, [r9, #BUF_TAIL_OFFSET]
+
+ ldr r10, [r9, #BUF_CNT_INT_KEY] @ increment interrupts counter
+ add r10, r10, #1
+ str r10, [r9, #BUF_CNT_INT_KEY]
+ @@@@@@@@@@@@@@@@@@@@@@@@
+
+
+hksw: @Is hook switch interrupt requested?
+ tst r13, #HOOK_SWITCH_MASK @ is hook switch status bit set?
+ beq mdm @ no - try next source
+
+
+ @@@@@@@@@@@@@@@@@@@@@@@@
+ @ Hook switch interrupt FIQ mode simple handler
+
+ @ Don't toggle active edge, the switch always bounces
+
+ @ Increment hook switch interrupt counter
+ ldr r10, [r9, #BUF_CNT_INT_HSW]
+ add r10, r10, #1
+ str r10, [r9, #BUF_CNT_INT_HSW]
+ @@@@@@@@@@@@@@@@@@@@@@@@
+
+
+mdm: @Is it a modem interrupt?
+ tst r13, #MODEM_IRQ_MASK @ is modem status bit set?
+ beq irq @ no - check for next interrupt
+
+
+ @@@@@@@@@@@@@@@@@@@@@@@@
+ @ Modem FIQ mode interrupt handler stub
+
+ @ Increment modem interrupt counter
+ ldr r10, [r9, #BUF_CNT_INT_MDM]
+ add r10, r10, #1
+ str r10, [r9, #BUF_CNT_INT_MDM]
+ @@@@@@@@@@@@@@@@@@@@@@@@
+
+
+irq: @ Place deferred_fiq interrupt request
+ ldr r12, deferred_fiq_ih_base @ set pointer to IRQ handler
+ mov r10, #DEFERRED_FIQ_MASK @ set deferred_fiq bit
+ str r10, [r12, #IRQ_ISR_REG_OFFSET] @ place it in the ISR register
+
+ ldr r12, omap1510_gpio_base @ set pointer back to GPIO bank
+ b restart @ check for next GPIO interrupt
+ @@@@@@@@@@@@@@@@@@@@@@@@@@@
+
+
+/*
+ * Virtual addresses for IO
+ */
+omap_ih1_base:
+ .word OMAP1_IO_ADDRESS(OMAP_IH1_BASE)
+deferred_fiq_ih_base:
+ .word OMAP1_IO_ADDRESS(DEFERRED_FIQ_IH_BASE)
+omap1510_gpio_base:
+ .word OMAP1_IO_ADDRESS(OMAP1510_GPIO_BASE)
+qwerty_fiqin_end:
+
+/*
+ * Check the size of the FIQ,
+ * it cannot go beyond 0xffff0200, and is copied to 0xffff001c
+ */
+.if (qwerty_fiqin_end - qwerty_fiqin_start) > (0x200 - 0x1c)
+ .err
+.endif
diff --git a/arch/arm/mach-omap1/ams-delta-fiq.c b/arch/arm/mach-omap1/ams-delta-fiq.c
new file mode 100644
index 0000000000..1f5852be05
--- /dev/null
+++ b/arch/arm/mach-omap1/ams-delta-fiq.c
@@ -0,0 +1,227 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Amstrad E3 FIQ handling
+ *
+ * Copyright (C) 2009 Janusz Krzysztofik
+ * Copyright (c) 2006 Matt Callow
+ * Copyright (c) 2004 Amstrad Plc
+ * Copyright (C) 2001 RidgeRun, Inc.
+ *
+ * Parts of this code are taken from linux/arch/arm/mach-omap/irq.c
+ * in the MontaVista 2.4 kernel (and the Amstrad changes therein)
+ */
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/platform_data/ams-delta-fiq.h>
+#include <linux/platform_device.h>
+
+#include <asm/fiq.h>
+#include <linux/soc/ti/omap1-io.h>
+
+#include "hardware.h"
+#include "ams-delta-fiq.h"
+#include "board-ams-delta.h"
+
+static struct fiq_handler fh = {
+ .name = "ams-delta-fiq"
+};
+
+/*
+ * This buffer is shared between FIQ and IRQ contexts.
+ * The FIQ and IRQ isrs can both read and write it.
+ * It is structured as a header section several 32bit slots,
+ * followed by the circular buffer where the FIQ isr stores
+ * keystrokes received from the qwerty keyboard. See
+ * <linux/platform_data/ams-delta-fiq.h> for details of offsets.
+ */
+static unsigned int fiq_buffer[1024];
+
+static struct irq_chip *irq_chip;
+static struct irq_data *irq_data[16];
+static unsigned int irq_counter[16];
+
+static const char *pin_name[16] __initconst = {
+ [AMS_DELTA_GPIO_PIN_KEYBRD_DATA] = "keybrd_data",
+ [AMS_DELTA_GPIO_PIN_KEYBRD_CLK] = "keybrd_clk",
+};
+
+static irqreturn_t deferred_fiq(int irq, void *dev_id)
+{
+ struct irq_data *d;
+ int gpio, irq_num, fiq_count;
+
+ /*
+ * For each handled GPIO interrupt, keep calling its interrupt handler
+ * until the IRQ counter catches the FIQ incremented interrupt counter.
+ */
+ for (gpio = AMS_DELTA_GPIO_PIN_KEYBRD_CLK;
+ gpio <= AMS_DELTA_GPIO_PIN_HOOK_SWITCH; gpio++) {
+ d = irq_data[gpio];
+ irq_num = d->irq;
+ fiq_count = fiq_buffer[FIQ_CNT_INT_00 + gpio];
+
+ if (irq_counter[gpio] < fiq_count &&
+ gpio != AMS_DELTA_GPIO_PIN_KEYBRD_CLK) {
+ /*
+ * handle_simple_irq() that OMAP GPIO edge
+ * interrupts default to since commit 80ac93c27441
+ * requires interrupt already acked and unmasked.
+ */
+ if (!WARN_ON_ONCE(!irq_chip->irq_unmask))
+ irq_chip->irq_unmask(d);
+ }
+ for (; irq_counter[gpio] < fiq_count; irq_counter[gpio]++)
+ generic_handle_irq(irq_num);
+ }
+ return IRQ_HANDLED;
+}
+
+void __init ams_delta_init_fiq(struct gpio_chip *chip,
+ struct platform_device *serio)
+{
+ struct gpio_desc *gpiod, *data = NULL, *clk = NULL;
+ void *fiqhandler_start;
+ unsigned int fiqhandler_length;
+ struct pt_regs FIQ_regs;
+ unsigned long val, offset;
+ int i, retval;
+
+ /* Store irq_chip location for IRQ handler use */
+ irq_chip = chip->irq.chip;
+ if (!irq_chip) {
+ pr_err("%s: GPIO chip %s is missing IRQ function\n", __func__,
+ chip->label);
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(irq_data); i++) {
+ gpiod = gpiochip_request_own_desc(chip, i, pin_name[i],
+ GPIO_ACTIVE_HIGH, GPIOD_IN);
+ if (IS_ERR(gpiod)) {
+ pr_err("%s: failed to get GPIO pin %d (%ld)\n",
+ __func__, i, PTR_ERR(gpiod));
+ return;
+ }
+ /* Store irq_data location for IRQ handler use */
+ irq_data[i] = irq_get_irq_data(gpiod_to_irq(gpiod));
+
+ /*
+ * FIQ handler takes full control over serio data and clk GPIO
+ * pins. Initialize them and keep requested so nobody can
+ * interfere. Fail if any of those two couldn't be requested.
+ */
+ switch (i) {
+ case AMS_DELTA_GPIO_PIN_KEYBRD_DATA:
+ data = gpiod;
+ gpiod_direction_input(data);
+ break;
+ case AMS_DELTA_GPIO_PIN_KEYBRD_CLK:
+ clk = gpiod;
+ gpiod_direction_input(clk);
+ break;
+ default:
+ gpiochip_free_own_desc(gpiod);
+ break;
+ }
+ }
+ if (!data || !clk)
+ goto out_gpio;
+
+ fiqhandler_start = &qwerty_fiqin_start;
+ fiqhandler_length = &qwerty_fiqin_end - &qwerty_fiqin_start;
+ pr_info("Installing fiq handler from %p, length 0x%x\n",
+ fiqhandler_start, fiqhandler_length);
+
+ retval = claim_fiq(&fh);
+ if (retval) {
+ pr_err("ams_delta_init_fiq(): couldn't claim FIQ, ret=%d\n",
+ retval);
+ goto out_gpio;
+ }
+
+ retval = request_irq(INT_DEFERRED_FIQ, deferred_fiq,
+ IRQ_TYPE_EDGE_RISING, "deferred_fiq", NULL);
+ if (retval < 0) {
+ pr_err("Failed to get deferred_fiq IRQ, ret=%d\n", retval);
+ release_fiq(&fh);
+ goto out_gpio;
+ }
+ /*
+ * Since no set_type() method is provided by OMAP irq chip,
+ * switch to edge triggered interrupt type manually.
+ */
+ offset = IRQ_ILR0_REG_OFFSET +
+ ((INT_DEFERRED_FIQ - NR_IRQS_LEGACY) & 0x1f) * 0x4;
+ val = omap_readl(DEFERRED_FIQ_IH_BASE + offset) & ~(1 << 1);
+ omap_writel(val, DEFERRED_FIQ_IH_BASE + offset);
+
+ set_fiq_handler(fiqhandler_start, fiqhandler_length);
+
+ /*
+ * Initialise the buffer which is shared
+ * between FIQ mode and IRQ mode
+ */
+ fiq_buffer[FIQ_GPIO_INT_MASK] = 0;
+ fiq_buffer[FIQ_MASK] = 0;
+ fiq_buffer[FIQ_STATE] = 0;
+ fiq_buffer[FIQ_KEY] = 0;
+ fiq_buffer[FIQ_KEYS_CNT] = 0;
+ fiq_buffer[FIQ_KEYS_HICNT] = 0;
+ fiq_buffer[FIQ_TAIL_OFFSET] = 0;
+ fiq_buffer[FIQ_HEAD_OFFSET] = 0;
+ fiq_buffer[FIQ_BUF_LEN] = 256;
+ fiq_buffer[FIQ_MISSED_KEYS] = 0;
+ fiq_buffer[FIQ_BUFFER_START] =
+ (unsigned int) &fiq_buffer[FIQ_CIRC_BUFF];
+
+ for (i = FIQ_CNT_INT_00; i <= FIQ_CNT_INT_15; i++)
+ fiq_buffer[i] = 0;
+
+ /*
+ * FIQ mode r9 always points to the fiq_buffer, because the FIQ isr
+ * will run in an unpredictable context. The fiq_buffer is the FIQ isr's
+ * only means of communication with the IRQ level and other kernel
+ * context code.
+ */
+ FIQ_regs.ARM_r9 = (unsigned int)fiq_buffer;
+ set_fiq_regs(&FIQ_regs);
+
+ pr_info("request_fiq(): fiq_buffer = %p\n", fiq_buffer);
+
+ /*
+ * Redirect GPIO interrupts to FIQ
+ */
+ offset = IRQ_ILR0_REG_OFFSET + (INT_GPIO_BANK1 - NR_IRQS_LEGACY) * 0x4;
+ val = omap_readl(OMAP_IH1_BASE + offset) | 1;
+ omap_writel(val, OMAP_IH1_BASE + offset);
+
+ /* Initialize serio device IRQ resource and platform_data */
+ serio->resource[0].start = gpiod_to_irq(clk);
+ serio->resource[0].end = serio->resource[0].start;
+ serio->dev.platform_data = fiq_buffer;
+
+ /*
+ * Since FIQ handler performs handling of GPIO registers for
+ * "keybrd_clk" IRQ pin, ams_delta_serio driver used to set
+ * handle_simple_irq() as active IRQ handler for that pin to avoid
+ * bad interaction with gpio-omap driver. This is no longer needed
+ * as handle_simple_irq() is now the default handler for OMAP GPIO
+ * edge interrupts.
+ * This comment replaces the obsolete code which has been removed
+ * from the ams_delta_serio driver and stands here only as a reminder
+ * of that dependency on gpio-omap driver behavior.
+ */
+
+ return;
+
+out_gpio:
+ if (data)
+ gpiochip_free_own_desc(data);
+ if (clk)
+ gpiochip_free_own_desc(clk);
+}
diff --git a/arch/arm/mach-omap1/ams-delta-fiq.h b/arch/arm/mach-omap1/ams-delta-fiq.h
new file mode 100644
index 0000000000..7f843caedb
--- /dev/null
+++ b/arch/arm/mach-omap1/ams-delta-fiq.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * arch/arm/mach-omap1/ams-delta-fiq.h
+ *
+ * Taken from the original Amstrad modifications to fiq.h
+ *
+ * Copyright (c) 2004 Amstrad Plc
+ * Copyright (c) 2006 Matt Callow
+ * Copyright (c) 2010 Janusz Krzysztofik
+ *
+ * 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.
+ */
+#ifndef __AMS_DELTA_FIQ_H
+#define __AMS_DELTA_FIQ_H
+
+#include "irqs.h"
+
+/*
+ * Interrupt number used for passing control from FIQ to IRQ.
+ * IRQ12, described as reserved, has been selected.
+ */
+#define INT_DEFERRED_FIQ INT_1510_RES12
+/*
+ * Base address of an interrupt handler that the INT_DEFERRED_FIQ belongs to.
+ */
+#if (INT_DEFERRED_FIQ < IH2_BASE)
+#define DEFERRED_FIQ_IH_BASE OMAP_IH1_BASE
+#else
+#define DEFERRED_FIQ_IH_BASE OMAP_IH2_BASE
+#endif
+
+#ifndef __ASSEMBLER__
+extern unsigned char qwerty_fiqin_start, qwerty_fiqin_end;
+
+extern void __init ams_delta_init_fiq(struct gpio_chip *chip,
+ struct platform_device *pdev);
+#endif
+
+#endif
diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c
new file mode 100644
index 0000000000..67de96c771
--- /dev/null
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -0,0 +1,855 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * linux/arch/arm/mach-omap1/board-ams-delta.c
+ *
+ * Modified from board-generic.c
+ *
+ * Board specific inits for the Amstrad E3 (codename Delta) videophone
+ *
+ * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
+ */
+#include <linux/gpio/driver.h>
+#include <linux/gpio/machine.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/leds.h>
+#include <linux/mtd/nand-gpio.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
+#include <linux/serial_8250.h>
+#include <linux/export.h>
+#include <linux/omapfb.h>
+#include <linux/io.h>
+#include <linux/platform_data/gpio-omap.h>
+#include <linux/soc/ti/omap1-mux.h>
+
+#include <asm/serial.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <linux/platform_data/keypad-omap.h>
+
+#include "hardware.h"
+#include "usb.h"
+#include "ams-delta-fiq.h"
+#include "board-ams-delta.h"
+#include "iomap.h"
+#include "common.h"
+
+static const unsigned int ams_delta_keymap[] = {
+ KEY(0, 0, KEY_F1), /* Advert */
+
+ KEY(0, 3, KEY_COFFEE), /* Games */
+ KEY(0, 2, KEY_QUESTION), /* Directory */
+ KEY(2, 3, KEY_CONNECT), /* Internet */
+ KEY(1, 2, KEY_SHOP), /* Services */
+ KEY(1, 1, KEY_PHONE), /* VoiceMail */
+
+ KEY(0, 1, KEY_DELETE), /* Delete */
+ KEY(2, 2, KEY_PLAY), /* Play */
+ KEY(1, 0, KEY_PAGEUP), /* Up */
+ KEY(1, 3, KEY_PAGEDOWN), /* Down */
+ KEY(2, 0, KEY_EMAIL), /* ReadEmail */
+ KEY(2, 1, KEY_STOP), /* Stop */
+
+ /* Numeric keypad portion */
+ KEY(0, 7, KEY_KP1),
+ KEY(0, 6, KEY_KP2),
+ KEY(0, 5, KEY_KP3),
+ KEY(1, 7, KEY_KP4),
+ KEY(1, 6, KEY_KP5),
+ KEY(1, 5, KEY_KP6),
+ KEY(2, 7, KEY_KP7),
+ KEY(2, 6, KEY_KP8),
+ KEY(2, 5, KEY_KP9),
+ KEY(3, 6, KEY_KP0),
+ KEY(3, 7, KEY_KPASTERISK),
+ KEY(3, 5, KEY_KPDOT), /* # key */
+ KEY(7, 2, KEY_NUMLOCK), /* Mute */
+ KEY(7, 1, KEY_KPMINUS), /* Recall */
+ KEY(6, 1, KEY_KPPLUS), /* Redial */
+ KEY(7, 6, KEY_KPSLASH), /* Handsfree */
+ KEY(6, 0, KEY_ENTER), /* Video */
+
+ KEY(7, 4, KEY_CAMERA), /* Photo */
+
+ KEY(0, 4, KEY_F2), /* Home */
+ KEY(1, 4, KEY_F3), /* Office */
+ KEY(2, 4, KEY_F4), /* Mobile */
+ KEY(7, 7, KEY_F5), /* SMS */
+ KEY(7, 5, KEY_F6), /* Email */
+
+ /* QWERTY portion of keypad */
+ KEY(3, 4, KEY_Q),
+ KEY(3, 3, KEY_W),
+ KEY(3, 2, KEY_E),
+ KEY(3, 1, KEY_R),
+ KEY(3, 0, KEY_T),
+ KEY(4, 7, KEY_Y),
+ KEY(4, 6, KEY_U),
+ KEY(4, 5, KEY_I),
+ KEY(4, 4, KEY_O),
+ KEY(4, 3, KEY_P),
+
+ KEY(4, 2, KEY_A),
+ KEY(4, 1, KEY_S),
+ KEY(4, 0, KEY_D),
+ KEY(5, 7, KEY_F),
+ KEY(5, 6, KEY_G),
+ KEY(5, 5, KEY_H),
+ KEY(5, 4, KEY_J),
+ KEY(5, 3, KEY_K),
+ KEY(5, 2, KEY_L),
+
+ KEY(5, 1, KEY_Z),
+ KEY(5, 0, KEY_X),
+ KEY(6, 7, KEY_C),
+ KEY(6, 6, KEY_V),
+ KEY(6, 5, KEY_B),
+ KEY(6, 4, KEY_N),
+ KEY(6, 3, KEY_M),
+ KEY(6, 2, KEY_SPACE),
+
+ KEY(7, 0, KEY_LEFTSHIFT), /* Vol up */
+ KEY(7, 3, KEY_LEFTCTRL), /* Vol down */
+};
+
+#define LATCH1_PHYS 0x01000000
+#define LATCH1_VIRT 0xEA000000
+#define MODEM_PHYS 0x04000000
+#define MODEM_VIRT 0xEB000000
+#define LATCH2_PHYS 0x08000000
+#define LATCH2_VIRT 0xEC000000
+
+static struct map_desc ams_delta_io_desc[] __initdata = {
+ /* AMS_DELTA_LATCH1 */
+ {
+ .virtual = LATCH1_VIRT,
+ .pfn = __phys_to_pfn(LATCH1_PHYS),
+ .length = 0x01000000,
+ .type = MT_DEVICE
+ },
+ /* AMS_DELTA_LATCH2 */
+ {
+ .virtual = LATCH2_VIRT,
+ .pfn = __phys_to_pfn(LATCH2_PHYS),
+ .length = 0x01000000,
+ .type = MT_DEVICE
+ },
+ /* AMS_DELTA_MODEM */
+ {
+ .virtual = MODEM_VIRT,
+ .pfn = __phys_to_pfn(MODEM_PHYS),
+ .length = 0x01000000,
+ .type = MT_DEVICE
+ }
+};
+
+static const struct omap_lcd_config ams_delta_lcd_config __initconst = {
+ .ctrl_name = "internal",
+};
+
+static struct omap_usb_config ams_delta_usb_config __initdata = {
+ .register_host = 1,
+ .hmc_mode = 16,
+ .pins[0] = 2,
+};
+
+#define LATCH1_NGPIO 8
+
+static struct resource latch1_resources[] = {
+ [0] = {
+ .name = "dat",
+ .start = LATCH1_PHYS,
+ .end = LATCH1_PHYS + (LATCH1_NGPIO - 1) / 8,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+#define LATCH1_LABEL "latch1"
+
+static struct bgpio_pdata latch1_pdata = {
+ .label = LATCH1_LABEL,
+ .base = -1,
+ .ngpio = LATCH1_NGPIO,
+};
+
+static struct platform_device latch1_gpio_device = {
+ .name = "basic-mmio-gpio",
+ .id = 0,
+ .resource = latch1_resources,
+ .num_resources = ARRAY_SIZE(latch1_resources),
+ .dev = {
+ .platform_data = &latch1_pdata,
+ },
+};
+
+#define LATCH1_PIN_LED_CAMERA 0
+#define LATCH1_PIN_LED_ADVERT 1
+#define LATCH1_PIN_LED_MAIL 2
+#define LATCH1_PIN_LED_HANDSFREE 3
+#define LATCH1_PIN_LED_VOICEMAIL 4
+#define LATCH1_PIN_LED_VOICE 5
+#define LATCH1_PIN_DOCKIT1 6
+#define LATCH1_PIN_DOCKIT2 7
+
+#define LATCH2_NGPIO 16
+
+static struct resource latch2_resources[] = {
+ [0] = {
+ .name = "dat",
+ .start = LATCH2_PHYS,
+ .end = LATCH2_PHYS + (LATCH2_NGPIO - 1) / 8,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+#define LATCH2_LABEL "latch2"
+
+static struct bgpio_pdata latch2_pdata = {
+ .label = LATCH2_LABEL,
+ .base = -1,
+ .ngpio = LATCH2_NGPIO,
+};
+
+static struct platform_device latch2_gpio_device = {
+ .name = "basic-mmio-gpio",
+ .id = 1,
+ .resource = latch2_resources,
+ .num_resources = ARRAY_SIZE(latch2_resources),
+ .dev = {
+ .platform_data = &latch2_pdata,
+ },
+};
+
+#define LATCH2_PIN_LCD_VBLEN 0
+#define LATCH2_PIN_LCD_NDISP 1
+#define LATCH2_PIN_NAND_NCE 2
+#define LATCH2_PIN_NAND_NRE 3
+#define LATCH2_PIN_NAND_NWP 4
+#define LATCH2_PIN_NAND_NWE 5
+#define LATCH2_PIN_NAND_ALE 6
+#define LATCH2_PIN_NAND_CLE 7
+#define LATCH2_PIN_KEYBRD_PWR 8
+#define LATCH2_PIN_KEYBRD_DATAOUT 9
+#define LATCH2_PIN_SCARD_RSTIN 10
+#define LATCH2_PIN_SCARD_CMDVCC 11
+#define LATCH2_PIN_MODEM_NRESET 12
+#define LATCH2_PIN_MODEM_CODEC 13
+#define LATCH2_PIN_HANDSFREE_MUTE 14
+#define LATCH2_PIN_HANDSET_MUTE 15
+
+static struct regulator_consumer_supply modem_nreset_consumers[] = {
+ REGULATOR_SUPPLY("RESET#", "serial8250.1"),
+ REGULATOR_SUPPLY("POR", "cx20442-codec"),
+};
+
+static struct regulator_init_data modem_nreset_data = {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(modem_nreset_consumers),
+ .consumer_supplies = modem_nreset_consumers,
+};
+
+static struct fixed_voltage_config modem_nreset_config = {
+ .supply_name = "modem_nreset",
+ .microvolts = 3300000,
+ .startup_delay = 25000,
+ .enabled_at_boot = 1,
+ .init_data = &modem_nreset_data,
+};
+
+static struct platform_device modem_nreset_device = {
+ .name = "reg-fixed-voltage",
+ .id = -1,
+ .dev = {
+ .platform_data = &modem_nreset_config,
+ },
+};
+
+static struct gpiod_lookup_table ams_delta_nreset_gpiod_table = {
+ .dev_id = "reg-fixed-voltage",
+ .table = {
+ GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_MODEM_NRESET,
+ NULL, GPIO_ACTIVE_HIGH),
+ { },
+ },
+};
+
+struct modem_private_data {
+ struct regulator *regulator;
+};
+
+static struct modem_private_data modem_priv;
+
+/*
+ * Define partitions for flash device
+ */
+
+static struct mtd_partition partition_info[] = {
+ { .name = "Kernel",
+ .offset = 0,
+ .size = 3 * SZ_1M + SZ_512K },
+ { .name = "u-boot",
+ .offset = 3 * SZ_1M + SZ_512K,
+ .size = SZ_256K },
+ { .name = "u-boot params",
+ .offset = 3 * SZ_1M + SZ_512K + SZ_256K,
+ .size = SZ_256K },
+ { .name = "Amstrad LDR",
+ .offset = 4 * SZ_1M,
+ .size = SZ_256K },
+ { .name = "File system",
+ .offset = 4 * SZ_1M + 1 * SZ_256K,
+ .size = 27 * SZ_1M },
+ { .name = "PBL reserved",
+ .offset = 32 * SZ_1M - 3 * SZ_256K,
+ .size = 3 * SZ_256K },
+};
+
+static struct gpio_nand_platdata nand_platdata = {
+ .parts = partition_info,
+ .num_parts = ARRAY_SIZE(partition_info),
+};
+
+static struct platform_device ams_delta_nand_device = {
+ .name = "ams-delta-nand",
+ .id = -1,
+ .dev = {
+ .platform_data = &nand_platdata,
+ },
+};
+
+#define OMAP_GPIO_LABEL "gpio-0-15"
+#define OMAP_MPUIO_LABEL "mpuio"
+
+static struct gpiod_lookup_table ams_delta_nand_gpio_table = {
+ .table = {
+ GPIO_LOOKUP(OMAP_GPIO_LABEL, AMS_DELTA_GPIO_PIN_NAND_RB, "rdy",
+ 0),
+ GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_NAND_NCE, "nce",
+ GPIO_ACTIVE_LOW),
+ GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_NAND_NRE, "nre",
+ GPIO_ACTIVE_LOW),
+ GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_NAND_NWP, "nwp",
+ GPIO_ACTIVE_LOW),
+ GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_NAND_NWE, "nwe",
+ GPIO_ACTIVE_LOW),
+ GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_NAND_ALE, "ale", 0),
+ GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_NAND_CLE, "cle", 0),
+ GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 0, "data", 0, 0),
+ GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 1, "data", 1, 0),
+ GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 2, "data", 2, 0),
+ GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 3, "data", 3, 0),
+ GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 4, "data", 4, 0),
+ GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 5, "data", 5, 0),
+ GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 6, "data", 6, 0),
+ GPIO_LOOKUP_IDX(OMAP_MPUIO_LABEL, 7, "data", 7, 0),
+ { },
+ },
+};
+
+static struct resource ams_delta_kp_resources[] = {
+ [0] = {
+ .start = INT_KEYBOARD,
+ .end = INT_KEYBOARD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static const struct matrix_keymap_data ams_delta_keymap_data = {
+ .keymap = ams_delta_keymap,
+ .keymap_size = ARRAY_SIZE(ams_delta_keymap),
+};
+
+static struct omap_kp_platform_data ams_delta_kp_data = {
+ .rows = 8,
+ .cols = 8,
+ .keymap_data = &ams_delta_keymap_data,
+ .delay = 9,
+};
+
+static struct platform_device ams_delta_kp_device = {
+ .name = "omap-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &ams_delta_kp_data,
+ },
+ .num_resources = ARRAY_SIZE(ams_delta_kp_resources),
+ .resource = ams_delta_kp_resources,
+};
+
+static struct platform_device ams_delta_lcd_device = {
+ .name = "lcd_ams_delta",
+ .id = -1,
+};
+
+static struct gpiod_lookup_table ams_delta_lcd_gpio_table = {
+ .table = {
+ GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_LCD_VBLEN, "vblen", 0),
+ GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_LCD_NDISP, "ndisp", 0),
+ { },
+ },
+};
+
+static struct gpio_led gpio_leds[] __initdata = {
+ [LATCH1_PIN_LED_CAMERA] = {
+ .name = "camera",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ [LATCH1_PIN_LED_ADVERT] = {
+ .name = "advert",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ [LATCH1_PIN_LED_MAIL] = {
+ .name = "email",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ [LATCH1_PIN_LED_HANDSFREE] = {
+ .name = "handsfree",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ [LATCH1_PIN_LED_VOICEMAIL] = {
+ .name = "voicemail",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+ [LATCH1_PIN_LED_VOICE] = {
+ .name = "voice",
+ .default_state = LEDS_GPIO_DEFSTATE_OFF,
+ },
+};
+
+static const struct gpio_led_platform_data leds_pdata __initconst = {
+ .leds = gpio_leds,
+ .num_leds = ARRAY_SIZE(gpio_leds),
+};
+
+static struct gpiod_lookup_table leds_gpio_table = {
+ .table = {
+ GPIO_LOOKUP_IDX(LATCH1_LABEL, LATCH1_PIN_LED_CAMERA, NULL,
+ LATCH1_PIN_LED_CAMERA, 0),
+ GPIO_LOOKUP_IDX(LATCH1_LABEL, LATCH1_PIN_LED_ADVERT, NULL,
+ LATCH1_PIN_LED_ADVERT, 0),
+ GPIO_LOOKUP_IDX(LATCH1_LABEL, LATCH1_PIN_LED_MAIL, NULL,
+ LATCH1_PIN_LED_MAIL, 0),
+ GPIO_LOOKUP_IDX(LATCH1_LABEL, LATCH1_PIN_LED_HANDSFREE, NULL,
+ LATCH1_PIN_LED_HANDSFREE, 0),
+ GPIO_LOOKUP_IDX(LATCH1_LABEL, LATCH1_PIN_LED_VOICEMAIL, NULL,
+ LATCH1_PIN_LED_VOICEMAIL, 0),
+ GPIO_LOOKUP_IDX(LATCH1_LABEL, LATCH1_PIN_LED_VOICE, NULL,
+ LATCH1_PIN_LED_VOICE, 0),
+ { },
+ },
+};
+
+static struct platform_device ams_delta_audio_device = {
+ .name = "ams-delta-audio",
+ .id = -1,
+};
+
+static struct gpiod_lookup_table ams_delta_audio_gpio_table = {
+ .table = {
+ GPIO_LOOKUP(OMAP_GPIO_LABEL, AMS_DELTA_GPIO_PIN_HOOK_SWITCH,
+ "hook_switch", 0),
+ GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_MODEM_CODEC,
+ "modem_codec", 0),
+ GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_HANDSFREE_MUTE,
+ "handsfree_mute", 0),
+ GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_HANDSET_MUTE,
+ "handset_mute", 0),
+ { },
+ },
+};
+
+static struct platform_device cx20442_codec_device = {
+ .name = "cx20442-codec",
+ .id = -1,
+};
+
+static struct resource ams_delta_serio_resources[] = {
+ {
+ .flags = IORESOURCE_IRQ,
+ /*
+ * Initialize IRQ resource with invalid IRQ number.
+ * It will be replaced with dynamically allocated GPIO IRQ
+ * obtained from GPIO chip as soon as the chip is available.
+ */
+ .start = -EINVAL,
+ .end = -EINVAL,
+ },
+};
+
+static struct platform_device ams_delta_serio_device = {
+ .name = "ams-delta-serio",
+ .id = PLATFORM_DEVID_NONE,
+ .dev = {
+ /*
+ * Initialize .platform_data explicitly with NULL to
+ * indicate it is going to be used. It will be replaced
+ * with FIQ buffer address as soon as FIQ is initialized.
+ */
+ .platform_data = NULL,
+ },
+ .num_resources = ARRAY_SIZE(ams_delta_serio_resources),
+ .resource = ams_delta_serio_resources,
+};
+
+static struct regulator_consumer_supply keybrd_pwr_consumers[] = {
+ /*
+ * Initialize supply .dev_name with NULL. It will be replaced
+ * with serio dev_name() as soon as the serio device is registered.
+ */
+ REGULATOR_SUPPLY("vcc", NULL),
+};
+
+static struct regulator_init_data keybrd_pwr_initdata = {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(keybrd_pwr_consumers),
+ .consumer_supplies = keybrd_pwr_consumers,
+};
+
+static struct fixed_voltage_config keybrd_pwr_config = {
+ .supply_name = "keybrd_pwr",
+ .microvolts = 5000000,
+ .init_data = &keybrd_pwr_initdata,
+};
+
+static struct platform_device keybrd_pwr_device = {
+ .name = "reg-fixed-voltage",
+ .id = PLATFORM_DEVID_AUTO,
+ .dev = {
+ .platform_data = &keybrd_pwr_config,
+ },
+};
+
+static struct gpiod_lookup_table keybrd_pwr_gpio_table = {
+ .table = {
+ GPIO_LOOKUP(LATCH2_LABEL, LATCH2_PIN_KEYBRD_PWR, NULL,
+ GPIO_ACTIVE_HIGH),
+ { },
+ },
+};
+
+static struct platform_device *ams_delta_devices[] __initdata = {
+ &latch1_gpio_device,
+ &latch2_gpio_device,
+ &ams_delta_kp_device,
+ &ams_delta_audio_device,
+ &ams_delta_serio_device,
+ &ams_delta_nand_device,
+ &ams_delta_lcd_device,
+ &cx20442_codec_device,
+ &modem_nreset_device,
+};
+
+static struct gpiod_lookup_table *ams_delta_gpio_tables[] __initdata = {
+ &ams_delta_nreset_gpiod_table,
+ &ams_delta_audio_gpio_table,
+ &keybrd_pwr_gpio_table,
+ &ams_delta_lcd_gpio_table,
+ &ams_delta_nand_gpio_table,
+};
+
+/*
+ * Some drivers may not use GPIO lookup tables but need to be provided
+ * with GPIO numbers. The same applies to GPIO based IRQ lines - some
+ * drivers may even not use GPIO layer but expect just IRQ numbers.
+ * We could either define GPIO lookup tables then use them on behalf
+ * of those devices, or we can use GPIO driver level methods for
+ * identification of GPIO and IRQ numbers. For the purpose of the latter,
+ * defina a helper function which identifies GPIO chips by their labels.
+ */
+static int gpiochip_match_by_label(struct gpio_chip *chip, void *data)
+{
+ char *label = data;
+
+ return !strcmp(label, chip->label);
+}
+
+static struct gpiod_hog ams_delta_gpio_hogs[] = {
+ GPIO_HOG(LATCH2_LABEL, LATCH2_PIN_KEYBRD_DATAOUT, "keybrd_dataout",
+ GPIO_ACTIVE_HIGH, GPIOD_OUT_LOW),
+ {},
+};
+
+static struct plat_serial8250_port ams_delta_modem_ports[];
+
+/*
+ * Obtain MODEM IRQ GPIO descriptor using its hardware pin
+ * number and assign related IRQ number to the MODEM port.
+ * Keep the GPIO descriptor open so nobody steps in.
+ */
+static void __init modem_assign_irq(struct gpio_chip *chip)
+{
+ struct gpio_desc *gpiod;
+
+ gpiod = gpiochip_request_own_desc(chip, AMS_DELTA_GPIO_PIN_MODEM_IRQ,
+ "modem_irq", GPIO_ACTIVE_HIGH,
+ GPIOD_IN);
+ if (IS_ERR(gpiod)) {
+ pr_err("%s: modem IRQ GPIO request failed (%ld)\n", __func__,
+ PTR_ERR(gpiod));
+ } else {
+ ams_delta_modem_ports[0].irq = gpiod_to_irq(gpiod);
+ }
+}
+
+/*
+ * The purpose of this function is to take care of proper initialization of
+ * devices and data structures which depend on GPIO lines provided by OMAP GPIO
+ * banks but their drivers don't use GPIO lookup tables or GPIO layer at all.
+ * The function may be called as soon as OMAP GPIO devices are probed.
+ * Since that happens at postcore_initcall, it can be called successfully
+ * from init_machine or later.
+ * Dependent devices may be registered from within this function or later.
+ */
+static void __init omap_gpio_deps_init(void)
+{
+ struct gpio_chip *chip;
+
+ chip = gpiochip_find(OMAP_GPIO_LABEL, gpiochip_match_by_label);
+ if (!chip) {
+ pr_err("%s: OMAP GPIO chip not found\n", __func__);
+ return;
+ }
+
+ /*
+ * Start with FIQ initialization as it may have to request
+ * and release successfully each OMAP GPIO pin in turn.
+ */
+ ams_delta_init_fiq(chip, &ams_delta_serio_device);
+
+ modem_assign_irq(chip);
+}
+
+/*
+ * Initialize latch2 pins with values which are safe for dependent on-board
+ * devices or useful for their successull initialization even before GPIO
+ * driver takes control over the latch pins:
+ * - LATCH2_PIN_LCD_VBLEN = 0
+ * - LATCH2_PIN_LCD_NDISP = 0 Keep LCD device powered off before its
+ * driver takes control over it.
+ * - LATCH2_PIN_NAND_NCE = 0
+ * - LATCH2_PIN_NAND_NWP = 0 Keep NAND device down and write-
+ * protected before its driver takes
+ * control over it.
+ * - LATCH2_PIN_KEYBRD_PWR = 0 Keep keyboard powered off before serio
+ * driver takes control over it.
+ * - LATCH2_PIN_KEYBRD_DATAOUT = 0 Keep low to avoid corruption of first
+ * byte of data received from attached
+ * keyboard when serio device is probed;
+ * the pin is also hogged low by the latch2
+ * GPIO driver as soon as it is ready.
+ * - LATCH2_PIN_MODEM_NRESET = 1 Enable voice MODEM device, allowing for
+ * its successful probe even before a
+ * regulator it depends on, which in turn
+ * takes control over the pin, is set up.
+ * - LATCH2_PIN_MODEM_CODEC = 1 Attach voice MODEM CODEC data port
+ * to the MODEM so the CODEC is under
+ * control even if audio driver doesn't
+ * take it over.
+ */
+static void __init ams_delta_latch2_init(void)
+{
+ u16 latch2 = 1 << LATCH2_PIN_MODEM_NRESET | 1 << LATCH2_PIN_MODEM_CODEC;
+
+ __raw_writew(latch2, IOMEM(LATCH2_VIRT));
+}
+
+static void __init ams_delta_init(void)
+{
+ struct platform_device *leds_pdev;
+
+ /* mux pins for uarts */
+ omap_cfg_reg(UART1_TX);
+ omap_cfg_reg(UART1_RTS);
+
+ /* parallel camera interface */
+ omap_cfg_reg(H19_1610_CAM_EXCLK);
+ omap_cfg_reg(J15_1610_CAM_LCLK);
+ omap_cfg_reg(L18_1610_CAM_VS);
+ omap_cfg_reg(L15_1610_CAM_HS);
+ omap_cfg_reg(L19_1610_CAM_D0);
+ omap_cfg_reg(K14_1610_CAM_D1);
+ omap_cfg_reg(K15_1610_CAM_D2);
+ omap_cfg_reg(K19_1610_CAM_D3);
+ omap_cfg_reg(K18_1610_CAM_D4);
+ omap_cfg_reg(J14_1610_CAM_D5);
+ omap_cfg_reg(J19_1610_CAM_D6);
+ omap_cfg_reg(J18_1610_CAM_D7);
+
+ omap_gpio_deps_init();
+ ams_delta_latch2_init();
+ gpiod_add_hogs(ams_delta_gpio_hogs);
+
+ omap_serial_init();
+ omap_register_i2c_bus(1, 100, NULL, 0);
+
+ omap1_usb_init(&ams_delta_usb_config);
+ platform_add_devices(ams_delta_devices, ARRAY_SIZE(ams_delta_devices));
+
+ /*
+ * As soon as regulator consumers have been registered, assign their
+ * dev_names to consumer supply entries of respective regulators.
+ */
+ keybrd_pwr_consumers[0].dev_name =
+ dev_name(&ams_delta_serio_device.dev);
+
+ /*
+ * Once consumer supply entries are populated with dev_names,
+ * register regulator devices. At this stage only the keyboard
+ * power regulator has its consumer supply table fully populated.
+ */
+ platform_device_register(&keybrd_pwr_device);
+
+ /*
+ * As soon as GPIO consumers have been registered, assign
+ * their dev_names to respective GPIO lookup tables.
+ */
+ ams_delta_audio_gpio_table.dev_id =
+ dev_name(&ams_delta_audio_device.dev);
+ keybrd_pwr_gpio_table.dev_id = dev_name(&keybrd_pwr_device.dev);
+ ams_delta_nand_gpio_table.dev_id = dev_name(&ams_delta_nand_device.dev);
+ ams_delta_lcd_gpio_table.dev_id = dev_name(&ams_delta_lcd_device.dev);
+
+ /*
+ * Once GPIO lookup tables are populated with dev_names, register them.
+ */
+ gpiod_add_lookup_tables(ams_delta_gpio_tables,
+ ARRAY_SIZE(ams_delta_gpio_tables));
+
+ leds_pdev = gpio_led_register_device(PLATFORM_DEVID_NONE, &leds_pdata);
+ if (!IS_ERR_OR_NULL(leds_pdev)) {
+ leds_gpio_table.dev_id = dev_name(&leds_pdev->dev);
+ gpiod_add_lookup_table(&leds_gpio_table);
+ }
+
+ omap_writew(omap_readw(ARM_RSTCT1) | 0x0004, ARM_RSTCT1);
+
+ omapfb_set_lcd_config(&ams_delta_lcd_config);
+}
+
+static void modem_pm(struct uart_port *port, unsigned int state, unsigned old)
+{
+ struct modem_private_data *priv = port->private_data;
+ int ret;
+
+ if (!priv)
+ return;
+
+ if (IS_ERR(priv->regulator))
+ return;
+
+ if (state == old)
+ return;
+
+ if (state == 0)
+ ret = regulator_enable(priv->regulator);
+ else if (old == 0)
+ ret = regulator_disable(priv->regulator);
+ else
+ ret = 0;
+
+ if (ret)
+ dev_warn(port->dev,
+ "ams_delta modem_pm: failed to %sable regulator: %d\n",
+ state ? "dis" : "en", ret);
+}
+
+static struct plat_serial8250_port ams_delta_modem_ports[] = {
+ {
+ .membase = IOMEM(MODEM_VIRT),
+ .mapbase = MODEM_PHYS,
+ .irq = IRQ_NOTCONNECTED, /* changed later */
+ .flags = UPF_BOOT_AUTOCONF,
+ .irqflags = IRQF_TRIGGER_RISING,
+ .iotype = UPIO_MEM,
+ .regshift = 1,
+ .uartclk = BASE_BAUD * 16,
+ .pm = modem_pm,
+ .private_data = &modem_priv,
+ },
+ { },
+};
+
+static int ams_delta_modem_pm_activate(struct device *dev)
+{
+ modem_priv.regulator = regulator_get(dev, "RESET#");
+ if (IS_ERR(modem_priv.regulator))
+ return -EPROBE_DEFER;
+
+ return 0;
+}
+
+static struct dev_pm_domain ams_delta_modem_pm_domain = {
+ .activate = ams_delta_modem_pm_activate,
+};
+
+static struct platform_device ams_delta_modem_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM1,
+ .dev = {
+ .platform_data = ams_delta_modem_ports,
+ .pm_domain = &ams_delta_modem_pm_domain,
+ },
+};
+
+/*
+ * This function expects MODEM IRQ number already assigned to the port.
+ * The MODEM device requires its RESET# pin kept high during probe.
+ * That requirement can be fulfilled in several ways:
+ * - with a descriptor of already functional modem_nreset regulator
+ * assigned to the MODEM private data,
+ * - with the regulator not yet controlled by modem_pm function but
+ * already enabled by default on probe,
+ * - before the modem_nreset regulator is probed, with the pin already
+ * set high explicitly.
+ * The last one is already guaranteed by ams_delta_latch2_init() called
+ * from machine_init.
+ * In order to avoid taking over ttyS0 device slot, the MODEM device
+ * should be registered after OMAP serial ports. Since those ports
+ * are registered at arch_initcall, this function can be called safely
+ * at arch_initcall_sync earliest.
+ */
+static int __init ams_delta_modem_init(void)
+{
+ if (!machine_is_ams_delta())
+ return -ENODEV;
+
+ omap_cfg_reg(M14_1510_GPIO2);
+
+ /* Initialize the modem_nreset regulator consumer before use */
+ modem_priv.regulator = ERR_PTR(-ENODEV);
+
+ return platform_device_register(&ams_delta_modem_device);
+}
+arch_initcall_sync(ams_delta_modem_init);
+
+static void __init ams_delta_map_io(void)
+{
+ omap1_map_io();
+ iotable_init(ams_delta_io_desc, ARRAY_SIZE(ams_delta_io_desc));
+}
+
+MACHINE_START(AMS_DELTA, "Amstrad E3 (Delta)")
+ /* Maintainer: Jonathan McDowell <noodles@earth.li> */
+ .atag_offset = 0x100,
+ .map_io = ams_delta_map_io,
+ .init_early = omap1_init_early,
+ .init_irq = omap1_init_irq,
+ .init_machine = ams_delta_init,
+ .init_late = omap1_init_late,
+ .init_time = omap1_timer_init,
+ .restart = omap1_restart,
+MACHINE_END
diff --git a/arch/arm/mach-omap1/board-ams-delta.h b/arch/arm/mach-omap1/board-ams-delta.h
new file mode 100644
index 0000000000..b5c4a373b9
--- /dev/null
+++ b/arch/arm/mach-omap1/board-ams-delta.h
@@ -0,0 +1,42 @@
+/*
+ * arch/arm/mach-omap1/board-ams-delta.h
+ *
+ * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef __ASM_ARCH_OMAP_AMS_DELTA_H
+#define __ASM_ARCH_OMAP_AMS_DELTA_H
+
+#if defined (CONFIG_MACH_AMS_DELTA)
+
+#define AMS_DELTA_GPIO_PIN_KEYBRD_DATA 0
+#define AMS_DELTA_GPIO_PIN_KEYBRD_CLK 1
+#define AMS_DELTA_GPIO_PIN_MODEM_IRQ 2
+#define AMS_DELTA_GPIO_PIN_HOOK_SWITCH 4
+#define AMS_DELTA_GPIO_PIN_SCARD_NOFF 6
+#define AMS_DELTA_GPIO_PIN_SCARD_IO 7
+#define AMS_DELTA_GPIO_PIN_CONFIG 11
+#define AMS_DELTA_GPIO_PIN_NAND_RB 12
+
+#endif /* CONFIG_MACH_AMS_DELTA */
+
+#endif /* __ASM_ARCH_OMAP_AMS_DELTA_H */
diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
new file mode 100644
index 0000000000..3312ef9335
--- /dev/null
+++ b/arch/arm/mach-omap1/board-nokia770.c
@@ -0,0 +1,351 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * linux/arch/arm/mach-omap1/board-nokia770.c
+ *
+ * Modified from board-generic.c
+ */
+#include <linux/clkdev.h>
+#include <linux/irq.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
+#include <linux/gpio/property.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/input.h>
+#include <linux/omapfb.h>
+
+#include <linux/spi/spi.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+
+#include <linux/platform_data/keypad-omap.h>
+#include <linux/platform_data/lcd-mipid.h>
+#include <linux/platform_data/gpio-omap.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include "mux.h"
+#include "hardware.h"
+#include "usb.h"
+#include "common.h"
+#include "clock.h"
+#include "mmc.h"
+
+static const struct software_node nokia770_mpuio_gpiochip_node = {
+ .name = "mpuio",
+};
+
+static const struct software_node nokia770_gpiochip1_node = {
+ .name = "gpio-0-15",
+};
+
+static const struct software_node nokia770_gpiochip2_node = {
+ .name = "gpio-16-31",
+};
+
+static const struct software_node *nokia770_gpiochip_nodes[] = {
+ &nokia770_mpuio_gpiochip_node,
+ &nokia770_gpiochip1_node,
+ &nokia770_gpiochip2_node,
+ NULL
+};
+
+#define ADS7846_PENDOWN_GPIO 15
+
+static const unsigned int nokia770_keymap[] = {
+ KEY(1, 0, GROUP_0 | KEY_UP),
+ KEY(2, 0, GROUP_1 | KEY_F5),
+ KEY(0, 1, GROUP_0 | KEY_LEFT),
+ KEY(1, 1, GROUP_0 | KEY_ENTER),
+ KEY(2, 1, GROUP_0 | KEY_RIGHT),
+ KEY(0, 2, GROUP_1 | KEY_ESC),
+ KEY(1, 2, GROUP_0 | KEY_DOWN),
+ KEY(2, 2, GROUP_1 | KEY_F4),
+ KEY(0, 3, GROUP_2 | KEY_F7),
+ KEY(1, 3, GROUP_2 | KEY_F8),
+ KEY(2, 3, GROUP_2 | KEY_F6),
+};
+
+static struct resource nokia770_kp_resources[] = {
+ [0] = {
+ .start = INT_KEYBOARD,
+ .end = INT_KEYBOARD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static const struct matrix_keymap_data nokia770_keymap_data = {
+ .keymap = nokia770_keymap,
+ .keymap_size = ARRAY_SIZE(nokia770_keymap),
+};
+
+static struct omap_kp_platform_data nokia770_kp_data = {
+ .rows = 8,
+ .cols = 8,
+ .keymap_data = &nokia770_keymap_data,
+ .delay = 4,
+};
+
+static struct platform_device nokia770_kp_device = {
+ .name = "omap-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &nokia770_kp_data,
+ },
+ .num_resources = ARRAY_SIZE(nokia770_kp_resources),
+ .resource = nokia770_kp_resources,
+};
+
+static struct platform_device *nokia770_devices[] __initdata = {
+ &nokia770_kp_device,
+};
+
+static struct mipid_platform_data nokia770_mipid_platform_data = { };
+
+static const struct omap_lcd_config nokia770_lcd_config __initconst = {
+ .ctrl_name = "hwa742",
+};
+
+static const struct property_entry nokia770_mipid_props[] = {
+ PROPERTY_ENTRY_GPIO("reset-gpios", &nokia770_gpiochip1_node,
+ 13, GPIO_ACTIVE_LOW),
+ { }
+};
+
+static const struct software_node nokia770_mipid_swnode = {
+ .name = "lcd_mipid",
+ .properties = nokia770_mipid_props,
+};
+
+static void __init mipid_dev_init(void)
+{
+ nokia770_mipid_platform_data.data_lines = 16;
+
+ omapfb_set_lcd_config(&nokia770_lcd_config);
+}
+
+static const struct property_entry nokia770_ads7846_props[] = {
+ PROPERTY_ENTRY_STRING("compatible", "ti,ads7846"),
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 4096),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 4096),
+ PROPERTY_ENTRY_U32("touchscreen-max-pressure", 256),
+ PROPERTY_ENTRY_U32("touchscreen-average-samples", 10),
+ PROPERTY_ENTRY_U16("ti,x-plate-ohms", 180),
+ PROPERTY_ENTRY_U16("ti,debounce-tol", 3),
+ PROPERTY_ENTRY_U16("ti,debounce-rep", 1),
+ PROPERTY_ENTRY_GPIO("pendown-gpios", &nokia770_gpiochip1_node,
+ ADS7846_PENDOWN_GPIO, GPIO_ACTIVE_LOW),
+ { }
+};
+
+static const struct software_node nokia770_ads7846_swnode = {
+ .name = "ads7846",
+ .properties = nokia770_ads7846_props,
+};
+
+static struct spi_board_info nokia770_spi_board_info[] __initdata = {
+ [0] = {
+ .modalias = "lcd_mipid",
+ .bus_num = 2,
+ .chip_select = 3,
+ .max_speed_hz = 12000000,
+ .platform_data = &nokia770_mipid_platform_data,
+ .swnode = &nokia770_mipid_swnode,
+ },
+ [1] = {
+ .modalias = "ads7846",
+ .bus_num = 2,
+ .chip_select = 0,
+ .max_speed_hz = 2500000,
+ .swnode = &nokia770_ads7846_swnode,
+ },
+};
+
+static void __init hwa742_dev_init(void)
+{
+ clk_add_alias("hwa_sys_ck", NULL, "bclk", NULL);
+}
+
+/* assume no Mini-AB port */
+
+static struct omap_usb_config nokia770_usb_config __initdata = {
+ .otg = 1,
+ .register_host = 1,
+ .register_dev = 1,
+ .hmc_mode = 16,
+ .pins[0] = 6,
+ .extcon = "tahvo-usb",
+};
+
+#if IS_ENABLED(CONFIG_MMC_OMAP)
+
+static struct gpiod_lookup_table nokia770_mmc_gpio_table = {
+ .dev_id = "mmci-omap.1",
+ .table = {
+ /* Slot index 0, VSD power, GPIO 41 */
+ GPIO_LOOKUP_IDX("gpio-32-47", 9,
+ "vsd", 0, GPIO_ACTIVE_HIGH),
+ /* Slot index 0, switch, GPIO 23 */
+ GPIO_LOOKUP_IDX("gpio-16-31", 7,
+ "cover", 0, GPIO_ACTIVE_HIGH),
+ { }
+ },
+};
+
+static struct omap_mmc_platform_data nokia770_mmc2_data = {
+ .nr_slots = 1,
+ .max_freq = 12000000,
+ .slots[0] = {
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .name = "mmcblk",
+ },
+};
+
+static struct omap_mmc_platform_data *nokia770_mmc_data[OMAP16XX_NR_MMC];
+
+static void __init nokia770_mmc_init(void)
+{
+ gpiod_add_lookup_table(&nokia770_mmc_gpio_table);
+ /* Only the second MMC controller is used */
+ nokia770_mmc_data[1] = &nokia770_mmc2_data;
+ omap1_init_mmc(nokia770_mmc_data, OMAP16XX_NR_MMC);
+}
+
+#else
+static inline void nokia770_mmc_init(void)
+{
+}
+#endif
+
+#if IS_ENABLED(CONFIG_I2C_CBUS_GPIO)
+
+static const struct software_node_ref_args nokia770_cbus_gpio_refs[] = {
+ SOFTWARE_NODE_REFERENCE(&nokia770_mpuio_gpiochip_node, 9, 0),
+ SOFTWARE_NODE_REFERENCE(&nokia770_mpuio_gpiochip_node, 10, 0),
+ SOFTWARE_NODE_REFERENCE(&nokia770_mpuio_gpiochip_node, 11, 0),
+};
+
+static const struct property_entry nokia770_cbus_props[] = {
+ PROPERTY_ENTRY_REF_ARRAY("gpios", nokia770_cbus_gpio_refs),
+ { }
+};
+
+static struct platform_device nokia770_cbus_device = {
+ .name = "i2c-cbus-gpio",
+ .id = 2,
+};
+
+static struct i2c_board_info nokia770_i2c_board_info_2[] __initdata = {
+ {
+ I2C_BOARD_INFO("retu", 0x01),
+ },
+ {
+ I2C_BOARD_INFO("tahvo", 0x02),
+ },
+};
+
+static void __init nokia770_cbus_init(void)
+{
+ struct gpio_desc *d;
+ int irq;
+
+ d = gpiod_get(NULL, "retu_irq", GPIOD_IN);
+ if (IS_ERR(d)) {
+ pr_err("Unable to get CBUS Retu IRQ GPIO descriptor\n");
+ } else {
+ irq = gpiod_to_irq(d);
+ irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
+ nokia770_i2c_board_info_2[0].irq = irq;
+ }
+ d = gpiod_get(NULL, "tahvo_irq", GPIOD_IN);
+ if (IS_ERR(d)) {
+ pr_err("Unable to get CBUS Tahvo IRQ GPIO descriptor\n");
+ } else {
+ irq = gpiod_to_irq(d);
+ irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
+ nokia770_i2c_board_info_2[1].irq = irq;
+ }
+ i2c_register_board_info(2, nokia770_i2c_board_info_2,
+ ARRAY_SIZE(nokia770_i2c_board_info_2));
+ device_create_managed_software_node(&nokia770_cbus_device.dev,
+ nokia770_cbus_props, NULL);
+ platform_device_register(&nokia770_cbus_device);
+}
+#else /* CONFIG_I2C_CBUS_GPIO */
+static void __init nokia770_cbus_init(void)
+{
+}
+#endif /* CONFIG_I2C_CBUS_GPIO */
+
+static struct gpiod_lookup_table nokia770_irq_gpio_table = {
+ .dev_id = NULL,
+ .table = {
+ /* GPIO used by SPI device 1 */
+ GPIO_LOOKUP("gpio-0-15", 15, "ads7846_irq",
+ GPIO_ACTIVE_HIGH),
+ /* GPIO used for retu IRQ */
+ GPIO_LOOKUP("gpio-48-63", 15, "retu_irq",
+ GPIO_ACTIVE_HIGH),
+ /* GPIO used for tahvo IRQ */
+ GPIO_LOOKUP("gpio-32-47", 8, "tahvo_irq",
+ GPIO_ACTIVE_HIGH),
+ /* GPIOs used by serial wakeup IRQs */
+ GPIO_LOOKUP_IDX("gpio-32-47", 5, "wakeup", 0,
+ GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP_IDX("gpio-16-31", 2, "wakeup", 1,
+ GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP_IDX("gpio-48-63", 1, "wakeup", 2,
+ GPIO_ACTIVE_HIGH),
+ { }
+ },
+};
+
+static void __init omap_nokia770_init(void)
+{
+ struct gpio_desc *d;
+
+ /* On Nokia 770, the SleepX signal is masked with an
+ * MPUIO line by default. It has to be unmasked for it
+ * to become functional */
+
+ /* SleepX mask direction */
+ omap_writew((omap_readw(0xfffb5008) & ~2), 0xfffb5008);
+ /* Unmask SleepX signal */
+ omap_writew((omap_readw(0xfffb5004) & ~2), 0xfffb5004);
+
+ software_node_register_node_group(nokia770_gpiochip_nodes);
+ platform_add_devices(nokia770_devices, ARRAY_SIZE(nokia770_devices));
+
+ gpiod_add_lookup_table(&nokia770_irq_gpio_table);
+ d = gpiod_get(NULL, "ads7846_irq", GPIOD_IN);
+ if (IS_ERR(d))
+ pr_err("Unable to get ADS7846 IRQ GPIO descriptor\n");
+ else
+ nokia770_spi_board_info[1].irq = gpiod_to_irq(d);
+
+ spi_register_board_info(nokia770_spi_board_info,
+ ARRAY_SIZE(nokia770_spi_board_info));
+ omap_serial_init();
+ omap_register_i2c_bus(1, 100, NULL, 0);
+ hwa742_dev_init();
+ mipid_dev_init();
+ omap1_usb_init(&nokia770_usb_config);
+ nokia770_mmc_init();
+ nokia770_cbus_init();
+}
+
+MACHINE_START(NOKIA770, "Nokia 770")
+ .atag_offset = 0x100,
+ .map_io = omap1_map_io,
+ .init_early = omap1_init_early,
+ .init_irq = omap1_init_irq,
+ .init_machine = omap_nokia770_init,
+ .init_late = omap1_init_late,
+ .init_time = omap1_timer_init,
+ .restart = omap1_restart,
+MACHINE_END
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
new file mode 100644
index 0000000000..7d5e6f9039
--- /dev/null
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -0,0 +1,454 @@
+/*
+ * linux/arch/arm/mach-omap1/board-osk.c
+ *
+ * Board specific init for OMAP5912 OSK
+ *
+ * Written by Dirk Behme <dirk.behme@de.bosch.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio/machine.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/smc91x.h>
+#include <linux/omapfb.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/mfd/tps65010.h>
+#include <linux/platform_data/gpio-omap.h>
+#include <linux/platform_data/omap1_bl.h>
+#include <linux/soc/ti/omap1-io.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include "tc.h"
+#include "flash.h"
+#include "mux.h"
+#include "hardware.h"
+#include "usb.h"
+#include "common.h"
+
+/* Name of the GPIO chip used by the OMAP for GPIOs 0..15 */
+#define OMAP_GPIO_LABEL "gpio-0-15"
+
+/* At OMAP5912 OSK the Ethernet is directly connected to CS1 */
+#define OMAP_OSK_ETHR_START 0x04800300
+
+/* TPS65010 has four GPIOs. nPG and LED2 can be treated like GPIOs with
+ * alternate pin configurations for hardware-controlled blinking.
+ */
+#define OSK_TPS_GPIO_USB_PWR_EN 0
+#define OSK_TPS_GPIO_LED_D3 1
+#define OSK_TPS_GPIO_LAN_RESET 2
+#define OSK_TPS_GPIO_DSP_PWR_EN 3
+#define OSK_TPS_GPIO_LED_D9 4
+#define OSK_TPS_GPIO_LED_D2 5
+
+static struct mtd_partition osk_partitions[] = {
+ /* bootloader (U-Boot, etc) in first sector */
+ {
+ .name = "bootloader",
+ .offset = 0,
+ .size = SZ_128K,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ /* bootloader params in the next sector */
+ {
+ .name = "params",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_128K,
+ .mask_flags = 0,
+ }, {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_2M,
+ .mask_flags = 0
+ }, {
+ .name = "filesystem",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ .mask_flags = 0
+ }
+};
+
+static struct physmap_flash_data osk_flash_data = {
+ .width = 2,
+ .set_vpp = omap1_set_vpp,
+ .parts = osk_partitions,
+ .nr_parts = ARRAY_SIZE(osk_partitions),
+};
+
+static struct resource osk_flash_resource = {
+ /* this is on CS3, wherever it's mapped */
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device osk5912_flash_device = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &osk_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &osk_flash_resource,
+};
+
+static struct smc91x_platdata osk5912_smc91x_info = {
+ .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
+ .leda = RPC_LED_100_10,
+ .ledb = RPC_LED_TX_RX,
+};
+
+static struct resource osk5912_smc91x_resources[] = {
+ [0] = {
+ .start = OMAP_OSK_ETHR_START, /* Physical */
+ .end = OMAP_OSK_ETHR_START + 0xf,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ },
+};
+
+static struct platform_device osk5912_smc91x_device = {
+ .name = "smc91x",
+ .id = -1,
+ .dev = {
+ .platform_data = &osk5912_smc91x_info,
+ },
+ .num_resources = ARRAY_SIZE(osk5912_smc91x_resources),
+ .resource = osk5912_smc91x_resources,
+};
+
+static struct resource osk5912_cf_resources[] = {
+ [0] = {
+ .flags = IORESOURCE_IRQ,
+ },
+ [1] = {
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device osk5912_cf_device = {
+ .name = "omap_cf",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(osk5912_cf_resources),
+ .resource = osk5912_cf_resources,
+};
+
+static struct platform_device *osk5912_devices[] __initdata = {
+ &osk5912_flash_device,
+ &osk5912_smc91x_device,
+ &osk5912_cf_device,
+};
+
+static const struct gpio_led tps_leds[] = {
+ /* NOTE: D9 and D2 have hardware blink support.
+ * Also, D9 requires non-battery power.
+ */
+ { .name = "d9", .default_trigger = "disk-activity", },
+ { .name = "d2", },
+ { .name = "d3", .default_trigger = "heartbeat", },
+};
+
+static struct gpiod_lookup_table tps_leds_gpio_table = {
+ .dev_id = "leds-gpio",
+ .table = {
+ /* Use local offsets on TPS65010 */
+ GPIO_LOOKUP_IDX("tps65010", OSK_TPS_GPIO_LED_D9, NULL, 0, GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP_IDX("tps65010", OSK_TPS_GPIO_LED_D2, NULL, 1, GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP_IDX("tps65010", OSK_TPS_GPIO_LED_D3, NULL, 2, GPIO_ACTIVE_LOW),
+ { }
+ },
+};
+
+static struct gpio_led_platform_data tps_leds_data = {
+ .num_leds = 3,
+ .leds = tps_leds,
+};
+
+static struct platform_device osk5912_tps_leds = {
+ .name = "leds-gpio",
+ .id = 0,
+ .dev.platform_data = &tps_leds_data,
+};
+
+/* The board just hold these GPIOs hogged from setup to teardown */
+static struct gpio_desc *eth_reset;
+static struct gpio_desc *vdd_dsp;
+
+static int osk_tps_setup(struct i2c_client *client, struct gpio_chip *gc)
+{
+ struct gpio_desc *d;
+ if (!IS_BUILTIN(CONFIG_TPS65010))
+ return -ENOSYS;
+
+ /* Set GPIO 1 HIGH to disable VBUS power supply;
+ * OHCI driver powers it up/down as needed.
+ */
+ d = gpiochip_request_own_desc(gc, OSK_TPS_GPIO_USB_PWR_EN, "n_vbus_en",
+ GPIO_ACTIVE_HIGH, GPIOD_OUT_HIGH);
+ /* Free the GPIO again as the driver will request it */
+ gpiochip_free_own_desc(d);
+
+ /* Set GPIO 2 high so LED D3 is off by default */
+ tps65010_set_gpio_out_value(GPIO2, HIGH);
+
+ /* Set GPIO 3 low to take ethernet out of reset */
+ eth_reset = gpiochip_request_own_desc(gc, OSK_TPS_GPIO_LAN_RESET, "smc_reset",
+ GPIO_ACTIVE_HIGH, GPIOD_OUT_LOW);
+
+ /* GPIO4 is VDD_DSP */
+ vdd_dsp = gpiochip_request_own_desc(gc, OSK_TPS_GPIO_DSP_PWR_EN, "dsp_power",
+ GPIO_ACTIVE_HIGH, GPIOD_OUT_HIGH);
+ /* REVISIT if DSP support isn't configured, power it off ... */
+
+ /* Let LED1 (D9) blink; leds-gpio may override it */
+ tps65010_set_led(LED1, BLINK);
+
+ /* Set LED2 off by default */
+ tps65010_set_led(LED2, OFF);
+
+ /* Enable LOW_PWR handshake */
+ tps65010_set_low_pwr(ON);
+
+ /* Switch VLDO2 to 3.0V for AIC23 */
+ tps65010_config_vregs1(TPS_LDO2_ENABLE | TPS_VLDO2_3_0V
+ | TPS_LDO1_ENABLE);
+
+ /* register these three LEDs */
+ osk5912_tps_leds.dev.parent = &client->dev;
+ gpiod_add_lookup_table(&tps_leds_gpio_table);
+ platform_device_register(&osk5912_tps_leds);
+
+ return 0;
+}
+
+static void osk_tps_teardown(struct i2c_client *client, struct gpio_chip *gc)
+{
+ gpiochip_free_own_desc(eth_reset);
+ gpiochip_free_own_desc(vdd_dsp);
+}
+
+static struct tps65010_board tps_board = {
+ .outmask = 0x0f,
+ .setup = osk_tps_setup,
+ .teardown = osk_tps_teardown,
+};
+
+static struct i2c_board_info __initdata osk_i2c_board_info[] = {
+ {
+ /* This device will get the name "i2c-tps65010" */
+ I2C_BOARD_INFO("tps65010", 0x48),
+ .dev_name = "tps65010",
+ .platform_data = &tps_board,
+
+ },
+ {
+ I2C_BOARD_INFO("tlv320aic23", 0x1B),
+ },
+ /* TODO when driver support is ready:
+ * - optionally on Mistral, ov9640 camera sensor at 0x30
+ */
+};
+
+static void __init osk_init_smc91x(void)
+{
+ u32 l;
+
+ /* Check EMIFS wait states to fix errors with SMC_GET_PKT_HDR */
+ l = omap_readl(EMIFS_CCS(1));
+ l |= 0x3;
+ omap_writel(l, EMIFS_CCS(1));
+}
+
+static void __init osk_init_cf(int seg)
+{
+ struct resource *res = &osk5912_cf_resources[1];
+
+ omap_cfg_reg(M7_1610_GPIO62);
+
+ switch (seg) {
+ /* NOTE: CS0 could be configured too ... */
+ case 1:
+ res->start = OMAP_CS1_PHYS;
+ break;
+ case 2:
+ res->start = OMAP_CS2_PHYS;
+ break;
+ case 3:
+ res->start = omap_cs3_phys();
+ break;
+ }
+
+ res->end = res->start + SZ_8K - 1;
+ osk5912_cf_device.dev.platform_data = (void *)(uintptr_t)seg;
+
+ /* NOTE: better EMIFS setup might support more cards; but the
+ * TRM only shows how to affect regular flash signals, not their
+ * CF/PCMCIA variants...
+ */
+ pr_debug("%s: cs%d, previous ccs %08x acs %08x\n", __func__,
+ seg, omap_readl(EMIFS_CCS(seg)), omap_readl(EMIFS_ACS(seg)));
+ omap_writel(0x0004a1b3, EMIFS_CCS(seg)); /* synch mode 4 etc */
+ omap_writel(0x00000000, EMIFS_ACS(seg)); /* OE hold/setup */
+}
+
+static struct gpiod_lookup_table osk_usb_gpio_table = {
+ .dev_id = "ohci",
+ .table = {
+ /* Power GPIO on the I2C-attached TPS65010 */
+ GPIO_LOOKUP("tps65010", OSK_TPS_GPIO_USB_PWR_EN, "power",
+ GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP(OMAP_GPIO_LABEL, 9, "overcurrent",
+ GPIO_ACTIVE_HIGH),
+ { }
+ },
+};
+
+static struct omap_usb_config osk_usb_config __initdata = {
+ /* has usb host connector (A) ... for development it can also
+ * be used, with a NONSTANDARD gender-bending cable/dongle, as
+ * a peripheral.
+ */
+#if IS_ENABLED(CONFIG_USB_OMAP)
+ .register_dev = 1,
+ .hmc_mode = 0,
+#else
+ .register_host = 1,
+ .hmc_mode = 16,
+ .rwc = 1,
+#endif
+ .pins[0] = 2,
+};
+
+#define EMIFS_CS3_VAL (0x88013141)
+
+static struct gpiod_lookup_table osk_irq_gpio_table = {
+ .dev_id = NULL,
+ .table = {
+ /* GPIO used for SMC91x IRQ */
+ GPIO_LOOKUP(OMAP_GPIO_LABEL, 0, "smc_irq",
+ GPIO_ACTIVE_HIGH),
+ /* GPIO used for CF IRQ */
+ GPIO_LOOKUP("gpio-48-63", 14, "cf_irq",
+ GPIO_ACTIVE_HIGH),
+ /* GPIO used by the TPS65010 chip */
+ GPIO_LOOKUP("mpuio", 1, "tps65010",
+ GPIO_ACTIVE_HIGH),
+ /* GPIOs used for serial wakeup IRQs */
+ GPIO_LOOKUP_IDX("gpio-32-47", 5, "wakeup", 0,
+ GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP_IDX("gpio-16-31", 2, "wakeup", 1,
+ GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP_IDX("gpio-48-63", 1, "wakeup", 2,
+ GPIO_ACTIVE_HIGH),
+ { }
+ },
+};
+
+static void __init osk_init(void)
+{
+ struct gpio_desc *d;
+ u32 l;
+
+ osk_init_smc91x();
+ osk_init_cf(2); /* CS2 */
+
+ /* Workaround for wrong CS3 (NOR flash) timing
+ * There are some U-Boot versions out there which configure
+ * wrong CS3 memory timings. This mainly leads to CRC
+ * or similar errors if you use NOR flash (e.g. with JFFS2)
+ */
+ l = omap_readl(EMIFS_CCS(3));
+ if (l != EMIFS_CS3_VAL)
+ omap_writel(EMIFS_CS3_VAL, EMIFS_CCS(3));
+
+ osk_flash_resource.end = osk_flash_resource.start = omap_cs3_phys();
+ osk_flash_resource.end += SZ_32M - 1;
+
+ /*
+ * Add the GPIOs to be used as IRQs and immediately look them up
+ * to be passed as an IRQ resource. This is ugly but should work
+ * until the day we convert to device tree.
+ */
+ gpiod_add_lookup_table(&osk_irq_gpio_table);
+
+ d = gpiod_get(NULL, "smc_irq", GPIOD_IN);
+ if (IS_ERR(d)) {
+ pr_err("Unable to get SMC IRQ GPIO descriptor\n");
+ } else {
+ irq_set_irq_type(gpiod_to_irq(d), IRQ_TYPE_EDGE_RISING);
+ osk5912_smc91x_resources[1] = DEFINE_RES_IRQ(gpiod_to_irq(d));
+ }
+
+ d = gpiod_get(NULL, "cf_irq", GPIOD_IN);
+ if (IS_ERR(d)) {
+ pr_err("Unable to get CF IRQ GPIO descriptor\n");
+ } else {
+ /* the CF I/O IRQ is really active-low */
+ irq_set_irq_type(gpiod_to_irq(d), IRQ_TYPE_EDGE_FALLING);
+ osk5912_cf_resources[0] = DEFINE_RES_IRQ(gpiod_to_irq(d));
+ }
+
+ platform_add_devices(osk5912_devices, ARRAY_SIZE(osk5912_devices));
+
+ l = omap_readl(USB_TRANSCEIVER_CTRL);
+ l |= (3 << 1);
+ omap_writel(l, USB_TRANSCEIVER_CTRL);
+
+ gpiod_add_lookup_table(&osk_usb_gpio_table);
+ omap1_usb_init(&osk_usb_config);
+
+ omap_serial_init();
+
+ /* irq for tps65010 chip */
+ /* bootloader effectively does: omap_cfg_reg(U19_1610_MPUIO1); */
+ d = gpiod_get(NULL, "tps65010", GPIOD_IN);
+ if (IS_ERR(d))
+ pr_err("Unable to get TPS65010 IRQ GPIO descriptor\n");
+ else
+ osk_i2c_board_info[0].irq = gpiod_to_irq(d);
+ omap_register_i2c_bus(1, 400, osk_i2c_board_info,
+ ARRAY_SIZE(osk_i2c_board_info));
+}
+
+MACHINE_START(OMAP_OSK, "TI-OSK")
+ /* Maintainer: Dirk Behme <dirk.behme@de.bosch.com> */
+ .atag_offset = 0x100,
+ .map_io = omap1_map_io,
+ .init_early = omap1_init_early,
+ .init_irq = omap1_init_irq,
+ .init_machine = osk_init,
+ .init_late = omap1_init_late,
+ .init_time = omap1_timer_init,
+ .restart = omap1_restart,
+MACHINE_END
diff --git a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c
new file mode 100644
index 0000000000..7e061d671f
--- /dev/null
+++ b/arch/arm/mach-omap1/board-palmte.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * linux/arch/arm/mach-omap1/board-palmte.c
+ *
+ * Modified from board-generic.c
+ *
+ * Support for the Palm Tungsten E PDA.
+ *
+ * Original version : Laurent Gonzalez
+ *
+ * Maintainers : http://palmtelinux.sf.net
+ * palmtelinux-developpers@lists.sf.net
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
+ */
+#include <linux/gpio/machine.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/spi/spi.h>
+#include <linux/interrupt.h>
+#include <linux/apm-emulation.h>
+#include <linux/omapfb.h>
+#include <linux/omap-dma.h>
+#include <linux/platform_data/keypad-omap.h>
+#include <linux/platform_data/omap1_bl.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include "tc.h"
+#include "flash.h"
+#include "mux.h"
+#include "hardware.h"
+#include "usb.h"
+#include "mmc.h"
+#include "common.h"
+
+#define PALMTE_USBDETECT_GPIO 0
+#define PALMTE_USB_OR_DC_GPIO 1
+#define PALMTE_TSC_GPIO 4
+#define PALMTE_PINTDAV_GPIO 6
+#define PALMTE_MMC_WP_GPIO 8
+#define PALMTE_MMC_POWER_GPIO 9
+#define PALMTE_HDQ_GPIO 11
+#define PALMTE_HEADPHONES_GPIO 14
+#define PALMTE_SPEAKER_GPIO 15
+#define PALMTE_DC_GPIO OMAP_MPUIO(2)
+#define PALMTE_MMC_SWITCH_GPIO OMAP_MPUIO(4)
+#define PALMTE_MMC1_GPIO OMAP_MPUIO(6)
+#define PALMTE_MMC2_GPIO OMAP_MPUIO(7)
+#define PALMTE_MMC3_GPIO OMAP_MPUIO(11)
+
+static const unsigned int palmte_keymap[] = {
+ KEY(0, 0, KEY_F1), /* Calendar */
+ KEY(1, 0, KEY_F2), /* Contacts */
+ KEY(2, 0, KEY_F3), /* Tasks List */
+ KEY(3, 0, KEY_F4), /* Note Pad */
+ KEY(4, 0, KEY_POWER),
+ KEY(0, 1, KEY_LEFT),
+ KEY(1, 1, KEY_DOWN),
+ KEY(2, 1, KEY_UP),
+ KEY(3, 1, KEY_RIGHT),
+ KEY(4, 1, KEY_ENTER),
+};
+
+static const struct matrix_keymap_data palmte_keymap_data = {
+ .keymap = palmte_keymap,
+ .keymap_size = ARRAY_SIZE(palmte_keymap),
+};
+
+static struct omap_kp_platform_data palmte_kp_data = {
+ .rows = 8,
+ .cols = 8,
+ .keymap_data = &palmte_keymap_data,
+ .rep = true,
+ .delay = 12,
+};
+
+static struct resource palmte_kp_resources[] = {
+ [0] = {
+ .start = INT_KEYBOARD,
+ .end = INT_KEYBOARD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device palmte_kp_device = {
+ .name = "omap-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &palmte_kp_data,
+ },
+ .num_resources = ARRAY_SIZE(palmte_kp_resources),
+ .resource = palmte_kp_resources,
+};
+
+static struct mtd_partition palmte_rom_partitions[] = {
+ /* PalmOS "Small ROM", contains the bootloader and the debugger */
+ {
+ .name = "smallrom",
+ .offset = 0,
+ .size = 0xa000,
+ .mask_flags = MTD_WRITEABLE,
+ },
+ /* PalmOS "Big ROM", a filesystem with all the OS code and data */
+ {
+ .name = "bigrom",
+ .offset = SZ_128K,
+ /*
+ * 0x5f0000 bytes big in the multi-language ("EFIGS") version,
+ * 0x7b0000 bytes in the English-only ("enUS") version.
+ */
+ .size = 0x7b0000,
+ .mask_flags = MTD_WRITEABLE,
+ },
+};
+
+static struct physmap_flash_data palmte_rom_data = {
+ .width = 2,
+ .set_vpp = omap1_set_vpp,
+ .parts = palmte_rom_partitions,
+ .nr_parts = ARRAY_SIZE(palmte_rom_partitions),
+};
+
+static struct resource palmte_rom_resource = {
+ .start = OMAP_CS0_PHYS,
+ .end = OMAP_CS0_PHYS + SZ_8M - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device palmte_rom_device = {
+ .name = "physmap-flash",
+ .id = -1,
+ .dev = {
+ .platform_data = &palmte_rom_data,
+ },
+ .num_resources = 1,
+ .resource = &palmte_rom_resource,
+};
+
+static struct platform_device palmte_lcd_device = {
+ .name = "lcd_palmte",
+ .id = -1,
+};
+
+static struct omap_backlight_config palmte_backlight_config = {
+ .default_intensity = 0xa0,
+};
+
+static struct platform_device palmte_backlight_device = {
+ .name = "omap-bl",
+ .id = -1,
+ .dev = {
+ .platform_data = &palmte_backlight_config,
+ },
+};
+
+static struct platform_device *palmte_devices[] __initdata = {
+ &palmte_rom_device,
+ &palmte_kp_device,
+ &palmte_lcd_device,
+ &palmte_backlight_device,
+};
+
+static struct omap_usb_config palmte_usb_config __initdata = {
+ .register_dev = 1, /* Mini-B only receptacle */
+ .hmc_mode = 0,
+ .pins[0] = 2,
+};
+
+static const struct omap_lcd_config palmte_lcd_config __initconst = {
+ .ctrl_name = "internal",
+};
+
+static struct spi_board_info palmte_spi_info[] __initdata = {
+ {
+ .modalias = "tsc2102",
+ .bus_num = 2, /* uWire (officially) */
+ .chip_select = 0, /* As opposed to 3 */
+ .max_speed_hz = 8000000,
+ },
+};
+
+#if IS_ENABLED(CONFIG_MMC_OMAP)
+
+static struct omap_mmc_platform_data _palmte_mmc_config = {
+ .nr_slots = 1,
+ .slots[0] = {
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .name = "mmcblk",
+ },
+};
+
+static struct omap_mmc_platform_data *palmte_mmc_config[OMAP15XX_NR_MMC] = {
+ [0] = &_palmte_mmc_config,
+};
+
+static void palmte_mmc_init(void)
+{
+ omap1_init_mmc(palmte_mmc_config, OMAP15XX_NR_MMC);
+}
+
+#else /* CONFIG_MMC_OMAP */
+
+static void palmte_mmc_init(void)
+{
+}
+
+#endif /* CONFIG_MMC_OMAP */
+
+static struct gpiod_lookup_table palmte_irq_gpio_table = {
+ .dev_id = NULL,
+ .table = {
+ /* GPIO used for TSC2102 PINTDAV IRQ */
+ GPIO_LOOKUP("gpio-0-15", PALMTE_PINTDAV_GPIO, "tsc2102_irq",
+ GPIO_ACTIVE_HIGH),
+ /* GPIO used for USB or DC input detection */
+ GPIO_LOOKUP("gpio-0-15", PALMTE_USB_OR_DC_GPIO, "usb_dc_irq",
+ GPIO_ACTIVE_HIGH),
+ { }
+ },
+};
+
+static void __init omap_palmte_init(void)
+{
+ struct gpio_desc *d;
+
+ /* mux pins for uarts */
+ omap_cfg_reg(UART1_TX);
+ omap_cfg_reg(UART1_RTS);
+ omap_cfg_reg(UART2_TX);
+ omap_cfg_reg(UART2_RTS);
+ omap_cfg_reg(UART3_TX);
+ omap_cfg_reg(UART3_RX);
+
+ platform_add_devices(palmte_devices, ARRAY_SIZE(palmte_devices));
+
+ gpiod_add_lookup_table(&palmte_irq_gpio_table);
+ d = gpiod_get(NULL, "tsc2102_irq", GPIOD_IN);
+ if (IS_ERR(d))
+ pr_err("Unable to get TSC2102 IRQ GPIO descriptor\n");
+ else
+ palmte_spi_info[0].irq = gpiod_to_irq(d);
+ spi_register_board_info(palmte_spi_info, ARRAY_SIZE(palmte_spi_info));
+
+ /* We are getting this just to set it up as input */
+ d = gpiod_get(NULL, "usb_dc_irq", GPIOD_IN);
+ if (IS_ERR(d))
+ pr_err("Unable to get USB/DC IRQ GPIO descriptor\n");
+ else
+ gpiod_put(d);
+
+ omap_serial_init();
+ omap1_usb_init(&palmte_usb_config);
+ omap_register_i2c_bus(1, 100, NULL, 0);
+
+ omapfb_set_lcd_config(&palmte_lcd_config);
+ palmte_mmc_init();
+}
+
+MACHINE_START(OMAP_PALMTE, "OMAP310 based Palm Tungsten E")
+ .atag_offset = 0x100,
+ .map_io = omap1_map_io,
+ .init_early = omap1_init_early,
+ .init_irq = omap1_init_irq,
+ .init_machine = omap_palmte_init,
+ .init_late = omap1_init_late,
+ .init_time = omap1_timer_init,
+ .restart = omap1_restart,
+MACHINE_END
diff --git a/arch/arm/mach-omap1/board-sx1-mmc.c b/arch/arm/mach-omap1/board-sx1-mmc.c
new file mode 100644
index 0000000000..f183a8448a
--- /dev/null
+++ b/arch/arm/mach-omap1/board-sx1-mmc.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * linux/arch/arm/mach-omap1/board-sx1-mmc.c
+ *
+ * Copyright (C) 2007 Instituto Nokia de Tecnologia - INdT
+ * Author: Carlos Eduardo Aguiar <carlos.aguiar@indt.org.br>
+ *
+ * This code is based on linux/arch/arm/mach-omap1/board-h2-mmc.c, which is:
+ * Copyright (C) 2007 Instituto Nokia de Tecnologia - INdT
+ */
+
+#include <linux/platform_device.h>
+
+#include "hardware.h"
+#include "board-sx1.h"
+#include "mmc.h"
+
+#if IS_ENABLED(CONFIG_MMC_OMAP)
+
+static int mmc_set_power(struct device *dev, int slot, int power_on,
+ int vdd)
+{
+ int err;
+ u8 dat = 0;
+
+ err = sx1_i2c_read_byte(SOFIA_I2C_ADDR, SOFIA_POWER1_REG, &dat);
+ if (err < 0)
+ return err;
+
+ if (power_on)
+ dat |= SOFIA_MMC_POWER;
+ else
+ dat &= ~SOFIA_MMC_POWER;
+
+ return sx1_i2c_write_byte(SOFIA_I2C_ADDR, SOFIA_POWER1_REG, dat);
+}
+
+/* Cover switch is at OMAP_MPUIO(3) */
+static struct omap_mmc_platform_data mmc1_data = {
+ .nr_slots = 1,
+ .slots[0] = {
+ .set_power = mmc_set_power,
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .name = "mmcblk",
+ },
+};
+
+static struct omap_mmc_platform_data *mmc_data[OMAP15XX_NR_MMC];
+
+void __init sx1_mmc_init(void)
+{
+ mmc_data[0] = &mmc1_data;
+ omap1_init_mmc(mmc_data, OMAP15XX_NR_MMC);
+}
+
+#else
+
+void __init sx1_mmc_init(void)
+{
+}
+
+#endif
diff --git a/arch/arm/mach-omap1/board-sx1.c b/arch/arm/mach-omap1/board-sx1.c
new file mode 100644
index 0000000000..b869c7ba1a
--- /dev/null
+++ b/arch/arm/mach-omap1/board-sx1.c
@@ -0,0 +1,371 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+* linux/arch/arm/mach-omap1/board-sx1.c
+*
+* Modified from board-generic.c
+*
+* Support for the Siemens SX1 mobile phone.
+*
+* Original version : Vladimir Ananiev (Vovan888-at-gmail com)
+*
+* Maintainters : Vladimir Ananiev (aka Vovan888), Sergge
+* oslik.ru
+*/
+#include <linux/gpio/machine.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/notifier.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/omapfb.h>
+#include <linux/platform_data/keypad-omap.h>
+#include <linux/omap-dma.h>
+#include "tc.h"
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include "flash.h"
+#include "mux.h"
+#include "board-sx1.h"
+#include "hardware.h"
+#include "usb.h"
+#include "common.h"
+
+/* Write to I2C device */
+int sx1_i2c_write_byte(u8 devaddr, u8 regoffset, u8 value)
+{
+ struct i2c_adapter *adap;
+ int err;
+ struct i2c_msg msg[1];
+ unsigned char data[2];
+
+ adap = i2c_get_adapter(0);
+ if (!adap)
+ return -ENODEV;
+ msg->addr = devaddr; /* I2C address of chip */
+ msg->flags = 0;
+ msg->len = 2;
+ msg->buf = data;
+ data[0] = regoffset; /* register num */
+ data[1] = value; /* register data */
+ err = i2c_transfer(adap, msg, 1);
+ i2c_put_adapter(adap);
+ if (err >= 0)
+ return 0;
+ return err;
+}
+
+/* Read from I2C device */
+int sx1_i2c_read_byte(u8 devaddr, u8 regoffset, u8 *value)
+{
+ struct i2c_adapter *adap;
+ int err;
+ struct i2c_msg msg[1];
+ unsigned char data[2];
+
+ adap = i2c_get_adapter(0);
+ if (!adap)
+ return -ENODEV;
+
+ msg->addr = devaddr; /* I2C address of chip */
+ msg->flags = 0;
+ msg->len = 1;
+ msg->buf = data;
+ data[0] = regoffset; /* register num */
+ err = i2c_transfer(adap, msg, 1);
+
+ msg->addr = devaddr; /* I2C address */
+ msg->flags = I2C_M_RD;
+ msg->len = 1;
+ msg->buf = data;
+ err = i2c_transfer(adap, msg, 1);
+ *value = data[0];
+ i2c_put_adapter(adap);
+
+ if (err >= 0)
+ return 0;
+ return err;
+}
+/* set keyboard backlight intensity */
+int sx1_setkeylight(u8 keylight)
+{
+ if (keylight > SOFIA_MAX_LIGHT_VAL)
+ keylight = SOFIA_MAX_LIGHT_VAL;
+ return sx1_i2c_write_byte(SOFIA_I2C_ADDR, SOFIA_KEYLIGHT_REG, keylight);
+}
+/* get current keylight intensity */
+int sx1_getkeylight(u8 * keylight)
+{
+ return sx1_i2c_read_byte(SOFIA_I2C_ADDR, SOFIA_KEYLIGHT_REG, keylight);
+}
+/* set LCD backlight intensity */
+int sx1_setbacklight(u8 backlight)
+{
+ if (backlight > SOFIA_MAX_LIGHT_VAL)
+ backlight = SOFIA_MAX_LIGHT_VAL;
+ return sx1_i2c_write_byte(SOFIA_I2C_ADDR, SOFIA_BACKLIGHT_REG,
+ backlight);
+}
+/* get current LCD backlight intensity */
+int sx1_getbacklight (u8 * backlight)
+{
+ return sx1_i2c_read_byte(SOFIA_I2C_ADDR, SOFIA_BACKLIGHT_REG,
+ backlight);
+}
+/* set LCD backlight power on/off */
+int sx1_setmmipower(u8 onoff)
+{
+ int err;
+ u8 dat = 0;
+ err = sx1_i2c_read_byte(SOFIA_I2C_ADDR, SOFIA_POWER1_REG, &dat);
+ if (err < 0)
+ return err;
+ if (onoff)
+ dat |= SOFIA_MMILIGHT_POWER;
+ else
+ dat &= ~SOFIA_MMILIGHT_POWER;
+ return sx1_i2c_write_byte(SOFIA_I2C_ADDR, SOFIA_POWER1_REG, dat);
+}
+
+/* set USB power on/off */
+int sx1_setusbpower(u8 onoff)
+{
+ int err;
+ u8 dat = 0;
+ err = sx1_i2c_read_byte(SOFIA_I2C_ADDR, SOFIA_POWER1_REG, &dat);
+ if (err < 0)
+ return err;
+ if (onoff)
+ dat |= SOFIA_USB_POWER;
+ else
+ dat &= ~SOFIA_USB_POWER;
+ return sx1_i2c_write_byte(SOFIA_I2C_ADDR, SOFIA_POWER1_REG, dat);
+}
+
+EXPORT_SYMBOL(sx1_setkeylight);
+EXPORT_SYMBOL(sx1_getkeylight);
+EXPORT_SYMBOL(sx1_setbacklight);
+EXPORT_SYMBOL(sx1_getbacklight);
+EXPORT_SYMBOL(sx1_setmmipower);
+EXPORT_SYMBOL(sx1_setusbpower);
+
+/*----------- Keypad -------------------------*/
+
+static const unsigned int sx1_keymap[] = {
+ KEY(3, 5, GROUP_0 | 117), /* camera Qt::Key_F17 */
+ KEY(4, 0, GROUP_0 | 114), /* voice memo Qt::Key_F14 */
+ KEY(4, 1, GROUP_2 | 114), /* voice memo */
+ KEY(4, 2, GROUP_3 | 114), /* voice memo */
+ KEY(0, 0, GROUP_1 | KEY_F12), /* red button Qt::Key_Hangup */
+ KEY(3, 4, GROUP_1 | KEY_LEFT),
+ KEY(3, 2, GROUP_1 | KEY_DOWN),
+ KEY(3, 1, GROUP_1 | KEY_RIGHT),
+ KEY(3, 0, GROUP_1 | KEY_UP),
+ KEY(3, 3, GROUP_1 | KEY_POWER), /* joystick press or Qt::Key_Select */
+ KEY(0, 5, GROUP_1 | KEY_1),
+ KEY(0, 4, GROUP_1 | KEY_2),
+ KEY(0, 3, GROUP_1 | KEY_3),
+ KEY(4, 3, GROUP_1 | KEY_4),
+ KEY(4, 4, GROUP_1 | KEY_5),
+ KEY(4, 5, GROUP_1 | KEY_KPASTERISK),/* "*" */
+ KEY(1, 4, GROUP_1 | KEY_6),
+ KEY(1, 5, GROUP_1 | KEY_7),
+ KEY(1, 3, GROUP_1 | KEY_8),
+ KEY(2, 3, GROUP_1 | KEY_9),
+ KEY(2, 5, GROUP_1 | KEY_0),
+ KEY(2, 4, GROUP_1 | 113), /* # F13 Toggle input method Qt::Key_F13 */
+ KEY(1, 0, GROUP_1 | KEY_F11), /* green button Qt::Key_Call */
+ KEY(2, 1, GROUP_1 | KEY_YEN), /* left soft Qt::Key_Context1 */
+ KEY(2, 2, GROUP_1 | KEY_F8), /* right soft Qt::Key_Back */
+ KEY(1, 2, GROUP_1 | KEY_LEFTSHIFT), /* shift */
+ KEY(1, 1, GROUP_1 | KEY_BACKSPACE), /* C (clear) */
+ KEY(2, 0, GROUP_1 | KEY_F7), /* menu Qt::Key_Menu */
+};
+
+static struct resource sx1_kp_resources[] = {
+ [0] = {
+ .start = INT_KEYBOARD,
+ .end = INT_KEYBOARD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static const struct matrix_keymap_data sx1_keymap_data = {
+ .keymap = sx1_keymap,
+ .keymap_size = ARRAY_SIZE(sx1_keymap),
+};
+
+static struct omap_kp_platform_data sx1_kp_data = {
+ .rows = 6,
+ .cols = 6,
+ .keymap_data = &sx1_keymap_data,
+ .delay = 80,
+};
+
+static struct platform_device sx1_kp_device = {
+ .name = "omap-keypad",
+ .id = -1,
+ .dev = {
+ .platform_data = &sx1_kp_data,
+ },
+ .num_resources = ARRAY_SIZE(sx1_kp_resources),
+ .resource = sx1_kp_resources,
+};
+
+/*----------- MTD -------------------------*/
+
+static struct mtd_partition sx1_partitions[] = {
+ /* bootloader (U-Boot, etc) in first sector */
+ {
+ .name = "bootloader",
+ .offset = 0x01800000,
+ .size = SZ_128K,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ },
+ /* bootloader params in the next sector */
+ {
+ .name = "params",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_128K,
+ .mask_flags = 0,
+ },
+ /* kernel */
+ {
+ .name = "kernel",
+ .offset = MTDPART_OFS_APPEND,
+ .size = SZ_2M - 2 * SZ_128K,
+ .mask_flags = 0
+ },
+ /* file system */
+ {
+ .name = "filesystem",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+ .mask_flags = 0
+ }
+};
+
+static struct physmap_flash_data sx1_flash_data = {
+ .width = 2,
+ .set_vpp = omap1_set_vpp,
+ .parts = sx1_partitions,
+ .nr_parts = ARRAY_SIZE(sx1_partitions),
+};
+
+/* MTD Intel 4000 flash - new flashes */
+static struct resource sx1_new_flash_resource = {
+ .start = OMAP_CS0_PHYS,
+ .end = OMAP_CS0_PHYS + SZ_32M - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device sx1_flash_device = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &sx1_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &sx1_new_flash_resource,
+};
+
+/*----------- USB -------------------------*/
+
+static struct omap_usb_config sx1_usb_config __initdata = {
+ .otg = 0,
+ .register_dev = 1,
+ .register_host = 0,
+ .hmc_mode = 0,
+ .pins[0] = 2,
+ .pins[1] = 0,
+ .pins[2] = 0,
+};
+
+/*----------- LCD -------------------------*/
+
+static const struct omap_lcd_config sx1_lcd_config __initconst = {
+ .ctrl_name = "internal",
+};
+
+/*-----------------------------------------*/
+static struct platform_device *sx1_devices[] __initdata = {
+ &sx1_flash_device,
+ &sx1_kp_device,
+};
+
+/*-----------------------------------------*/
+
+static struct gpiod_lookup_table sx1_gpio_table = {
+ .dev_id = NULL,
+ .table = {
+ GPIO_LOOKUP("gpio-0-15", 1, "irda_off",
+ GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("gpio-0-15", 11, "switch",
+ GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("gpio-0-15", 15, "usb_on",
+ GPIO_ACTIVE_HIGH),
+ { }
+ },
+};
+
+static void __init omap_sx1_init(void)
+{
+ struct gpio_desc *d;
+
+ /* mux pins for uarts */
+ omap_cfg_reg(UART1_TX);
+ omap_cfg_reg(UART1_RTS);
+ omap_cfg_reg(UART2_TX);
+ omap_cfg_reg(UART2_RTS);
+ omap_cfg_reg(UART3_TX);
+ omap_cfg_reg(UART3_RX);
+
+ platform_add_devices(sx1_devices, ARRAY_SIZE(sx1_devices));
+
+ omap_serial_init();
+ omap_register_i2c_bus(1, 100, NULL, 0);
+ omap1_usb_init(&sx1_usb_config);
+ sx1_mmc_init();
+ gpiod_add_lookup_table(&sx1_gpio_table);
+
+ /* turn on USB power */
+ /* sx1_setusbpower(1); can't do it here because i2c is not ready */
+ d = gpiod_get(NULL, "irda_off", GPIOD_OUT_HIGH);
+ if (IS_ERR(d))
+ pr_err("Unable to get IRDA OFF GPIO descriptor\n");
+ else
+ gpiod_put(d);
+ d = gpiod_get(NULL, "switch", GPIOD_OUT_LOW);
+ if (IS_ERR(d))
+ pr_err("Unable to get SWITCH GPIO descriptor\n");
+ else
+ gpiod_put(d);
+ d = gpiod_get(NULL, "usb_on", GPIOD_OUT_LOW);
+ if (IS_ERR(d))
+ pr_err("Unable to get USB ON GPIO descriptor\n");
+ else
+ gpiod_put(d);
+
+ omapfb_set_lcd_config(&sx1_lcd_config);
+}
+
+MACHINE_START(SX1, "OMAP310 based Siemens SX1")
+ .atag_offset = 0x100,
+ .map_io = omap1_map_io,
+ .init_early = omap1_init_early,
+ .init_irq = omap1_init_irq,
+ .init_machine = omap_sx1_init,
+ .init_late = omap1_init_late,
+ .init_time = omap1_timer_init,
+ .restart = omap1_restart,
+MACHINE_END
diff --git a/arch/arm/mach-omap1/board-sx1.h b/arch/arm/mach-omap1/board-sx1.h
new file mode 100644
index 0000000000..fafe54a2e4
--- /dev/null
+++ b/arch/arm/mach-omap1/board-sx1.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Siemens SX1 board definitions
+ *
+ * Copyright: Vovan888 at gmail com
+ */
+
+#ifndef __ASM_ARCH_SX1_I2C_CHIPS_H
+#define __ASM_ARCH_SX1_I2C_CHIPS_H
+
+#define SOFIA_MAX_LIGHT_VAL 0x2B
+
+#define SOFIA_I2C_ADDR 0x32
+/* Sofia reg 3 bits masks */
+#define SOFIA_POWER1_REG 0x03
+
+#define SOFIA_USB_POWER 0x01
+#define SOFIA_MMC_POWER 0x04
+#define SOFIA_BLUETOOTH_POWER 0x08
+#define SOFIA_MMILIGHT_POWER 0x20
+
+#define SOFIA_POWER2_REG 0x04
+#define SOFIA_BACKLIGHT_REG 0x06
+#define SOFIA_KEYLIGHT_REG 0x07
+#define SOFIA_DIMMING_REG 0x09
+
+
+/* Function Prototypes for SX1 devices control on I2C bus */
+
+int sx1_setbacklight(u8 backlight);
+int sx1_getbacklight(u8 *backlight);
+int sx1_setkeylight(u8 keylight);
+int sx1_getkeylight(u8 *keylight);
+
+int sx1_setmmipower(u8 onoff);
+int sx1_setusbpower(u8 onoff);
+int sx1_i2c_read_byte(u8 devaddr, u8 regoffset, u8 *value);
+int sx1_i2c_write_byte(u8 devaddr, u8 regoffset, u8 value);
+
+/* MMC prototypes */
+
+extern void sx1_mmc_init(void);
+extern void sx1_mmc_slot_cover_handler(void *arg, int state);
+
+#endif /* __ASM_ARCH_SX1_I2C_CHIPS_H */
diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c
new file mode 100644
index 0000000000..83381e23fa
--- /dev/null
+++ b/arch/arm/mach-omap1/clock.c
@@ -0,0 +1,840 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * linux/arch/arm/mach-omap1/clock.c
+ *
+ * Copyright (C) 2004 - 2005, 2009-2010 Nokia Corporation
+ * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ *
+ * Modified to use omap shared clock framework by
+ * Tony Lindgren <tony@atomide.com>
+ */
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/soc/ti/omap1-io.h>
+#include <linux/spinlock.h>
+
+#include <asm/mach-types.h>
+
+#include "hardware.h"
+#include "soc.h"
+#include "iomap.h"
+#include "clock.h"
+#include "opp.h"
+#include "sram.h"
+
+__u32 arm_idlect1_mask;
+/* provide direct internal access (not via clk API) to some clocks */
+struct omap1_clk *api_ck_p, *ck_dpll1_p, *ck_ref_p;
+
+/* protect registeres shared among clk_enable/disable() and clk_set_rate() operations */
+static DEFINE_SPINLOCK(arm_ckctl_lock);
+static DEFINE_SPINLOCK(arm_idlect2_lock);
+static DEFINE_SPINLOCK(mod_conf_ctrl_0_lock);
+static DEFINE_SPINLOCK(mod_conf_ctrl_1_lock);
+static DEFINE_SPINLOCK(swd_clk_div_ctrl_sel_lock);
+
+/*
+ * Omap1 specific clock functions
+ */
+
+unsigned long omap1_uart_recalc(struct omap1_clk *clk, unsigned long p_rate)
+{
+ unsigned int val = __raw_readl(clk->enable_reg);
+ return val & 1 << clk->enable_bit ? 48000000 : 12000000;
+}
+
+unsigned long omap1_sossi_recalc(struct omap1_clk *clk, unsigned long p_rate)
+{
+ u32 div = omap_readl(MOD_CONF_CTRL_1);
+
+ div = (div >> 17) & 0x7;
+ div++;
+
+ return p_rate / div;
+}
+
+static void omap1_clk_allow_idle(struct omap1_clk *clk)
+{
+ struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk;
+
+ if (!(clk->flags & CLOCK_IDLE_CONTROL))
+ return;
+
+ if (iclk->no_idle_count > 0 && !(--iclk->no_idle_count))
+ arm_idlect1_mask |= 1 << iclk->idlect_shift;
+}
+
+static void omap1_clk_deny_idle(struct omap1_clk *clk)
+{
+ struct arm_idlect1_clk * iclk = (struct arm_idlect1_clk *)clk;
+
+ if (!(clk->flags & CLOCK_IDLE_CONTROL))
+ return;
+
+ if (iclk->no_idle_count++ == 0)
+ arm_idlect1_mask &= ~(1 << iclk->idlect_shift);
+}
+
+static __u16 verify_ckctl_value(__u16 newval)
+{
+ /* This function checks for following limitations set
+ * by the hardware (all conditions must be true):
+ * DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2
+ * ARM_CK >= TC_CK
+ * DSP_CK >= TC_CK
+ * DSPMMU_CK >= TC_CK
+ *
+ * In addition following rules are enforced:
+ * LCD_CK <= TC_CK
+ * ARMPER_CK <= TC_CK
+ *
+ * However, maximum frequencies are not checked for!
+ */
+ __u8 per_exp;
+ __u8 lcd_exp;
+ __u8 arm_exp;
+ __u8 dsp_exp;
+ __u8 tc_exp;
+ __u8 dspmmu_exp;
+
+ per_exp = (newval >> CKCTL_PERDIV_OFFSET) & 3;
+ lcd_exp = (newval >> CKCTL_LCDDIV_OFFSET) & 3;
+ arm_exp = (newval >> CKCTL_ARMDIV_OFFSET) & 3;
+ dsp_exp = (newval >> CKCTL_DSPDIV_OFFSET) & 3;
+ tc_exp = (newval >> CKCTL_TCDIV_OFFSET) & 3;
+ dspmmu_exp = (newval >> CKCTL_DSPMMUDIV_OFFSET) & 3;
+
+ if (dspmmu_exp < dsp_exp)
+ dspmmu_exp = dsp_exp;
+ if (dspmmu_exp > dsp_exp+1)
+ dspmmu_exp = dsp_exp+1;
+ if (tc_exp < arm_exp)
+ tc_exp = arm_exp;
+ if (tc_exp < dspmmu_exp)
+ tc_exp = dspmmu_exp;
+ if (tc_exp > lcd_exp)
+ lcd_exp = tc_exp;
+ if (tc_exp > per_exp)
+ per_exp = tc_exp;
+
+ newval &= 0xf000;
+ newval |= per_exp << CKCTL_PERDIV_OFFSET;
+ newval |= lcd_exp << CKCTL_LCDDIV_OFFSET;
+ newval |= arm_exp << CKCTL_ARMDIV_OFFSET;
+ newval |= dsp_exp << CKCTL_DSPDIV_OFFSET;
+ newval |= tc_exp << CKCTL_TCDIV_OFFSET;
+ newval |= dspmmu_exp << CKCTL_DSPMMUDIV_OFFSET;
+
+ return newval;
+}
+
+static int calc_dsor_exp(unsigned long rate, unsigned long realrate)
+{
+ /* Note: If target frequency is too low, this function will return 4,
+ * which is invalid value. Caller must check for this value and act
+ * accordingly.
+ *
+ * Note: This function does not check for following limitations set
+ * by the hardware (all conditions must be true):
+ * DSPMMU_CK == DSP_CK or DSPMMU_CK == DSP_CK/2
+ * ARM_CK >= TC_CK
+ * DSP_CK >= TC_CK
+ * DSPMMU_CK >= TC_CK
+ */
+ unsigned dsor_exp;
+
+ if (unlikely(realrate == 0))
+ return -EIO;
+
+ for (dsor_exp=0; dsor_exp<4; dsor_exp++) {
+ if (realrate <= rate)
+ break;
+
+ realrate /= 2;
+ }
+
+ return dsor_exp;
+}
+
+unsigned long omap1_ckctl_recalc(struct omap1_clk *clk, unsigned long p_rate)
+{
+ /* Calculate divisor encoded as 2-bit exponent */
+ int dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
+
+ /* update locally maintained rate, required by arm_ck for omap1_show_rates() */
+ clk->rate = p_rate / dsor;
+ return clk->rate;
+}
+
+static int omap1_clk_is_enabled(struct clk_hw *hw)
+{
+ struct omap1_clk *clk = to_omap1_clk(hw);
+ bool api_ck_was_enabled = true;
+ __u32 regval32;
+ int ret;
+
+ if (!clk->ops) /* no gate -- always enabled */
+ return 1;
+
+ if (clk->ops == &clkops_dspck) {
+ api_ck_was_enabled = omap1_clk_is_enabled(&api_ck_p->hw);
+ if (!api_ck_was_enabled)
+ if (api_ck_p->ops->enable(api_ck_p) < 0)
+ return 0;
+ }
+
+ if (clk->flags & ENABLE_REG_32BIT)
+ regval32 = __raw_readl(clk->enable_reg);
+ else
+ regval32 = __raw_readw(clk->enable_reg);
+
+ ret = regval32 & (1 << clk->enable_bit);
+
+ if (!api_ck_was_enabled)
+ api_ck_p->ops->disable(api_ck_p);
+
+ return ret;
+}
+
+
+unsigned long omap1_ckctl_recalc_dsp_domain(struct omap1_clk *clk, unsigned long p_rate)
+{
+ bool api_ck_was_enabled;
+ int dsor;
+
+ /* Calculate divisor encoded as 2-bit exponent
+ *
+ * The clock control bits are in DSP domain,
+ * so api_ck is needed for access.
+ * Note that DSP_CKCTL virt addr = phys addr, so
+ * we must use __raw_readw() instead of omap_readw().
+ */
+ api_ck_was_enabled = omap1_clk_is_enabled(&api_ck_p->hw);
+ if (!api_ck_was_enabled)
+ api_ck_p->ops->enable(api_ck_p);
+ dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset));
+ if (!api_ck_was_enabled)
+ api_ck_p->ops->disable(api_ck_p);
+
+ return p_rate / dsor;
+}
+
+/* MPU virtual clock functions */
+int omap1_select_table_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate)
+{
+ /* Find the highest supported frequency <= rate and switch to it */
+ struct mpu_rate * ptr;
+ unsigned long ref_rate;
+
+ ref_rate = ck_ref_p->rate;
+
+ for (ptr = omap1_rate_table; ptr->rate; ptr++) {
+ if (!(ptr->flags & cpu_mask))
+ continue;
+
+ if (ptr->xtal != ref_rate)
+ continue;
+
+ /* Can check only after xtal frequency check */
+ if (ptr->rate <= rate)
+ break;
+ }
+
+ if (!ptr->rate)
+ return -EINVAL;
+
+ /*
+ * In most cases we should not need to reprogram DPLL.
+ * Reprogramming the DPLL is tricky, it must be done from SRAM.
+ */
+ omap_sram_reprogram_clock(ptr->dpllctl_val, ptr->ckctl_val);
+
+ /* XXX Do we need to recalculate the tree below DPLL1 at this point? */
+ ck_dpll1_p->rate = ptr->pll_rate;
+
+ return 0;
+}
+
+int omap1_clk_set_rate_dsp_domain(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate)
+{
+ int dsor_exp;
+ u16 regval;
+
+ dsor_exp = calc_dsor_exp(rate, p_rate);
+ if (dsor_exp > 3)
+ dsor_exp = -EINVAL;
+ if (dsor_exp < 0)
+ return dsor_exp;
+
+ regval = __raw_readw(DSP_CKCTL);
+ regval &= ~(3 << clk->rate_offset);
+ regval |= dsor_exp << clk->rate_offset;
+ __raw_writew(regval, DSP_CKCTL);
+ clk->rate = p_rate / (1 << dsor_exp);
+
+ return 0;
+}
+
+long omap1_clk_round_rate_ckctl_arm(struct omap1_clk *clk, unsigned long rate,
+ unsigned long *p_rate)
+{
+ int dsor_exp = calc_dsor_exp(rate, *p_rate);
+
+ if (dsor_exp < 0)
+ return dsor_exp;
+ if (dsor_exp > 3)
+ dsor_exp = 3;
+ return *p_rate / (1 << dsor_exp);
+}
+
+int omap1_clk_set_rate_ckctl_arm(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate)
+{
+ unsigned long flags;
+ int dsor_exp;
+ u16 regval;
+
+ dsor_exp = calc_dsor_exp(rate, p_rate);
+ if (dsor_exp > 3)
+ dsor_exp = -EINVAL;
+ if (dsor_exp < 0)
+ return dsor_exp;
+
+ /* protect ARM_CKCTL register from concurrent access via clk_enable/disable() */
+ spin_lock_irqsave(&arm_ckctl_lock, flags);
+
+ regval = omap_readw(ARM_CKCTL);
+ regval &= ~(3 << clk->rate_offset);
+ regval |= dsor_exp << clk->rate_offset;
+ regval = verify_ckctl_value(regval);
+ omap_writew(regval, ARM_CKCTL);
+ clk->rate = p_rate / (1 << dsor_exp);
+
+ spin_unlock_irqrestore(&arm_ckctl_lock, flags);
+
+ return 0;
+}
+
+long omap1_round_to_table_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate)
+{
+ /* Find the highest supported frequency <= rate */
+ struct mpu_rate * ptr;
+ long highest_rate;
+ unsigned long ref_rate;
+
+ ref_rate = ck_ref_p->rate;
+
+ highest_rate = -EINVAL;
+
+ for (ptr = omap1_rate_table; ptr->rate; ptr++) {
+ if (!(ptr->flags & cpu_mask))
+ continue;
+
+ if (ptr->xtal != ref_rate)
+ continue;
+
+ highest_rate = ptr->rate;
+
+ /* Can check only after xtal frequency check */
+ if (ptr->rate <= rate)
+ break;
+ }
+
+ return highest_rate;
+}
+
+static unsigned calc_ext_dsor(unsigned long rate)
+{
+ unsigned dsor;
+
+ /* MCLK and BCLK divisor selection is not linear:
+ * freq = 96MHz / dsor
+ *
+ * RATIO_SEL range: dsor <-> RATIO_SEL
+ * 0..6: (RATIO_SEL+2) <-> (dsor-2)
+ * 6..48: (8+(RATIO_SEL-6)*2) <-> ((dsor-8)/2+6)
+ * Minimum dsor is 2 and maximum is 96. Odd divisors starting from 9
+ * can not be used.
+ */
+ for (dsor = 2; dsor < 96; ++dsor) {
+ if ((dsor & 1) && dsor > 8)
+ continue;
+ if (rate >= 96000000 / dsor)
+ break;
+ }
+ return dsor;
+}
+
+/* XXX Only needed on 1510 */
+long omap1_round_uart_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate)
+{
+ return rate > 24000000 ? 48000000 : 12000000;
+}
+
+int omap1_set_uart_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate)
+{
+ unsigned long flags;
+ unsigned int val;
+
+ if (rate == 12000000)
+ val = 0;
+ else if (rate == 48000000)
+ val = 1 << clk->enable_bit;
+ else
+ return -EINVAL;
+
+ /* protect MOD_CONF_CTRL_0 register from concurrent access via clk_enable/disable() */
+ spin_lock_irqsave(&mod_conf_ctrl_0_lock, flags);
+
+ val |= __raw_readl(clk->enable_reg) & ~(1 << clk->enable_bit);
+ __raw_writel(val, clk->enable_reg);
+
+ spin_unlock_irqrestore(&mod_conf_ctrl_0_lock, flags);
+
+ clk->rate = rate;
+
+ return 0;
+}
+
+/* External clock (MCLK & BCLK) functions */
+int omap1_set_ext_clk_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate)
+{
+ unsigned long flags;
+ unsigned dsor;
+ __u16 ratio_bits;
+
+ dsor = calc_ext_dsor(rate);
+ clk->rate = 96000000 / dsor;
+ if (dsor > 8)
+ ratio_bits = ((dsor - 8) / 2 + 6) << 2;
+ else
+ ratio_bits = (dsor - 2) << 2;
+
+ /* protect SWD_CLK_DIV_CTRL_SEL register from concurrent access via clk_enable/disable() */
+ spin_lock_irqsave(&swd_clk_div_ctrl_sel_lock, flags);
+
+ ratio_bits |= __raw_readw(clk->enable_reg) & ~0xfd;
+ __raw_writew(ratio_bits, clk->enable_reg);
+
+ spin_unlock_irqrestore(&swd_clk_div_ctrl_sel_lock, flags);
+
+ return 0;
+}
+
+static int calc_div_sossi(unsigned long rate, unsigned long p_rate)
+{
+ int div;
+
+ /* Round towards slower frequency */
+ div = (p_rate + rate - 1) / rate;
+
+ return --div;
+}
+
+long omap1_round_sossi_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate)
+{
+ int div;
+
+ div = calc_div_sossi(rate, *p_rate);
+ if (div < 0)
+ div = 0;
+ else if (div > 7)
+ div = 7;
+
+ return *p_rate / (div + 1);
+}
+
+int omap1_set_sossi_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate)
+{
+ unsigned long flags;
+ u32 l;
+ int div;
+
+ div = calc_div_sossi(rate, p_rate);
+ if (div < 0 || div > 7)
+ return -EINVAL;
+
+ /* protect MOD_CONF_CTRL_1 register from concurrent access via clk_enable/disable() */
+ spin_lock_irqsave(&mod_conf_ctrl_1_lock, flags);
+
+ l = omap_readl(MOD_CONF_CTRL_1);
+ l &= ~(7 << 17);
+ l |= div << 17;
+ omap_writel(l, MOD_CONF_CTRL_1);
+
+ clk->rate = p_rate / (div + 1);
+
+ spin_unlock_irqrestore(&mod_conf_ctrl_1_lock, flags);
+
+ return 0;
+}
+
+long omap1_round_ext_clk_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate)
+{
+ return 96000000 / calc_ext_dsor(rate);
+}
+
+int omap1_init_ext_clk(struct omap1_clk *clk)
+{
+ unsigned dsor;
+ __u16 ratio_bits;
+
+ /* Determine current rate and ensure clock is based on 96MHz APLL */
+ ratio_bits = __raw_readw(clk->enable_reg) & ~1;
+ __raw_writew(ratio_bits, clk->enable_reg);
+
+ ratio_bits = (ratio_bits & 0xfc) >> 2;
+ if (ratio_bits > 6)
+ dsor = (ratio_bits - 6) * 2 + 8;
+ else
+ dsor = ratio_bits + 2;
+
+ clk-> rate = 96000000 / dsor;
+
+ return 0;
+}
+
+static int omap1_clk_enable(struct clk_hw *hw)
+{
+ struct omap1_clk *clk = to_omap1_clk(hw), *parent = to_omap1_clk(clk_hw_get_parent(hw));
+ int ret = 0;
+
+ if (parent && clk->flags & CLOCK_NO_IDLE_PARENT)
+ omap1_clk_deny_idle(parent);
+
+ if (clk->ops && !(WARN_ON(!clk->ops->enable)))
+ ret = clk->ops->enable(clk);
+
+ return ret;
+}
+
+static void omap1_clk_disable(struct clk_hw *hw)
+{
+ struct omap1_clk *clk = to_omap1_clk(hw), *parent = to_omap1_clk(clk_hw_get_parent(hw));
+
+ if (clk->ops && !(WARN_ON(!clk->ops->disable)))
+ clk->ops->disable(clk);
+
+ if (likely(parent) && clk->flags & CLOCK_NO_IDLE_PARENT)
+ omap1_clk_allow_idle(parent);
+}
+
+static int omap1_clk_enable_generic(struct omap1_clk *clk)
+{
+ unsigned long flags;
+ __u16 regval16;
+ __u32 regval32;
+
+ if (unlikely(clk->enable_reg == NULL)) {
+ printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
+ clk_hw_get_name(&clk->hw));
+ return -EINVAL;
+ }
+
+ /* protect clk->enable_reg from concurrent access via clk_set_rate() */
+ if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_CKCTL))
+ spin_lock_irqsave(&arm_ckctl_lock, flags);
+ else if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_IDLECT2))
+ spin_lock_irqsave(&arm_idlect2_lock, flags);
+ else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0))
+ spin_lock_irqsave(&mod_conf_ctrl_0_lock, flags);
+ else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1))
+ spin_lock_irqsave(&mod_conf_ctrl_1_lock, flags);
+ else if (clk->enable_reg == OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL))
+ spin_lock_irqsave(&swd_clk_div_ctrl_sel_lock, flags);
+
+ if (clk->flags & ENABLE_REG_32BIT) {
+ regval32 = __raw_readl(clk->enable_reg);
+ regval32 |= (1 << clk->enable_bit);
+ __raw_writel(regval32, clk->enable_reg);
+ } else {
+ regval16 = __raw_readw(clk->enable_reg);
+ regval16 |= (1 << clk->enable_bit);
+ __raw_writew(regval16, clk->enable_reg);
+ }
+
+ if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_CKCTL))
+ spin_unlock_irqrestore(&arm_ckctl_lock, flags);
+ else if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_IDLECT2))
+ spin_unlock_irqrestore(&arm_idlect2_lock, flags);
+ else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0))
+ spin_unlock_irqrestore(&mod_conf_ctrl_0_lock, flags);
+ else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1))
+ spin_unlock_irqrestore(&mod_conf_ctrl_1_lock, flags);
+ else if (clk->enable_reg == OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL))
+ spin_unlock_irqrestore(&swd_clk_div_ctrl_sel_lock, flags);
+
+ return 0;
+}
+
+static void omap1_clk_disable_generic(struct omap1_clk *clk)
+{
+ unsigned long flags;
+ __u16 regval16;
+ __u32 regval32;
+
+ if (clk->enable_reg == NULL)
+ return;
+
+ /* protect clk->enable_reg from concurrent access via clk_set_rate() */
+ if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_CKCTL))
+ spin_lock_irqsave(&arm_ckctl_lock, flags);
+ else if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_IDLECT2))
+ spin_lock_irqsave(&arm_idlect2_lock, flags);
+ else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0))
+ spin_lock_irqsave(&mod_conf_ctrl_0_lock, flags);
+ else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1))
+ spin_lock_irqsave(&mod_conf_ctrl_1_lock, flags);
+ else if (clk->enable_reg == OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL))
+ spin_lock_irqsave(&swd_clk_div_ctrl_sel_lock, flags);
+
+ if (clk->flags & ENABLE_REG_32BIT) {
+ regval32 = __raw_readl(clk->enable_reg);
+ regval32 &= ~(1 << clk->enable_bit);
+ __raw_writel(regval32, clk->enable_reg);
+ } else {
+ regval16 = __raw_readw(clk->enable_reg);
+ regval16 &= ~(1 << clk->enable_bit);
+ __raw_writew(regval16, clk->enable_reg);
+ }
+
+ if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_CKCTL))
+ spin_unlock_irqrestore(&arm_ckctl_lock, flags);
+ else if (clk->enable_reg == OMAP1_IO_ADDRESS(ARM_IDLECT2))
+ spin_unlock_irqrestore(&arm_idlect2_lock, flags);
+ else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0))
+ spin_unlock_irqrestore(&mod_conf_ctrl_0_lock, flags);
+ else if (clk->enable_reg == OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1))
+ spin_unlock_irqrestore(&mod_conf_ctrl_1_lock, flags);
+ else if (clk->enable_reg == OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL))
+ spin_unlock_irqrestore(&swd_clk_div_ctrl_sel_lock, flags);
+}
+
+const struct clkops clkops_generic = {
+ .enable = omap1_clk_enable_generic,
+ .disable = omap1_clk_disable_generic,
+};
+
+static int omap1_clk_enable_dsp_domain(struct omap1_clk *clk)
+{
+ bool api_ck_was_enabled;
+ int retval = 0;
+
+ api_ck_was_enabled = omap1_clk_is_enabled(&api_ck_p->hw);
+ if (!api_ck_was_enabled)
+ retval = api_ck_p->ops->enable(api_ck_p);
+
+ if (!retval) {
+ retval = omap1_clk_enable_generic(clk);
+
+ if (!api_ck_was_enabled)
+ api_ck_p->ops->disable(api_ck_p);
+ }
+
+ return retval;
+}
+
+static void omap1_clk_disable_dsp_domain(struct omap1_clk *clk)
+{
+ bool api_ck_was_enabled;
+
+ api_ck_was_enabled = omap1_clk_is_enabled(&api_ck_p->hw);
+ if (!api_ck_was_enabled)
+ if (api_ck_p->ops->enable(api_ck_p) < 0)
+ return;
+
+ omap1_clk_disable_generic(clk);
+
+ if (!api_ck_was_enabled)
+ api_ck_p->ops->disable(api_ck_p);
+}
+
+const struct clkops clkops_dspck = {
+ .enable = omap1_clk_enable_dsp_domain,
+ .disable = omap1_clk_disable_dsp_domain,
+};
+
+/* XXX SYSC register handling does not belong in the clock framework */
+static int omap1_clk_enable_uart_functional_16xx(struct omap1_clk *clk)
+{
+ int ret;
+ struct uart_clk *uclk;
+
+ ret = omap1_clk_enable_generic(clk);
+ if (ret == 0) {
+ /* Set smart idle acknowledgement mode */
+ uclk = (struct uart_clk *)clk;
+ omap_writeb((omap_readb(uclk->sysc_addr) & ~0x10) | 8,
+ uclk->sysc_addr);
+ }
+
+ return ret;
+}
+
+/* XXX SYSC register handling does not belong in the clock framework */
+static void omap1_clk_disable_uart_functional_16xx(struct omap1_clk *clk)
+{
+ struct uart_clk *uclk;
+
+ /* Set force idle acknowledgement mode */
+ uclk = (struct uart_clk *)clk;
+ omap_writeb((omap_readb(uclk->sysc_addr) & ~0x18), uclk->sysc_addr);
+
+ omap1_clk_disable_generic(clk);
+}
+
+/* XXX SYSC register handling does not belong in the clock framework */
+const struct clkops clkops_uart_16xx = {
+ .enable = omap1_clk_enable_uart_functional_16xx,
+ .disable = omap1_clk_disable_uart_functional_16xx,
+};
+
+static unsigned long omap1_clk_recalc_rate(struct clk_hw *hw, unsigned long p_rate)
+{
+ struct omap1_clk *clk = to_omap1_clk(hw);
+
+ if (clk->recalc)
+ return clk->recalc(clk, p_rate);
+
+ return clk->rate;
+}
+
+static long omap1_clk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *p_rate)
+{
+ struct omap1_clk *clk = to_omap1_clk(hw);
+
+ if (clk->round_rate != NULL)
+ return clk->round_rate(clk, rate, p_rate);
+
+ return omap1_clk_recalc_rate(hw, *p_rate);
+}
+
+static int omap1_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long p_rate)
+{
+ struct omap1_clk *clk = to_omap1_clk(hw);
+ int ret = -EINVAL;
+
+ if (clk->set_rate)
+ ret = clk->set_rate(clk, rate, p_rate);
+ return ret;
+}
+
+/*
+ * Omap1 clock reset and init functions
+ */
+
+static int omap1_clk_init_op(struct clk_hw *hw)
+{
+ struct omap1_clk *clk = to_omap1_clk(hw);
+
+ if (clk->init)
+ return clk->init(clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_OMAP_RESET_CLOCKS
+
+static void omap1_clk_disable_unused(struct clk_hw *hw)
+{
+ struct omap1_clk *clk = to_omap1_clk(hw);
+ const char *name = clk_hw_get_name(hw);
+
+ /* Clocks in the DSP domain need api_ck. Just assume bootloader
+ * has not enabled any DSP clocks */
+ if (clk->enable_reg == DSP_IDLECT2) {
+ pr_info("Skipping reset check for DSP domain clock \"%s\"\n", name);
+ return;
+ }
+
+ pr_info("Disabling unused clock \"%s\"... ", name);
+ omap1_clk_disable(hw);
+ printk(" done\n");
+}
+
+#endif
+
+const struct clk_ops omap1_clk_gate_ops = {
+ .enable = omap1_clk_enable,
+ .disable = omap1_clk_disable,
+ .is_enabled = omap1_clk_is_enabled,
+#ifdef CONFIG_OMAP_RESET_CLOCKS
+ .disable_unused = omap1_clk_disable_unused,
+#endif
+};
+
+const struct clk_ops omap1_clk_rate_ops = {
+ .recalc_rate = omap1_clk_recalc_rate,
+ .round_rate = omap1_clk_round_rate,
+ .set_rate = omap1_clk_set_rate,
+ .init = omap1_clk_init_op,
+};
+
+const struct clk_ops omap1_clk_full_ops = {
+ .enable = omap1_clk_enable,
+ .disable = omap1_clk_disable,
+ .is_enabled = omap1_clk_is_enabled,
+#ifdef CONFIG_OMAP_RESET_CLOCKS
+ .disable_unused = omap1_clk_disable_unused,
+#endif
+ .recalc_rate = omap1_clk_recalc_rate,
+ .round_rate = omap1_clk_round_rate,
+ .set_rate = omap1_clk_set_rate,
+ .init = omap1_clk_init_op,
+};
+
+/*
+ * OMAP specific clock functions shared between omap1 and omap2
+ */
+
+/* Used for clocks that always have same value as the parent clock */
+unsigned long followparent_recalc(struct omap1_clk *clk, unsigned long p_rate)
+{
+ return p_rate;
+}
+
+/*
+ * Used for clocks that have the same value as the parent clock,
+ * divided by some factor
+ */
+unsigned long omap_fixed_divisor_recalc(struct omap1_clk *clk, unsigned long p_rate)
+{
+ WARN_ON(!clk->fixed_div);
+
+ return p_rate / clk->fixed_div;
+}
+
+/* Propagate rate to children */
+void propagate_rate(struct omap1_clk *tclk)
+{
+ struct clk *clkp;
+
+ /* depend on CCF ability to recalculate new rates across whole clock subtree */
+ if (WARN_ON(!(clk_hw_get_flags(&tclk->hw) & CLK_GET_RATE_NOCACHE)))
+ return;
+
+ clkp = clk_get_sys(NULL, clk_hw_get_name(&tclk->hw));
+ if (WARN_ON(!clkp))
+ return;
+
+ clk_get_rate(clkp);
+ clk_put(clkp);
+}
+
+const struct clk_ops omap1_clk_null_ops = {
+};
+
+/*
+ * Dummy clock
+ *
+ * Used for clock aliases that are needed on some OMAPs, but not others
+ */
+struct omap1_clk dummy_ck __refdata = {
+ .hw.init = CLK_HW_INIT_NO_PARENT("dummy", &omap1_clk_null_ops, 0),
+};
diff --git a/arch/arm/mach-omap1/clock.h b/arch/arm/mach-omap1/clock.h
new file mode 100644
index 0000000000..16cfb2e86e
--- /dev/null
+++ b/arch/arm/mach-omap1/clock.h
@@ -0,0 +1,195 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * linux/arch/arm/mach-omap1/clock.h
+ *
+ * Copyright (C) 2004 - 2005, 2009 Nokia corporation
+ * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ * Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, Inc
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP1_CLOCK_H
+#define __ARCH_ARM_MACH_OMAP1_CLOCK_H
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+
+struct module;
+struct omap1_clk;
+
+struct omap_clk {
+ u16 cpu;
+ struct clk_lookup lk;
+};
+
+#define CLK(dev, con, ck, cp) \
+ { \
+ .cpu = cp, \
+ .lk = { \
+ .dev_id = dev, \
+ .con_id = con, \
+ .clk_hw = ck, \
+ }, \
+ }
+
+/* Platform flags for the clkdev-OMAP integration code */
+#define CK_310 (1 << 0)
+#define CK_7XX (1 << 1) /* 7xx, 850 */
+#define CK_1510 (1 << 2)
+#define CK_16XX (1 << 3) /* 16xx, 17xx, 5912 */
+#define CK_1710 (1 << 4) /* 1710 extra for rate selection */
+
+/**
+ * struct clkops - some clock function pointers
+ * @enable: fn ptr that enables the current clock in hardware
+ * @disable: fn ptr that enables the current clock in hardware
+ * @allow_idle: fn ptr that enables autoidle for the current clock in hardware
+ */
+struct clkops {
+ int (*enable)(struct omap1_clk *clk);
+ void (*disable)(struct omap1_clk *clk);
+};
+
+/*
+ * struct clk.flags possibilities
+ *
+ * XXX document the rest of the clock flags here
+ */
+#define ENABLE_REG_32BIT (1 << 0) /* Use 32-bit access */
+#define CLOCK_IDLE_CONTROL (1 << 1)
+#define CLOCK_NO_IDLE_PARENT (1 << 2)
+
+/**
+ * struct omap1_clk - OMAP1 struct clk
+ * @hw: struct clk_hw for common clock framework integration
+ * @ops: struct clkops * for this clock
+ * @rate: current clock rate
+ * @enable_reg: register to write to enable the clock (see @enable_bit)
+ * @recalc: fn ptr that returns the clock's current rate
+ * @set_rate: fn ptr that can change the clock's current rate
+ * @round_rate: fn ptr that can round the clock's current rate
+ * @init: fn ptr to do clock-specific initialization
+ * @enable_bit: bitshift to write to enable/disable the clock (see @enable_reg)
+ * @fixed_div: when > 0, this clock's rate is its parent's rate / @fixed_div
+ * @flags: see "struct clk.flags possibilities" above
+ * @rate_offset: bitshift for rate selection bitfield (OMAP1 only)
+ */
+struct omap1_clk {
+ struct clk_hw hw;
+ const struct clkops *ops;
+ unsigned long rate;
+ void __iomem *enable_reg;
+ unsigned long (*recalc)(struct omap1_clk *clk, unsigned long rate);
+ int (*set_rate)(struct omap1_clk *clk, unsigned long rate,
+ unsigned long p_rate);
+ long (*round_rate)(struct omap1_clk *clk, unsigned long rate,
+ unsigned long *p_rate);
+ int (*init)(struct omap1_clk *clk);
+ u8 enable_bit;
+ u8 fixed_div;
+ u8 flags;
+ u8 rate_offset;
+};
+#define to_omap1_clk(_hw) container_of(_hw, struct omap1_clk, hw)
+
+void propagate_rate(struct omap1_clk *clk);
+unsigned long followparent_recalc(struct omap1_clk *clk, unsigned long p_rate);
+unsigned long omap_fixed_divisor_recalc(struct omap1_clk *clk, unsigned long p_rate);
+
+extern struct omap1_clk dummy_ck;
+
+int omap1_clk_init(void);
+void omap1_clk_late_init(void);
+unsigned long omap1_ckctl_recalc(struct omap1_clk *clk, unsigned long p_rate);
+long omap1_round_sossi_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate);
+int omap1_set_sossi_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate);
+unsigned long omap1_sossi_recalc(struct omap1_clk *clk, unsigned long p_rate);
+unsigned long omap1_ckctl_recalc_dsp_domain(struct omap1_clk *clk, unsigned long p_rate);
+int omap1_clk_set_rate_dsp_domain(struct omap1_clk *clk, unsigned long rate,
+ unsigned long p_rate);
+long omap1_round_uart_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate);
+int omap1_set_uart_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate);
+unsigned long omap1_uart_recalc(struct omap1_clk *clk, unsigned long p_rate);
+int omap1_set_ext_clk_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate);
+long omap1_round_ext_clk_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate);
+int omap1_init_ext_clk(struct omap1_clk *clk);
+int omap1_select_table_rate(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate);
+long omap1_round_to_table_rate(struct omap1_clk *clk, unsigned long rate, unsigned long *p_rate);
+int omap1_clk_set_rate_ckctl_arm(struct omap1_clk *clk, unsigned long rate, unsigned long p_rate);
+long omap1_clk_round_rate_ckctl_arm(struct omap1_clk *clk, unsigned long rate,
+ unsigned long *p_rate);
+
+struct uart_clk {
+ struct omap1_clk clk;
+ unsigned long sysc_addr;
+};
+
+/* Provide a method for preventing idling some ARM IDLECT clocks */
+struct arm_idlect1_clk {
+ struct omap1_clk clk;
+ unsigned long no_idle_count;
+ __u8 idlect_shift;
+};
+
+/* ARM_CKCTL bit shifts */
+#define CKCTL_PERDIV_OFFSET 0
+#define CKCTL_LCDDIV_OFFSET 2
+#define CKCTL_ARMDIV_OFFSET 4
+#define CKCTL_DSPDIV_OFFSET 6
+#define CKCTL_TCDIV_OFFSET 8
+#define CKCTL_DSPMMUDIV_OFFSET 10
+/*#define ARM_TIMXO 12*/
+#define EN_DSPCK 13
+/*#define ARM_INTHCK_SEL 14*/ /* Divide-by-2 for mpu inth_ck */
+/* DSP_CKCTL bit shifts */
+#define CKCTL_DSPPERDIV_OFFSET 0
+
+/* ARM_IDLECT2 bit shifts */
+#define EN_WDTCK 0
+#define EN_XORPCK 1
+#define EN_PERCK 2
+#define EN_LCDCK 3
+#define EN_LBCK 4 /* Not on 1610/1710 */
+/*#define EN_HSABCK 5*/
+#define EN_APICK 6
+#define EN_TIMCK 7
+#define DMACK_REQ 8
+#define EN_GPIOCK 9 /* Not on 1610/1710 */
+/*#define EN_LBFREECK 10*/
+#define EN_CKOUT_ARM 11
+
+/* ARM_IDLECT3 bit shifts */
+#define EN_OCPI_CK 0
+#define EN_TC1_CK 2
+#define EN_TC2_CK 4
+
+/* DSP_IDLECT2 bit shifts (0,1,2 are same as for ARM_IDLECT2) */
+#define EN_DSPTIMCK 5
+
+/* Various register defines for clock controls scattered around OMAP chip */
+#define SDW_MCLK_INV_BIT 2 /* In ULPD_CLKC_CTRL */
+#define USB_MCLK_EN_BIT 4 /* In ULPD_CLKC_CTRL */
+#define USB_HOST_HHC_UHOST_EN 9 /* In MOD_CONF_CTRL_0 */
+#define SWD_ULPD_PLL_CLK_REQ 1 /* In SWD_CLK_DIV_CTRL_SEL */
+#define COM_ULPD_PLL_CLK_REQ 1 /* In COM_CLK_DIV_CTRL_SEL */
+#define SWD_CLK_DIV_CTRL_SEL 0xfffe0874
+#define COM_CLK_DIV_CTRL_SEL 0xfffe0878
+#define SOFT_REQ_REG 0xfffe0834
+#define SOFT_REQ_REG2 0xfffe0880
+
+extern __u32 arm_idlect1_mask;
+extern struct omap1_clk *api_ck_p, *ck_dpll1_p, *ck_ref_p;
+
+extern const struct clkops clkops_dspck;
+extern const struct clkops clkops_uart_16xx;
+extern const struct clkops clkops_generic;
+
+/* used for passing SoC type to omap1_{select,round_to}_table_rate() */
+extern u32 cpu_mask;
+
+extern const struct clk_ops omap1_clk_null_ops;
+extern const struct clk_ops omap1_clk_gate_ops;
+extern const struct clk_ops omap1_clk_rate_ops;
+extern const struct clk_ops omap1_clk_full_ops;
+
+#endif
diff --git a/arch/arm/mach-omap1/clock_data.c b/arch/arm/mach-omap1/clock_data.c
new file mode 100644
index 0000000000..c58d200e48
--- /dev/null
+++ b/arch/arm/mach-omap1/clock_data.c
@@ -0,0 +1,834 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * linux/arch/arm/mach-omap1/clock_data.c
+ *
+ * Copyright (C) 2004 - 2005, 2009-2010 Nokia Corporation
+ * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ * Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, Inc
+ *
+ * To do:
+ * - Clocks that are only available on some chips should be marked with the
+ * chips that they are present on.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/soc/ti/omap1-io.h>
+
+#include <asm/mach-types.h> /* for machine_is_* */
+
+#include "soc.h"
+#include "hardware.h"
+#include "usb.h" /* for OTG_BASE */
+#include "iomap.h"
+#include "clock.h"
+#include "sram.h"
+
+/* Some ARM_IDLECT1 bit shifts - used in struct arm_idlect1_clk */
+#define IDL_CLKOUT_ARM_SHIFT 12
+#define IDLTIM_ARM_SHIFT 9
+#define IDLAPI_ARM_SHIFT 8
+#define IDLIF_ARM_SHIFT 6
+#define IDLLB_ARM_SHIFT 4 /* undocumented? */
+#define OMAP1510_IDLLCD_ARM_SHIFT 3 /* undocumented? */
+#define IDLPER_ARM_SHIFT 2
+#define IDLXORP_ARM_SHIFT 1
+#define IDLWDT_ARM_SHIFT 0
+
+/* Some MOD_CONF_CTRL_0 bit shifts - used in struct clk.enable_bit */
+#define CONF_MOD_UART3_CLK_MODE_R 31
+#define CONF_MOD_UART2_CLK_MODE_R 30
+#define CONF_MOD_UART1_CLK_MODE_R 29
+#define CONF_MOD_MMC_SD_CLK_REQ_R 23
+#define CONF_MOD_MCBSP3_AUXON 20
+
+/* Some MOD_CONF_CTRL_1 bit shifts - used in struct clk.enable_bit */
+#define CONF_MOD_SOSSI_CLK_EN_R 16
+
+/* Some OTG_SYSCON_2-specific bit fields */
+#define OTG_SYSCON_2_UHOST_EN_SHIFT 8
+
+/* Some SOFT_REQ_REG bit fields - used in struct clk.enable_bit */
+#define SOFT_MMC2_DPLL_REQ_SHIFT 13
+#define SOFT_MMC_DPLL_REQ_SHIFT 12
+#define SOFT_UART3_DPLL_REQ_SHIFT 11
+#define SOFT_UART2_DPLL_REQ_SHIFT 10
+#define SOFT_UART1_DPLL_REQ_SHIFT 9
+#define SOFT_USB_OTG_DPLL_REQ_SHIFT 8
+#define SOFT_CAM_DPLL_REQ_SHIFT 7
+#define SOFT_COM_MCKO_REQ_SHIFT 6
+#define SOFT_PERIPH_REQ_SHIFT 5 /* sys_ck gate for UART2 ? */
+#define USB_REQ_EN_SHIFT 4
+#define SOFT_USB_REQ_SHIFT 3 /* sys_ck gate for USB host? */
+#define SOFT_SDW_REQ_SHIFT 2 /* sys_ck gate for Bluetooth? */
+#define SOFT_COM_REQ_SHIFT 1 /* sys_ck gate for com proc? */
+#define SOFT_DPLL_REQ_SHIFT 0
+
+/*
+ * Omap1 clocks
+ */
+
+static struct omap1_clk ck_ref = {
+ .hw.init = CLK_HW_INIT_NO_PARENT("ck_ref", &omap1_clk_rate_ops, 0),
+ .rate = 12000000,
+};
+
+static struct omap1_clk ck_dpll1 = {
+ .hw.init = CLK_HW_INIT("ck_dpll1", "ck_ref", &omap1_clk_rate_ops,
+ /*
+ * force recursive refresh of rates of the clock
+ * and its children when clk_get_rate() is called
+ */
+ CLK_GET_RATE_NOCACHE),
+};
+
+/*
+ * FIXME: This clock seems to be necessary but no-one has asked for its
+ * activation. [ FIX: SoSSI, SSR ]
+ */
+static struct arm_idlect1_clk ck_dpll1out = {
+ .clk = {
+ .hw.init = CLK_HW_INIT("ck_dpll1out", "ck_dpll1", &omap1_clk_gate_ops, 0),
+ .ops = &clkops_generic,
+ .flags = CLOCK_IDLE_CONTROL | ENABLE_REG_32BIT,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
+ .enable_bit = EN_CKOUT_ARM,
+ },
+ .idlect_shift = IDL_CLKOUT_ARM_SHIFT,
+};
+
+static struct omap1_clk sossi_ck = {
+ .hw.init = CLK_HW_INIT("ck_sossi", "ck_dpll1out", &omap1_clk_full_ops, 0),
+ .ops = &clkops_generic,
+ .flags = CLOCK_NO_IDLE_PARENT | ENABLE_REG_32BIT,
+ .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_1),
+ .enable_bit = CONF_MOD_SOSSI_CLK_EN_R,
+ .recalc = &omap1_sossi_recalc,
+ .round_rate = &omap1_round_sossi_rate,
+ .set_rate = &omap1_set_sossi_rate,
+};
+
+static struct omap1_clk arm_ck = {
+ .hw.init = CLK_HW_INIT("arm_ck", "ck_dpll1", &omap1_clk_rate_ops, 0),
+ .rate_offset = CKCTL_ARMDIV_OFFSET,
+ .recalc = &omap1_ckctl_recalc,
+ .round_rate = omap1_clk_round_rate_ckctl_arm,
+ .set_rate = omap1_clk_set_rate_ckctl_arm,
+};
+
+static struct arm_idlect1_clk armper_ck = {
+ .clk = {
+ .hw.init = CLK_HW_INIT("armper_ck", "ck_dpll1", &omap1_clk_full_ops,
+ CLK_IS_CRITICAL),
+ .ops = &clkops_generic,
+ .flags = CLOCK_IDLE_CONTROL,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
+ .enable_bit = EN_PERCK,
+ .rate_offset = CKCTL_PERDIV_OFFSET,
+ .recalc = &omap1_ckctl_recalc,
+ .round_rate = omap1_clk_round_rate_ckctl_arm,
+ .set_rate = omap1_clk_set_rate_ckctl_arm,
+ },
+ .idlect_shift = IDLPER_ARM_SHIFT,
+};
+
+/*
+ * FIXME: This clock seems to be necessary but no-one has asked for its
+ * activation. [ GPIO code for 1510 ]
+ */
+static struct omap1_clk arm_gpio_ck = {
+ .hw.init = CLK_HW_INIT("ick", "ck_dpll1", &omap1_clk_gate_ops, CLK_IS_CRITICAL),
+ .ops = &clkops_generic,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
+ .enable_bit = EN_GPIOCK,
+};
+
+static struct arm_idlect1_clk armxor_ck = {
+ .clk = {
+ .hw.init = CLK_HW_INIT("armxor_ck", "ck_ref", &omap1_clk_gate_ops,
+ CLK_IS_CRITICAL),
+ .ops = &clkops_generic,
+ .flags = CLOCK_IDLE_CONTROL,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
+ .enable_bit = EN_XORPCK,
+ },
+ .idlect_shift = IDLXORP_ARM_SHIFT,
+};
+
+static struct arm_idlect1_clk armtim_ck = {
+ .clk = {
+ .hw.init = CLK_HW_INIT("armtim_ck", "ck_ref", &omap1_clk_gate_ops,
+ CLK_IS_CRITICAL),
+ .ops = &clkops_generic,
+ .flags = CLOCK_IDLE_CONTROL,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
+ .enable_bit = EN_TIMCK,
+ },
+ .idlect_shift = IDLTIM_ARM_SHIFT,
+};
+
+static struct arm_idlect1_clk armwdt_ck = {
+ .clk = {
+ .hw.init = CLK_HW_INIT("armwdt_ck", "ck_ref", &omap1_clk_full_ops, 0),
+ .ops = &clkops_generic,
+ .flags = CLOCK_IDLE_CONTROL,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
+ .enable_bit = EN_WDTCK,
+ .fixed_div = 14,
+ .recalc = &omap_fixed_divisor_recalc,
+ },
+ .idlect_shift = IDLWDT_ARM_SHIFT,
+};
+
+static struct omap1_clk arminth_ck16xx = {
+ .hw.init = CLK_HW_INIT("arminth_ck", "arm_ck", &omap1_clk_null_ops, 0),
+ /* Note: On 16xx the frequency can be divided by 2 by programming
+ * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1
+ *
+ * 1510 version is in TC clocks.
+ */
+};
+
+static struct omap1_clk dsp_ck = {
+ .hw.init = CLK_HW_INIT("dsp_ck", "ck_dpll1", &omap1_clk_full_ops, 0),
+ .ops = &clkops_generic,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_CKCTL),
+ .enable_bit = EN_DSPCK,
+ .rate_offset = CKCTL_DSPDIV_OFFSET,
+ .recalc = &omap1_ckctl_recalc,
+ .round_rate = omap1_clk_round_rate_ckctl_arm,
+ .set_rate = omap1_clk_set_rate_ckctl_arm,
+};
+
+static struct omap1_clk dspmmu_ck = {
+ .hw.init = CLK_HW_INIT("dspmmu_ck", "ck_dpll1", &omap1_clk_rate_ops, 0),
+ .rate_offset = CKCTL_DSPMMUDIV_OFFSET,
+ .recalc = &omap1_ckctl_recalc,
+ .round_rate = omap1_clk_round_rate_ckctl_arm,
+ .set_rate = omap1_clk_set_rate_ckctl_arm,
+};
+
+static struct omap1_clk dspper_ck = {
+ .hw.init = CLK_HW_INIT("dspper_ck", "ck_dpll1", &omap1_clk_full_ops, 0),
+ .ops = &clkops_dspck,
+ .enable_reg = DSP_IDLECT2,
+ .enable_bit = EN_PERCK,
+ .rate_offset = CKCTL_PERDIV_OFFSET,
+ .recalc = &omap1_ckctl_recalc_dsp_domain,
+ .round_rate = omap1_clk_round_rate_ckctl_arm,
+ .set_rate = &omap1_clk_set_rate_dsp_domain,
+};
+
+static struct omap1_clk dspxor_ck = {
+ .hw.init = CLK_HW_INIT("dspxor_ck", "ck_ref", &omap1_clk_gate_ops, 0),
+ .ops = &clkops_dspck,
+ .enable_reg = DSP_IDLECT2,
+ .enable_bit = EN_XORPCK,
+};
+
+static struct omap1_clk dsptim_ck = {
+ .hw.init = CLK_HW_INIT("dsptim_ck", "ck_ref", &omap1_clk_gate_ops, 0),
+ .ops = &clkops_dspck,
+ .enable_reg = DSP_IDLECT2,
+ .enable_bit = EN_DSPTIMCK,
+};
+
+static struct arm_idlect1_clk tc_ck = {
+ .clk = {
+ .hw.init = CLK_HW_INIT("tc_ck", "ck_dpll1", &omap1_clk_rate_ops, 0),
+ .flags = CLOCK_IDLE_CONTROL,
+ .rate_offset = CKCTL_TCDIV_OFFSET,
+ .recalc = &omap1_ckctl_recalc,
+ .round_rate = omap1_clk_round_rate_ckctl_arm,
+ .set_rate = omap1_clk_set_rate_ckctl_arm,
+ },
+ .idlect_shift = IDLIF_ARM_SHIFT,
+};
+
+static struct omap1_clk arminth_ck1510 = {
+ .hw.init = CLK_HW_INIT("arminth_ck", "tc_ck", &omap1_clk_null_ops, 0),
+ /* Note: On 1510 the frequency follows TC_CK
+ *
+ * 16xx version is in MPU clocks.
+ */
+};
+
+static struct omap1_clk tipb_ck = {
+ /* No-idle controlled by "tc_ck" */
+ .hw.init = CLK_HW_INIT("tipb_ck", "tc_ck", &omap1_clk_null_ops, 0),
+};
+
+static struct omap1_clk l3_ocpi_ck = {
+ /* No-idle controlled by "tc_ck" */
+ .hw.init = CLK_HW_INIT("l3_ocpi_ck", "tc_ck", &omap1_clk_gate_ops, 0),
+ .ops = &clkops_generic,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT3),
+ .enable_bit = EN_OCPI_CK,
+};
+
+static struct omap1_clk tc1_ck = {
+ .hw.init = CLK_HW_INIT("tc1_ck", "tc_ck", &omap1_clk_gate_ops, 0),
+ .ops = &clkops_generic,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT3),
+ .enable_bit = EN_TC1_CK,
+};
+
+/*
+ * FIXME: This clock seems to be necessary but no-one has asked for its
+ * activation. [ pm.c (SRAM), CCP, Camera ]
+ */
+
+static struct omap1_clk tc2_ck = {
+ .hw.init = CLK_HW_INIT("tc2_ck", "tc_ck", &omap1_clk_gate_ops, CLK_IS_CRITICAL),
+ .ops = &clkops_generic,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT3),
+ .enable_bit = EN_TC2_CK,
+};
+
+static struct omap1_clk dma_ck = {
+ /* No-idle controlled by "tc_ck" */
+ .hw.init = CLK_HW_INIT("dma_ck", "tc_ck", &omap1_clk_null_ops, 0),
+};
+
+static struct omap1_clk dma_lcdfree_ck = {
+ .hw.init = CLK_HW_INIT("dma_lcdfree_ck", "tc_ck", &omap1_clk_null_ops, 0),
+};
+
+static struct arm_idlect1_clk api_ck = {
+ .clk = {
+ .hw.init = CLK_HW_INIT("api_ck", "tc_ck", &omap1_clk_gate_ops, 0),
+ .ops = &clkops_generic,
+ .flags = CLOCK_IDLE_CONTROL,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
+ .enable_bit = EN_APICK,
+ },
+ .idlect_shift = IDLAPI_ARM_SHIFT,
+};
+
+static struct arm_idlect1_clk lb_ck = {
+ .clk = {
+ .hw.init = CLK_HW_INIT("lb_ck", "tc_ck", &omap1_clk_gate_ops, 0),
+ .ops = &clkops_generic,
+ .flags = CLOCK_IDLE_CONTROL,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
+ .enable_bit = EN_LBCK,
+ },
+ .idlect_shift = IDLLB_ARM_SHIFT,
+};
+
+static struct omap1_clk rhea1_ck = {
+ .hw.init = CLK_HW_INIT("rhea1_ck", "tc_ck", &omap1_clk_null_ops, 0),
+};
+
+static struct omap1_clk rhea2_ck = {
+ .hw.init = CLK_HW_INIT("rhea2_ck", "tc_ck", &omap1_clk_null_ops, 0),
+};
+
+static struct omap1_clk lcd_ck_16xx = {
+ .hw.init = CLK_HW_INIT("lcd_ck", "ck_dpll1", &omap1_clk_full_ops, 0),
+ .ops = &clkops_generic,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
+ .enable_bit = EN_LCDCK,
+ .rate_offset = CKCTL_LCDDIV_OFFSET,
+ .recalc = &omap1_ckctl_recalc,
+ .round_rate = omap1_clk_round_rate_ckctl_arm,
+ .set_rate = omap1_clk_set_rate_ckctl_arm,
+};
+
+static struct arm_idlect1_clk lcd_ck_1510 = {
+ .clk = {
+ .hw.init = CLK_HW_INIT("lcd_ck", "ck_dpll1", &omap1_clk_full_ops, 0),
+ .ops = &clkops_generic,
+ .flags = CLOCK_IDLE_CONTROL,
+ .enable_reg = OMAP1_IO_ADDRESS(ARM_IDLECT2),
+ .enable_bit = EN_LCDCK,
+ .rate_offset = CKCTL_LCDDIV_OFFSET,
+ .recalc = &omap1_ckctl_recalc,
+ .round_rate = omap1_clk_round_rate_ckctl_arm,
+ .set_rate = omap1_clk_set_rate_ckctl_arm,
+ },
+ .idlect_shift = OMAP1510_IDLLCD_ARM_SHIFT,
+};
+
+
+/*
+ * XXX The enable_bit here is misused - it simply switches between 12MHz
+ * and 48MHz. Reimplement with clk_mux.
+ *
+ * XXX does this need SYSC register handling?
+ */
+static struct omap1_clk uart1_1510 = {
+ /* Direct from ULPD, no real parent */
+ .hw.init = CLK_HW_INIT("uart1_ck", "armper_ck", &omap1_clk_full_ops, 0),
+ .flags = ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
+ .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
+ .enable_bit = CONF_MOD_UART1_CLK_MODE_R,
+ .round_rate = &omap1_round_uart_rate,
+ .set_rate = &omap1_set_uart_rate,
+ .recalc = &omap1_uart_recalc,
+};
+
+/*
+ * XXX The enable_bit here is misused - it simply switches between 12MHz
+ * and 48MHz. Reimplement with clk_mux.
+ *
+ * XXX SYSC register handling does not belong in the clock framework
+ */
+static struct uart_clk uart1_16xx = {
+ .clk = {
+ .ops = &clkops_uart_16xx,
+ /* Direct from ULPD, no real parent */
+ .hw.init = CLK_HW_INIT("uart1_ck", "armper_ck", &omap1_clk_full_ops, 0),
+ .rate = 48000000,
+ .flags = ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
+ .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
+ .enable_bit = CONF_MOD_UART1_CLK_MODE_R,
+ },
+ .sysc_addr = 0xfffb0054,
+};
+
+/*
+ * XXX The enable_bit here is misused - it simply switches between 12MHz
+ * and 48MHz. Reimplement with clk_mux.
+ *
+ * XXX does this need SYSC register handling?
+ */
+static struct omap1_clk uart2_ck = {
+ /* Direct from ULPD, no real parent */
+ .hw.init = CLK_HW_INIT("uart2_ck", "armper_ck", &omap1_clk_full_ops, 0),
+ .flags = ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
+ .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
+ .enable_bit = CONF_MOD_UART2_CLK_MODE_R,
+ .round_rate = &omap1_round_uart_rate,
+ .set_rate = &omap1_set_uart_rate,
+ .recalc = &omap1_uart_recalc,
+};
+
+/*
+ * XXX The enable_bit here is misused - it simply switches between 12MHz
+ * and 48MHz. Reimplement with clk_mux.
+ *
+ * XXX does this need SYSC register handling?
+ */
+static struct omap1_clk uart3_1510 = {
+ /* Direct from ULPD, no real parent */
+ .hw.init = CLK_HW_INIT("uart3_ck", "armper_ck", &omap1_clk_full_ops, 0),
+ .flags = ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
+ .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
+ .enable_bit = CONF_MOD_UART3_CLK_MODE_R,
+ .round_rate = &omap1_round_uart_rate,
+ .set_rate = &omap1_set_uart_rate,
+ .recalc = &omap1_uart_recalc,
+};
+
+/*
+ * XXX The enable_bit here is misused - it simply switches between 12MHz
+ * and 48MHz. Reimplement with clk_mux.
+ *
+ * XXX SYSC register handling does not belong in the clock framework
+ */
+static struct uart_clk uart3_16xx = {
+ .clk = {
+ .ops = &clkops_uart_16xx,
+ /* Direct from ULPD, no real parent */
+ .hw.init = CLK_HW_INIT("uart3_ck", "armper_ck", &omap1_clk_full_ops, 0),
+ .rate = 48000000,
+ .flags = ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
+ .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
+ .enable_bit = CONF_MOD_UART3_CLK_MODE_R,
+ },
+ .sysc_addr = 0xfffb9854,
+};
+
+static struct omap1_clk usb_clko = { /* 6 MHz output on W4_USB_CLKO */
+ .ops = &clkops_generic,
+ /* Direct from ULPD, no parent */
+ .hw.init = CLK_HW_INIT_NO_PARENT("usb_clko", &omap1_clk_full_ops, 0),
+ .rate = 6000000,
+ .flags = ENABLE_REG_32BIT,
+ .enable_reg = OMAP1_IO_ADDRESS(ULPD_CLOCK_CTRL),
+ .enable_bit = USB_MCLK_EN_BIT,
+};
+
+static struct omap1_clk usb_hhc_ck1510 = {
+ .ops = &clkops_generic,
+ /* Direct from ULPD, no parent */
+ .hw.init = CLK_HW_INIT_NO_PARENT("usb_hhc_ck", &omap1_clk_full_ops, 0),
+ .rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */
+ .flags = ENABLE_REG_32BIT,
+ .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
+ .enable_bit = USB_HOST_HHC_UHOST_EN,
+};
+
+static struct omap1_clk usb_hhc_ck16xx = {
+ .ops = &clkops_generic,
+ /* Direct from ULPD, no parent */
+ .hw.init = CLK_HW_INIT_NO_PARENT("usb_hhc_ck", &omap1_clk_full_ops, 0),
+ .rate = 48000000,
+ /* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */
+ .flags = ENABLE_REG_32BIT,
+ .enable_reg = OMAP1_IO_ADDRESS(OTG_BASE + 0x08), /* OTG_SYSCON_2 */
+ .enable_bit = OTG_SYSCON_2_UHOST_EN_SHIFT
+};
+
+static struct omap1_clk usb_dc_ck = {
+ .ops = &clkops_generic,
+ /* Direct from ULPD, no parent */
+ .hw.init = CLK_HW_INIT_NO_PARENT("usb_dc_ck", &omap1_clk_full_ops, 0),
+ .rate = 48000000,
+ .enable_reg = OMAP1_IO_ADDRESS(SOFT_REQ_REG),
+ .enable_bit = SOFT_USB_OTG_DPLL_REQ_SHIFT,
+};
+
+static struct omap1_clk uart1_7xx = {
+ .ops = &clkops_generic,
+ /* Direct from ULPD, no parent */
+ .hw.init = CLK_HW_INIT_NO_PARENT("uart1_ck", &omap1_clk_full_ops, 0),
+ .rate = 12000000,
+ .enable_reg = OMAP1_IO_ADDRESS(SOFT_REQ_REG),
+ .enable_bit = 9,
+};
+
+static struct omap1_clk uart2_7xx = {
+ .ops = &clkops_generic,
+ /* Direct from ULPD, no parent */
+ .hw.init = CLK_HW_INIT_NO_PARENT("uart2_ck", &omap1_clk_full_ops, 0),
+ .rate = 12000000,
+ .enable_reg = OMAP1_IO_ADDRESS(SOFT_REQ_REG),
+ .enable_bit = 11,
+};
+
+static struct omap1_clk mclk_1510 = {
+ .ops = &clkops_generic,
+ /* Direct from ULPD, no parent. May be enabled by ext hardware. */
+ .hw.init = CLK_HW_INIT_NO_PARENT("mclk", &omap1_clk_full_ops, 0),
+ .rate = 12000000,
+ .enable_reg = OMAP1_IO_ADDRESS(SOFT_REQ_REG),
+ .enable_bit = SOFT_COM_MCKO_REQ_SHIFT,
+};
+
+static struct omap1_clk mclk_16xx = {
+ .ops = &clkops_generic,
+ /* Direct from ULPD, no parent. May be enabled by ext hardware. */
+ .hw.init = CLK_HW_INIT_NO_PARENT("mclk", &omap1_clk_full_ops, 0),
+ .enable_reg = OMAP1_IO_ADDRESS(COM_CLK_DIV_CTRL_SEL),
+ .enable_bit = COM_ULPD_PLL_CLK_REQ,
+ .set_rate = &omap1_set_ext_clk_rate,
+ .round_rate = &omap1_round_ext_clk_rate,
+ .init = &omap1_init_ext_clk,
+};
+
+static struct omap1_clk bclk_1510 = {
+ /* Direct from ULPD, no parent. May be enabled by ext hardware. */
+ .hw.init = CLK_HW_INIT_NO_PARENT("bclk", &omap1_clk_rate_ops, 0),
+ .rate = 12000000,
+};
+
+static struct omap1_clk bclk_16xx = {
+ .ops = &clkops_generic,
+ /* Direct from ULPD, no parent. May be enabled by ext hardware. */
+ .hw.init = CLK_HW_INIT_NO_PARENT("bclk", &omap1_clk_full_ops, 0),
+ .enable_reg = OMAP1_IO_ADDRESS(SWD_CLK_DIV_CTRL_SEL),
+ .enable_bit = SWD_ULPD_PLL_CLK_REQ,
+ .set_rate = &omap1_set_ext_clk_rate,
+ .round_rate = &omap1_round_ext_clk_rate,
+ .init = &omap1_init_ext_clk,
+};
+
+static struct omap1_clk mmc1_ck = {
+ .ops = &clkops_generic,
+ /* Functional clock is direct from ULPD, interface clock is ARMPER */
+ .hw.init = CLK_HW_INIT("mmc1_ck", "armper_ck", &omap1_clk_full_ops, 0),
+ .rate = 48000000,
+ .flags = ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
+ .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
+ .enable_bit = CONF_MOD_MMC_SD_CLK_REQ_R,
+};
+
+/*
+ * XXX MOD_CONF_CTRL_0 bit 20 is defined in the 1510 TRM as
+ * CONF_MOD_MCBSP3_AUXON ??
+ */
+static struct omap1_clk mmc2_ck = {
+ .ops = &clkops_generic,
+ /* Functional clock is direct from ULPD, interface clock is ARMPER */
+ .hw.init = CLK_HW_INIT("mmc2_ck", "armper_ck", &omap1_clk_full_ops, 0),
+ .rate = 48000000,
+ .flags = ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
+ .enable_reg = OMAP1_IO_ADDRESS(MOD_CONF_CTRL_0),
+ .enable_bit = 20,
+};
+
+static struct omap1_clk mmc3_ck = {
+ .ops = &clkops_generic,
+ /* Functional clock is direct from ULPD, interface clock is ARMPER */
+ .hw.init = CLK_HW_INIT("mmc3_ck", "armper_ck", &omap1_clk_full_ops, 0),
+ .rate = 48000000,
+ .flags = ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT,
+ .enable_reg = OMAP1_IO_ADDRESS(SOFT_REQ_REG),
+ .enable_bit = SOFT_MMC_DPLL_REQ_SHIFT,
+};
+
+static struct omap1_clk virtual_ck_mpu = {
+ /* Is smarter alias for arm_ck */
+ .hw.init = CLK_HW_INIT("mpu", "arm_ck", &omap1_clk_rate_ops, 0),
+ .recalc = &followparent_recalc,
+ .set_rate = &omap1_select_table_rate,
+ .round_rate = &omap1_round_to_table_rate,
+};
+
+/* virtual functional clock domain for I2C. Just for making sure that ARMXOR_CK
+remains active during MPU idle whenever this is enabled */
+static struct omap1_clk i2c_fck = {
+ .hw.init = CLK_HW_INIT("i2c_fck", "armxor_ck", &omap1_clk_gate_ops, 0),
+ .flags = CLOCK_NO_IDLE_PARENT,
+};
+
+static struct omap1_clk i2c_ick = {
+ .hw.init = CLK_HW_INIT("i2c_ick", "armper_ck", &omap1_clk_gate_ops, 0),
+ .flags = CLOCK_NO_IDLE_PARENT,
+};
+
+/*
+ * clkdev integration
+ */
+
+static struct omap_clk omap_clks[] = {
+ /* non-ULPD clocks */
+ CLK(NULL, "ck_ref", &ck_ref.hw, CK_16XX | CK_1510 | CK_310 | CK_7XX),
+ CLK(NULL, "ck_dpll1", &ck_dpll1.hw, CK_16XX | CK_1510 | CK_310 | CK_7XX),
+ /* CK_GEN1 clocks */
+ CLK(NULL, "ck_dpll1out", &ck_dpll1out.clk.hw, CK_16XX),
+ CLK(NULL, "ck_sossi", &sossi_ck.hw, CK_16XX),
+ CLK(NULL, "arm_ck", &arm_ck.hw, CK_16XX | CK_1510 | CK_310),
+ CLK(NULL, "armper_ck", &armper_ck.clk.hw, CK_16XX | CK_1510 | CK_310),
+ CLK("omap_gpio.0", "ick", &arm_gpio_ck.hw, CK_1510 | CK_310),
+ CLK(NULL, "armxor_ck", &armxor_ck.clk.hw, CK_16XX | CK_1510 | CK_310 | CK_7XX),
+ CLK(NULL, "armtim_ck", &armtim_ck.clk.hw, CK_16XX | CK_1510 | CK_310),
+ CLK("omap_wdt", "fck", &armwdt_ck.clk.hw, CK_16XX | CK_1510 | CK_310),
+ CLK("omap_wdt", "ick", &armper_ck.clk.hw, CK_16XX),
+ CLK("omap_wdt", "ick", &dummy_ck.hw, CK_1510 | CK_310),
+ CLK(NULL, "arminth_ck", &arminth_ck1510.hw, CK_1510 | CK_310),
+ CLK(NULL, "arminth_ck", &arminth_ck16xx.hw, CK_16XX),
+ /* CK_GEN2 clocks */
+ CLK(NULL, "dsp_ck", &dsp_ck.hw, CK_16XX | CK_1510 | CK_310),
+ CLK(NULL, "dspmmu_ck", &dspmmu_ck.hw, CK_16XX | CK_1510 | CK_310),
+ CLK(NULL, "dspper_ck", &dspper_ck.hw, CK_16XX | CK_1510 | CK_310),
+ CLK(NULL, "dspxor_ck", &dspxor_ck.hw, CK_16XX | CK_1510 | CK_310),
+ CLK(NULL, "dsptim_ck", &dsptim_ck.hw, CK_16XX | CK_1510 | CK_310),
+ /* CK_GEN3 clocks */
+ CLK(NULL, "tc_ck", &tc_ck.clk.hw, CK_16XX | CK_1510 | CK_310 | CK_7XX),
+ CLK(NULL, "tipb_ck", &tipb_ck.hw, CK_1510 | CK_310),
+ CLK(NULL, "l3_ocpi_ck", &l3_ocpi_ck.hw, CK_16XX | CK_7XX),
+ CLK(NULL, "tc1_ck", &tc1_ck.hw, CK_16XX),
+ CLK(NULL, "tc2_ck", &tc2_ck.hw, CK_16XX),
+ CLK(NULL, "dma_ck", &dma_ck.hw, CK_16XX | CK_1510 | CK_310),
+ CLK(NULL, "dma_lcdfree_ck", &dma_lcdfree_ck.hw, CK_16XX),
+ CLK(NULL, "api_ck", &api_ck.clk.hw, CK_16XX | CK_1510 | CK_310 | CK_7XX),
+ CLK(NULL, "lb_ck", &lb_ck.clk.hw, CK_1510 | CK_310),
+ CLK(NULL, "rhea1_ck", &rhea1_ck.hw, CK_16XX),
+ CLK(NULL, "rhea2_ck", &rhea2_ck.hw, CK_16XX),
+ CLK(NULL, "lcd_ck", &lcd_ck_16xx.hw, CK_16XX | CK_7XX),
+ CLK(NULL, "lcd_ck", &lcd_ck_1510.clk.hw, CK_1510 | CK_310),
+ /* ULPD clocks */
+ CLK(NULL, "uart1_ck", &uart1_1510.hw, CK_1510 | CK_310),
+ CLK(NULL, "uart1_ck", &uart1_16xx.clk.hw, CK_16XX),
+ CLK(NULL, "uart1_ck", &uart1_7xx.hw, CK_7XX),
+ CLK(NULL, "uart2_ck", &uart2_ck.hw, CK_16XX | CK_1510 | CK_310),
+ CLK(NULL, "uart2_ck", &uart2_7xx.hw, CK_7XX),
+ CLK(NULL, "uart3_ck", &uart3_1510.hw, CK_1510 | CK_310),
+ CLK(NULL, "uart3_ck", &uart3_16xx.clk.hw, CK_16XX),
+ CLK(NULL, "usb_clko", &usb_clko.hw, CK_16XX | CK_1510 | CK_310),
+ CLK(NULL, "usb_hhc_ck", &usb_hhc_ck1510.hw, CK_1510 | CK_310),
+ CLK(NULL, "usb_hhc_ck", &usb_hhc_ck16xx.hw, CK_16XX),
+ CLK(NULL, "usb_dc_ck", &usb_dc_ck.hw, CK_16XX | CK_7XX),
+ CLK(NULL, "mclk", &mclk_1510.hw, CK_1510 | CK_310),
+ CLK(NULL, "mclk", &mclk_16xx.hw, CK_16XX),
+ CLK(NULL, "bclk", &bclk_1510.hw, CK_1510 | CK_310),
+ CLK(NULL, "bclk", &bclk_16xx.hw, CK_16XX),
+ CLK("mmci-omap.0", "fck", &mmc1_ck.hw, CK_16XX | CK_1510 | CK_310),
+ CLK("mmci-omap.0", "fck", &mmc3_ck.hw, CK_7XX),
+ CLK("mmci-omap.0", "ick", &armper_ck.clk.hw, CK_16XX | CK_1510 | CK_310 | CK_7XX),
+ CLK("mmci-omap.1", "fck", &mmc2_ck.hw, CK_16XX),
+ CLK("mmci-omap.1", "ick", &armper_ck.clk.hw, CK_16XX),
+ /* Virtual clocks */
+ CLK(NULL, "mpu", &virtual_ck_mpu.hw, CK_16XX | CK_1510 | CK_310),
+ CLK("omap_i2c.1", "fck", &i2c_fck.hw, CK_16XX | CK_1510 | CK_310 | CK_7XX),
+ CLK("omap_i2c.1", "ick", &i2c_ick.hw, CK_16XX),
+ CLK("omap_i2c.1", "ick", &dummy_ck.hw, CK_1510 | CK_310 | CK_7XX),
+ CLK("omap1_spi100k.1", "fck", &dummy_ck.hw, CK_7XX),
+ CLK("omap1_spi100k.1", "ick", &dummy_ck.hw, CK_7XX),
+ CLK("omap1_spi100k.2", "fck", &dummy_ck.hw, CK_7XX),
+ CLK("omap1_spi100k.2", "ick", &dummy_ck.hw, CK_7XX),
+ CLK("omap_uwire", "fck", &armxor_ck.clk.hw, CK_16XX | CK_1510 | CK_310),
+ CLK("omap-mcbsp.1", "ick", &dspper_ck.hw, CK_16XX),
+ CLK("omap-mcbsp.1", "ick", &dummy_ck.hw, CK_1510 | CK_310),
+ CLK("omap-mcbsp.2", "ick", &armper_ck.clk.hw, CK_16XX),
+ CLK("omap-mcbsp.2", "ick", &dummy_ck.hw, CK_1510 | CK_310),
+ CLK("omap-mcbsp.3", "ick", &dspper_ck.hw, CK_16XX),
+ CLK("omap-mcbsp.3", "ick", &dummy_ck.hw, CK_1510 | CK_310),
+ CLK("omap-mcbsp.1", "fck", &dspxor_ck.hw, CK_16XX | CK_1510 | CK_310),
+ CLK("omap-mcbsp.2", "fck", &armper_ck.clk.hw, CK_16XX | CK_1510 | CK_310),
+ CLK("omap-mcbsp.3", "fck", &dspxor_ck.hw, CK_16XX | CK_1510 | CK_310),
+};
+
+/*
+ * init
+ */
+
+static void __init omap1_show_rates(void)
+{
+ pr_notice("Clocking rate (xtal/DPLL1/MPU): %ld.%01ld/%ld.%01ld/%ld.%01ld MHz\n",
+ ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10,
+ ck_dpll1.rate / 1000000, (ck_dpll1.rate / 100000) % 10,
+ arm_ck.rate / 1000000, (arm_ck.rate / 100000) % 10);
+}
+
+u32 cpu_mask;
+
+int __init omap1_clk_init(void)
+{
+ struct omap_clk *c;
+ u32 reg;
+
+#ifdef CONFIG_DEBUG_LL
+ /* Make sure UART clocks are enabled early */
+ if (cpu_is_omap16xx())
+ omap_writel(omap_readl(MOD_CONF_CTRL_0) |
+ CONF_MOD_UART1_CLK_MODE_R |
+ CONF_MOD_UART3_CLK_MODE_R, MOD_CONF_CTRL_0);
+#endif
+
+ /* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */
+ reg = omap_readw(SOFT_REQ_REG) & (1 << 4);
+ omap_writew(reg, SOFT_REQ_REG);
+ if (!cpu_is_omap15xx())
+ omap_writew(0, SOFT_REQ_REG2);
+
+ /* By default all idlect1 clocks are allowed to idle */
+ arm_idlect1_mask = ~0;
+
+ cpu_mask = 0;
+ if (cpu_is_omap1710())
+ cpu_mask |= CK_1710;
+ if (cpu_is_omap16xx())
+ cpu_mask |= CK_16XX;
+ if (cpu_is_omap1510())
+ cpu_mask |= CK_1510;
+ if (cpu_is_omap310())
+ cpu_mask |= CK_310;
+
+ /* Pointers to these clocks are needed by code in clock.c */
+ api_ck_p = &api_ck.clk;
+ ck_dpll1_p = &ck_dpll1;
+ ck_ref_p = &ck_ref;
+
+ pr_info("Clocks: ARM_SYSST: 0x%04x DPLL_CTL: 0x%04x ARM_CKCTL: 0x%04x\n",
+ omap_readw(ARM_SYSST), omap_readw(DPLL_CTL),
+ omap_readw(ARM_CKCTL));
+
+ /* We want to be in synchronous scalable mode */
+ omap_writew(0x1000, ARM_SYSST);
+
+
+ /*
+ * Initially use the values set by bootloader. Determine PLL rate and
+ * recalculate dependent clocks as if kernel had changed PLL or
+ * divisors. See also omap1_clk_late_init() that can reprogram dpll1
+ * after the SRAM is initialized.
+ */
+ {
+ unsigned pll_ctl_val = omap_readw(DPLL_CTL);
+
+ ck_dpll1.rate = ck_ref.rate; /* Base xtal rate */
+ if (pll_ctl_val & 0x10) {
+ /* PLL enabled, apply multiplier and divisor */
+ if (pll_ctl_val & 0xf80)
+ ck_dpll1.rate *= (pll_ctl_val & 0xf80) >> 7;
+ ck_dpll1.rate /= ((pll_ctl_val & 0x60) >> 5) + 1;
+ } else {
+ /* PLL disabled, apply bypass divisor */
+ switch (pll_ctl_val & 0xc) {
+ case 0:
+ break;
+ case 0x4:
+ ck_dpll1.rate /= 2;
+ break;
+ default:
+ ck_dpll1.rate /= 4;
+ break;
+ }
+ }
+ }
+
+ /* Amstrad Delta wants BCLK high when inactive */
+ if (machine_is_ams_delta())
+ omap_writel(omap_readl(ULPD_CLOCK_CTRL) |
+ (1 << SDW_MCLK_INV_BIT),
+ ULPD_CLOCK_CTRL);
+
+ /* Turn off DSP and ARM_TIMXO. Make sure ARM_INTHCK is not divided */
+ omap_writew(omap_readw(ARM_CKCTL) & 0x0fff, ARM_CKCTL);
+
+ /* Put DSP/MPUI into reset until needed */
+ omap_writew(0, ARM_RSTCT1);
+ omap_writew(1, ARM_RSTCT2);
+ omap_writew(0x400, ARM_IDLECT1);
+
+ /*
+ * According to OMAP5910 Erratum SYS_DMA_1, bit DMACK_REQ (bit 8)
+ * of the ARM_IDLECT2 register must be set to zero. The power-on
+ * default value of this bit is one.
+ */
+ omap_writew(0x0000, ARM_IDLECT2); /* Turn LCD clock off also */
+
+ for (c = omap_clks; c < omap_clks + ARRAY_SIZE(omap_clks); c++) {
+ if (!(c->cpu & cpu_mask))
+ continue;
+
+ if (c->lk.clk_hw->init) { /* NULL if provider already registered */
+ const struct clk_init_data *init = c->lk.clk_hw->init;
+ const char *name = c->lk.clk_hw->init->name;
+ int err;
+
+ err = clk_hw_register(NULL, c->lk.clk_hw);
+ if (err < 0) {
+ pr_err("failed to register clock \"%s\"! (%d)\n", name, err);
+ /* may be tried again, restore init data */
+ c->lk.clk_hw->init = init;
+ continue;
+ }
+ }
+
+ clk_hw_register_clkdev(c->lk.clk_hw, c->lk.con_id, c->lk.dev_id);
+ }
+
+ omap1_show_rates();
+
+ return 0;
+}
+
+#define OMAP1_DPLL1_SANE_VALUE 60000000
+
+void __init omap1_clk_late_init(void)
+{
+ unsigned long rate = ck_dpll1.rate;
+
+ /* Find the highest supported frequency and enable it */
+ if (omap1_select_table_rate(&virtual_ck_mpu, ~0, arm_ck.rate)) {
+ pr_err("System frequencies not set, using default. Check your config.\n");
+ /*
+ * Reprogramming the DPLL is tricky, it must be done from SRAM.
+ */
+ omap_sram_reprogram_clock(0x2290, 0x0005);
+ ck_dpll1.rate = OMAP1_DPLL1_SANE_VALUE;
+ }
+ propagate_rate(&ck_dpll1);
+ omap1_show_rates();
+ loops_per_jiffy = cpufreq_scale(loops_per_jiffy, rate, ck_dpll1.rate);
+}
diff --git a/arch/arm/mach-omap1/common.h b/arch/arm/mach-omap1/common.h
new file mode 100644
index 0000000000..7a7c3d9eb8
--- /dev/null
+++ b/arch/arm/mach-omap1/common.h
@@ -0,0 +1,78 @@
+/*
+ *
+ * Header for code common to all OMAP1 machines.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP1_COMMON_H
+#define __ARCH_ARM_MACH_OMAP1_COMMON_H
+
+#include <linux/platform_data/i2c-omap.h>
+#include <linux/reboot.h>
+
+#include <asm/exception.h>
+
+#include "irqs.h"
+#include "soc.h"
+#include "i2c.h"
+
+#ifdef CONFIG_OMAP_SERIAL_WAKE
+int omap_serial_wakeup_init(void);
+#else
+static inline int omap_serial_wakeup_init(void)
+{
+ return 0;
+}
+#endif
+
+void omap1_map_io(void);
+void omap1_init_early(void);
+void omap1_init_irq(void);
+void __exception_irq_entry omap1_handle_irq(struct pt_regs *regs);
+void omap1_init_late(void);
+void omap1_restart(enum reboot_mode, const char *);
+
+extern void __init omap_check_revision(void);
+
+struct nand_chip;
+extern void omap1_nand_cmd_ctl(struct nand_chip *this, int cmd,
+ unsigned int ctrl);
+
+extern void omap1_timer_init(void);
+#ifdef CONFIG_OMAP_32K_TIMER
+extern int omap_32k_timer_init(void);
+#else
+static inline int __init omap_32k_timer_init(void)
+{
+ return -ENODEV;
+}
+#endif
+
+#ifdef CONFIG_ARCH_OMAP16XX
+extern int ocpi_enable(void);
+#else
+static inline int ocpi_enable(void) { return 0; }
+#endif
+
+extern u32 omap1_get_reset_sources(void);
+
+#endif /* __ARCH_ARM_MACH_OMAP1_COMMON_H */
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
new file mode 100644
index 0000000000..8b2c5f911e
--- /dev/null
+++ b/arch/arm/mach-omap1/devices.c
@@ -0,0 +1,363 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * linux/arch/arm/mach-omap1/devices.c
+ *
+ * OMAP1 platform device setup/initialization
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+
+#include <linux/platform_data/omap-wd-timer.h>
+#include <linux/soc/ti/omap1-io.h>
+
+#include <asm/mach/map.h>
+
+#include "tc.h"
+#include "mux.h"
+
+#include "hardware.h"
+#include "common.h"
+#include "clock.h"
+#include "mmc.h"
+#include "sram.h"
+
+#if IS_ENABLED(CONFIG_RTC_DRV_OMAP)
+
+#define OMAP_RTC_BASE 0xfffb4800
+
+static struct resource rtc_resources[] = {
+ {
+ .start = OMAP_RTC_BASE,
+ .end = OMAP_RTC_BASE + 0x5f,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_RTC_TIMER,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = INT_RTC_ALARM,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device omap_rtc_device = {
+ .name = "omap_rtc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(rtc_resources),
+ .resource = rtc_resources,
+};
+
+static void omap_init_rtc(void)
+{
+ (void) platform_device_register(&omap_rtc_device);
+}
+#else
+static inline void omap_init_rtc(void) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#if IS_ENABLED(CONFIG_MMC_OMAP)
+
+static inline void omap1_mmc_mux(struct omap_mmc_platform_data *mmc_controller,
+ int controller_nr)
+{
+ if (controller_nr == 0) {
+ omap_cfg_reg(MMC_CMD);
+ omap_cfg_reg(MMC_CLK);
+ omap_cfg_reg(MMC_DAT0);
+
+ if (cpu_is_omap1710()) {
+ omap_cfg_reg(M15_1710_MMC_CLKI);
+ omap_cfg_reg(P19_1710_MMC_CMDDIR);
+ omap_cfg_reg(P20_1710_MMC_DATDIR0);
+ }
+ if (mmc_controller->slots[0].wires == 4) {
+ omap_cfg_reg(MMC_DAT1);
+ /* NOTE: DAT2 can be on W10 (here) or M15 */
+ if (!mmc_controller->slots[0].nomux)
+ omap_cfg_reg(MMC_DAT2);
+ omap_cfg_reg(MMC_DAT3);
+ }
+ }
+
+ /* Block 2 is on newer chips, and has many pinout options */
+ if (cpu_is_omap16xx() && controller_nr == 1) {
+ if (!mmc_controller->slots[1].nomux) {
+ omap_cfg_reg(Y8_1610_MMC2_CMD);
+ omap_cfg_reg(Y10_1610_MMC2_CLK);
+ omap_cfg_reg(R18_1610_MMC2_CLKIN);
+ omap_cfg_reg(W8_1610_MMC2_DAT0);
+ if (mmc_controller->slots[1].wires == 4) {
+ omap_cfg_reg(V8_1610_MMC2_DAT1);
+ omap_cfg_reg(W15_1610_MMC2_DAT2);
+ omap_cfg_reg(R10_1610_MMC2_DAT3);
+ }
+
+ /* These are needed for the level shifter */
+ omap_cfg_reg(V9_1610_MMC2_CMDDIR);
+ omap_cfg_reg(V5_1610_MMC2_DATDIR0);
+ omap_cfg_reg(W19_1610_MMC2_DATDIR1);
+ }
+
+ /* Feedback clock must be set on OMAP-1710 MMC2 */
+ if (cpu_is_omap1710())
+ omap_writel(omap_readl(MOD_CONF_CTRL_1) | (1 << 24),
+ MOD_CONF_CTRL_1);
+ }
+}
+
+#define OMAP_MMC_NR_RES 4
+
+/*
+ * Register MMC devices.
+ */
+static int __init omap_mmc_add(const char *name, int id, unsigned long base,
+ unsigned long size, unsigned int irq,
+ unsigned rx_req, unsigned tx_req,
+ struct omap_mmc_platform_data *data)
+{
+ struct platform_device *pdev;
+ struct resource res[OMAP_MMC_NR_RES];
+ int ret;
+
+ pdev = platform_device_alloc(name, id);
+ if (!pdev)
+ return -ENOMEM;
+
+ memset(res, 0, OMAP_MMC_NR_RES * sizeof(struct resource));
+ res[0].start = base;
+ res[0].end = base + size - 1;
+ res[0].flags = IORESOURCE_MEM;
+ res[1].start = res[1].end = irq;
+ res[1].flags = IORESOURCE_IRQ;
+ res[2].start = rx_req;
+ res[2].name = "rx";
+ res[2].flags = IORESOURCE_DMA;
+ res[3].start = tx_req;
+ res[3].name = "tx";
+ res[3].flags = IORESOURCE_DMA;
+
+ if (cpu_is_omap15xx())
+ data->slots[0].features = MMC_OMAP15XX;
+ if (cpu_is_omap16xx())
+ data->slots[0].features = MMC_OMAP16XX;
+
+ ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
+ if (ret == 0)
+ ret = platform_device_add_data(pdev, data, sizeof(*data));
+ if (ret)
+ goto fail;
+
+ ret = platform_device_add(pdev);
+ if (ret)
+ goto fail;
+
+ /* return device handle to board setup code */
+ data->dev = &pdev->dev;
+ return 0;
+
+fail:
+ platform_device_put(pdev);
+ return ret;
+}
+
+void __init omap1_init_mmc(struct omap_mmc_platform_data **mmc_data,
+ int nr_controllers)
+{
+ int i;
+
+ for (i = 0; i < nr_controllers; i++) {
+ unsigned long base, size;
+ unsigned rx_req, tx_req;
+ unsigned int irq = 0;
+
+ if (!mmc_data[i])
+ continue;
+
+ omap1_mmc_mux(mmc_data[i], i);
+
+ switch (i) {
+ case 0:
+ base = OMAP1_MMC1_BASE;
+ irq = INT_MMC;
+ rx_req = 22;
+ tx_req = 21;
+ break;
+ case 1:
+ if (!cpu_is_omap16xx())
+ return;
+ base = OMAP1_MMC2_BASE;
+ irq = INT_1610_MMC2;
+ rx_req = 55;
+ tx_req = 54;
+ break;
+ default:
+ continue;
+ }
+ size = OMAP1_MMC_SIZE;
+
+ omap_mmc_add("mmci-omap", i, base, size, irq,
+ rx_req, tx_req, mmc_data[i]);
+ }
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* Numbering for the SPI-capable controllers when used for SPI:
+ * spi = 1
+ * uwire = 2
+ * mmc1..2 = 3..4
+ * mcbsp1..3 = 5..7
+ */
+
+#if IS_ENABLED(CONFIG_SPI_OMAP_UWIRE)
+
+#define OMAP_UWIRE_BASE 0xfffb3000
+
+static struct resource uwire_resources[] = {
+ {
+ .start = OMAP_UWIRE_BASE,
+ .end = OMAP_UWIRE_BASE + 0x20,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device omap_uwire_device = {
+ .name = "omap_uwire",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(uwire_resources),
+ .resource = uwire_resources,
+};
+
+static void omap_init_uwire(void)
+{
+ /* FIXME define and use a boot tag; not all boards will be hooking
+ * up devices to the microwire controller, and multi-board configs
+ * mean that CONFIG_SPI_OMAP_UWIRE may be configured anyway...
+ */
+
+ /* board-specific code must configure chipselects (only a few
+ * are normally used) and SCLK/SDI/SDO (each has two choices).
+ */
+ (void) platform_device_register(&omap_uwire_device);
+}
+#else
+static inline void omap_init_uwire(void) {}
+#endif
+
+
+#define OMAP1_RNG_BASE 0xfffe5000
+
+static struct resource omap1_rng_resources[] = {
+ {
+ .start = OMAP1_RNG_BASE,
+ .end = OMAP1_RNG_BASE + 0x4f,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device omap1_rng_device = {
+ .name = "omap_rng",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(omap1_rng_resources),
+ .resource = omap1_rng_resources,
+};
+
+static void omap1_init_rng(void)
+{
+ if (!cpu_is_omap16xx())
+ return;
+
+ (void) platform_device_register(&omap1_rng_device);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * This gets called after board-specific INIT_MACHINE, and initializes most
+ * on-chip peripherals accessible on this board (except for few like USB):
+ *
+ * (a) Does any "standard config" pin muxing needed. Board-specific
+ * code will have muxed GPIO pins and done "nonstandard" setup;
+ * that code could live in the boot loader.
+ * (b) Populating board-specific platform_data with the data drivers
+ * rely on to handle wiring variations.
+ * (c) Creating platform devices as meaningful on this board and
+ * with this kernel configuration.
+ *
+ * Claiming GPIOs, and setting their direction and initial values, is the
+ * responsibility of the device drivers. So is responding to probe().
+ *
+ * Board-specific knowledge like creating devices or pin setup is to be
+ * kept out of drivers as much as possible. In particular, pin setup
+ * may be handled by the boot loader, and drivers should expect it will
+ * normally have been done by the time they're probed.
+ */
+static int __init omap1_init_devices(void)
+{
+ if (!cpu_class_is_omap1())
+ return -ENODEV;
+
+ omap1_sram_init();
+ omap1_clk_late_init();
+
+ /* please keep these calls, and their implementations above,
+ * in alphabetical order so they're easier to sort through.
+ */
+
+ omap_init_rtc();
+ omap_init_uwire();
+ omap1_init_rng();
+
+ return 0;
+}
+arch_initcall(omap1_init_devices);
+
+#if IS_ENABLED(CONFIG_OMAP_WATCHDOG)
+
+static struct resource wdt_resources[] = {
+ {
+ .start = 0xfffeb000,
+ .end = 0xfffeb07F,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device omap_wdt_device = {
+ .name = "omap_wdt",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(wdt_resources),
+ .resource = wdt_resources,
+};
+
+static int __init omap_init_wdt(void)
+{
+ struct omap_wd_timer_platform_data pdata;
+ int ret;
+
+ if (!cpu_is_omap16xx())
+ return -ENODEV;
+
+ pdata.read_reset_sources = omap1_get_reset_sources;
+
+ ret = platform_device_register(&omap_wdt_device);
+ if (!ret) {
+ ret = platform_device_add_data(&omap_wdt_device, &pdata,
+ sizeof(pdata));
+ if (ret)
+ platform_device_del(&omap_wdt_device);
+ }
+
+ return ret;
+}
+subsys_initcall(omap_init_wdt);
+#endif
diff --git a/arch/arm/mach-omap1/dma.c b/arch/arm/mach-omap1/dma.c
new file mode 100644
index 0000000000..756966cb71
--- /dev/null
+++ b/arch/arm/mach-omap1/dma.c
@@ -0,0 +1,394 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * OMAP1/OMAP7xx - specific DMA driver
+ *
+ * Copyright (C) 2003 - 2008 Nokia Corporation
+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ * DMA channel linking for 1610 by Samuel Ortiz <samuel.ortiz@nokia.com>
+ * Graphics DMA and LCD DMA graphics tranformations
+ * by Imre Deak <imre.deak@nokia.com>
+ * OMAP2/3 support Copyright (C) 2004-2007 Texas Instruments, Inc.
+ * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com/
+ * Converted DMA library into platform driver
+ * - G, Manjunath Kondaiah <manjugk@ti.com>
+ */
+
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/omap-dma.h>
+#include "tc.h"
+
+#include "soc.h"
+
+#define OMAP1_DMA_BASE (0xfffed800)
+
+static u32 enable_1510_mode;
+
+static const struct omap_dma_reg reg_map[] = {
+ [GCR] = { 0x0400, 0x00, OMAP_DMA_REG_16BIT },
+ [GSCR] = { 0x0404, 0x00, OMAP_DMA_REG_16BIT },
+ [GRST1] = { 0x0408, 0x00, OMAP_DMA_REG_16BIT },
+ [HW_ID] = { 0x0442, 0x00, OMAP_DMA_REG_16BIT },
+ [PCH2_ID] = { 0x0444, 0x00, OMAP_DMA_REG_16BIT },
+ [PCH0_ID] = { 0x0446, 0x00, OMAP_DMA_REG_16BIT },
+ [PCH1_ID] = { 0x0448, 0x00, OMAP_DMA_REG_16BIT },
+ [PCHG_ID] = { 0x044a, 0x00, OMAP_DMA_REG_16BIT },
+ [PCHD_ID] = { 0x044c, 0x00, OMAP_DMA_REG_16BIT },
+ [CAPS_0] = { 0x044e, 0x00, OMAP_DMA_REG_2X16BIT },
+ [CAPS_1] = { 0x0452, 0x00, OMAP_DMA_REG_2X16BIT },
+ [CAPS_2] = { 0x0456, 0x00, OMAP_DMA_REG_16BIT },
+ [CAPS_3] = { 0x0458, 0x00, OMAP_DMA_REG_16BIT },
+ [CAPS_4] = { 0x045a, 0x00, OMAP_DMA_REG_16BIT },
+ [PCH2_SR] = { 0x0460, 0x00, OMAP_DMA_REG_16BIT },
+ [PCH0_SR] = { 0x0480, 0x00, OMAP_DMA_REG_16BIT },
+ [PCH1_SR] = { 0x0482, 0x00, OMAP_DMA_REG_16BIT },
+ [PCHD_SR] = { 0x04c0, 0x00, OMAP_DMA_REG_16BIT },
+
+ /* Common Registers */
+ [CSDP] = { 0x0000, 0x40, OMAP_DMA_REG_16BIT },
+ [CCR] = { 0x0002, 0x40, OMAP_DMA_REG_16BIT },
+ [CICR] = { 0x0004, 0x40, OMAP_DMA_REG_16BIT },
+ [CSR] = { 0x0006, 0x40, OMAP_DMA_REG_16BIT },
+ [CEN] = { 0x0010, 0x40, OMAP_DMA_REG_16BIT },
+ [CFN] = { 0x0012, 0x40, OMAP_DMA_REG_16BIT },
+ [CSFI] = { 0x0014, 0x40, OMAP_DMA_REG_16BIT },
+ [CSEI] = { 0x0016, 0x40, OMAP_DMA_REG_16BIT },
+ [CPC] = { 0x0018, 0x40, OMAP_DMA_REG_16BIT }, /* 15xx only */
+ [CSAC] = { 0x0018, 0x40, OMAP_DMA_REG_16BIT },
+ [CDAC] = { 0x001a, 0x40, OMAP_DMA_REG_16BIT },
+ [CDEI] = { 0x001c, 0x40, OMAP_DMA_REG_16BIT },
+ [CDFI] = { 0x001e, 0x40, OMAP_DMA_REG_16BIT },
+ [CLNK_CTRL] = { 0x0028, 0x40, OMAP_DMA_REG_16BIT },
+
+ /* Channel specific register offsets */
+ [CSSA] = { 0x0008, 0x40, OMAP_DMA_REG_2X16BIT },
+ [CDSA] = { 0x000c, 0x40, OMAP_DMA_REG_2X16BIT },
+ [COLOR] = { 0x0020, 0x40, OMAP_DMA_REG_2X16BIT },
+ [CCR2] = { 0x0024, 0x40, OMAP_DMA_REG_16BIT },
+ [LCH_CTRL] = { 0x002a, 0x40, OMAP_DMA_REG_16BIT },
+};
+
+static struct resource res[] __initdata = {
+ [0] = {
+ .start = OMAP1_DMA_BASE,
+ .end = OMAP1_DMA_BASE + SZ_2K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "0",
+ .start = INT_DMA_CH0_6,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .name = "1",
+ .start = INT_DMA_CH1_7,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .name = "2",
+ .start = INT_DMA_CH2_8,
+ .flags = IORESOURCE_IRQ,
+ },
+ [4] = {
+ .name = "3",
+ .start = INT_DMA_CH3,
+ .flags = IORESOURCE_IRQ,
+ },
+ [5] = {
+ .name = "4",
+ .start = INT_DMA_CH4,
+ .flags = IORESOURCE_IRQ,
+ },
+ [6] = {
+ .name = "5",
+ .start = INT_DMA_CH5,
+ .flags = IORESOURCE_IRQ,
+ },
+ /* Handled in lcd_dma.c */
+ [7] = {
+ .name = "6",
+ .start = INT_1610_DMA_CH6,
+ .flags = IORESOURCE_IRQ,
+ },
+ /* irq's for omap16xx and omap7xx */
+ [8] = {
+ .name = "7",
+ .start = INT_1610_DMA_CH7,
+ .flags = IORESOURCE_IRQ,
+ },
+ [9] = {
+ .name = "8",
+ .start = INT_1610_DMA_CH8,
+ .flags = IORESOURCE_IRQ,
+ },
+ [10] = {
+ .name = "9",
+ .start = INT_1610_DMA_CH9,
+ .flags = IORESOURCE_IRQ,
+ },
+ [11] = {
+ .name = "10",
+ .start = INT_1610_DMA_CH10,
+ .flags = IORESOURCE_IRQ,
+ },
+ [12] = {
+ .name = "11",
+ .start = INT_1610_DMA_CH11,
+ .flags = IORESOURCE_IRQ,
+ },
+ [13] = {
+ .name = "12",
+ .start = INT_1610_DMA_CH12,
+ .flags = IORESOURCE_IRQ,
+ },
+ [14] = {
+ .name = "13",
+ .start = INT_1610_DMA_CH13,
+ .flags = IORESOURCE_IRQ,
+ },
+ [15] = {
+ .name = "14",
+ .start = INT_1610_DMA_CH14,
+ .flags = IORESOURCE_IRQ,
+ },
+ [16] = {
+ .name = "15",
+ .start = INT_1610_DMA_CH15,
+ .flags = IORESOURCE_IRQ,
+ },
+ [17] = {
+ .name = "16",
+ .start = INT_DMA_LCD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static void __iomem *dma_base;
+static inline void dma_write(u32 val, int reg, int lch)
+{
+ void __iomem *addr = dma_base;
+
+ addr += reg_map[reg].offset;
+ addr += reg_map[reg].stride * lch;
+
+ __raw_writew(val, addr);
+ if (reg_map[reg].type == OMAP_DMA_REG_2X16BIT)
+ __raw_writew(val >> 16, addr + 2);
+}
+
+static inline u32 dma_read(int reg, int lch)
+{
+ void __iomem *addr = dma_base;
+ uint32_t val;
+
+ addr += reg_map[reg].offset;
+ addr += reg_map[reg].stride * lch;
+
+ val = __raw_readw(addr);
+ if (reg_map[reg].type == OMAP_DMA_REG_2X16BIT)
+ val |= __raw_readw(addr + 2) << 16;
+
+ return val;
+}
+
+static void omap1_clear_lch_regs(int lch)
+{
+ int i;
+
+ for (i = CPC; i <= COLOR; i += 1)
+ dma_write(0, i, lch);
+}
+
+static void omap1_clear_dma(int lch)
+{
+ u32 l;
+
+ l = dma_read(CCR, lch);
+ l &= ~OMAP_DMA_CCR_EN;
+ dma_write(l, CCR, lch);
+
+ /* Clear pending interrupts */
+ l = dma_read(CSR, lch);
+}
+
+static void omap1_show_dma_caps(void)
+{
+ if (enable_1510_mode) {
+ printk(KERN_INFO "DMA support for OMAP15xx initialized\n");
+ } else {
+ u16 w;
+ printk(KERN_INFO "OMAP DMA hardware version %d\n",
+ dma_read(HW_ID, 0));
+ printk(KERN_INFO "DMA capabilities: %08x:%08x:%04x:%04x:%04x\n",
+ dma_read(CAPS_0, 0), dma_read(CAPS_1, 0),
+ dma_read(CAPS_2, 0), dma_read(CAPS_3, 0),
+ dma_read(CAPS_4, 0));
+
+ /* Disable OMAP 3.0/3.1 compatibility mode. */
+ w = dma_read(GSCR, 0);
+ w |= 1 << 3;
+ dma_write(w, GSCR, 0);
+ }
+}
+
+static unsigned configure_dma_errata(void)
+{
+ unsigned errata = 0;
+
+ /*
+ * Erratum 3.2/3.3: sometimes 0 is returned if CSAC/CDAC is
+ * read before the DMA controller finished disabling the channel.
+ */
+ if (!cpu_is_omap15xx())
+ SET_DMA_ERRATA(DMA_ERRATA_3_3);
+
+ return errata;
+}
+
+static const struct platform_device_info omap_dma_dev_info = {
+ .name = "omap-dma-engine",
+ .id = -1,
+ .dma_mask = DMA_BIT_MASK(32),
+ .res = res,
+ .num_res = 1,
+};
+
+/* OMAP1510, OMAP1610*/
+static const struct dma_slave_map omap1xxx_sdma_map[] = {
+ { "omap-mcbsp.1", "tx", SDMA_FILTER_PARAM(8) },
+ { "omap-mcbsp.1", "rx", SDMA_FILTER_PARAM(9) },
+ { "omap-mcbsp.3", "tx", SDMA_FILTER_PARAM(10) },
+ { "omap-mcbsp.3", "rx", SDMA_FILTER_PARAM(11) },
+ { "omap-mcbsp.2", "tx", SDMA_FILTER_PARAM(16) },
+ { "omap-mcbsp.2", "rx", SDMA_FILTER_PARAM(17) },
+ { "mmci-omap.0", "tx", SDMA_FILTER_PARAM(21) },
+ { "mmci-omap.0", "rx", SDMA_FILTER_PARAM(22) },
+ { "omap_udc", "rx0", SDMA_FILTER_PARAM(26) },
+ { "omap_udc", "rx1", SDMA_FILTER_PARAM(27) },
+ { "omap_udc", "rx2", SDMA_FILTER_PARAM(28) },
+ { "omap_udc", "tx0", SDMA_FILTER_PARAM(29) },
+ { "omap_udc", "tx1", SDMA_FILTER_PARAM(30) },
+ { "omap_udc", "tx2", SDMA_FILTER_PARAM(31) },
+ { "mmci-omap.1", "tx", SDMA_FILTER_PARAM(54) },
+ { "mmci-omap.1", "rx", SDMA_FILTER_PARAM(55) },
+};
+
+static struct omap_system_dma_plat_info dma_plat_info __initdata = {
+ .reg_map = reg_map,
+ .channel_stride = 0x40,
+ .show_dma_caps = omap1_show_dma_caps,
+ .clear_lch_regs = omap1_clear_lch_regs,
+ .clear_dma = omap1_clear_dma,
+ .dma_write = dma_write,
+ .dma_read = dma_read,
+};
+
+static int __init omap1_system_dma_init(void)
+{
+ struct omap_system_dma_plat_info p;
+ struct omap_dma_dev_attr *d;
+ struct platform_device *pdev, *dma_pdev;
+ int ret;
+
+ pdev = platform_device_alloc("omap_dma_system", 0);
+ if (!pdev) {
+ pr_err("%s: Unable to device alloc for dma\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ dma_base = ioremap(res[0].start, resource_size(&res[0]));
+ if (!dma_base) {
+ pr_err("%s: Unable to ioremap\n", __func__);
+ ret = -ENODEV;
+ goto exit_device_put;
+ }
+
+ ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
+ if (ret) {
+ dev_err(&pdev->dev, "%s: Unable to add resources for %s%d\n",
+ __func__, pdev->name, pdev->id);
+ goto exit_iounmap;
+ }
+
+ d = kzalloc(sizeof(*d), GFP_KERNEL);
+ if (!d) {
+ ret = -ENOMEM;
+ goto exit_iounmap;
+ }
+
+ /* Valid attributes for omap1 plus processors */
+ if (cpu_is_omap15xx())
+ d->dev_caps = ENABLE_1510_MODE;
+ enable_1510_mode = d->dev_caps & ENABLE_1510_MODE;
+
+ if (cpu_is_omap16xx())
+ d->dev_caps = ENABLE_16XX_MODE;
+
+ d->dev_caps |= SRC_PORT;
+ d->dev_caps |= DST_PORT;
+ d->dev_caps |= SRC_INDEX;
+ d->dev_caps |= DST_INDEX;
+ d->dev_caps |= IS_BURST_ONLY4;
+ d->dev_caps |= CLEAR_CSR_ON_READ;
+ d->dev_caps |= IS_WORD_16;
+
+ /* available logical channels */
+ if (cpu_is_omap15xx()) {
+ d->lch_count = 9;
+ } else {
+ if (d->dev_caps & ENABLE_1510_MODE)
+ d->lch_count = 9;
+ else
+ d->lch_count = 16;
+ }
+
+ p = dma_plat_info;
+ p.dma_attr = d;
+ p.errata = configure_dma_errata();
+
+ p.slave_map = omap1xxx_sdma_map;
+ p.slavecnt = ARRAY_SIZE(omap1xxx_sdma_map);
+
+ ret = platform_device_add_data(pdev, &p, sizeof(p));
+ if (ret) {
+ dev_err(&pdev->dev, "%s: Unable to add resources for %s%d\n",
+ __func__, pdev->name, pdev->id);
+ goto exit_release_d;
+ }
+
+ ret = platform_device_add(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: Unable to add resources for %s%d\n",
+ __func__, pdev->name, pdev->id);
+ goto exit_release_d;
+ }
+
+ dma_pdev = platform_device_register_full(&omap_dma_dev_info);
+ if (IS_ERR(dma_pdev)) {
+ ret = PTR_ERR(dma_pdev);
+ goto exit_release_pdev;
+ }
+
+ return ret;
+
+exit_release_pdev:
+ platform_device_del(pdev);
+exit_release_d:
+ kfree(d);
+exit_iounmap:
+ iounmap(dma_base);
+exit_device_put:
+ platform_device_put(pdev);
+
+ return ret;
+}
+arch_initcall(omap1_system_dma_init);
diff --git a/arch/arm/mach-omap1/fb.c b/arch/arm/mach-omap1/fb.c
new file mode 100644
index 0000000000..b6e952b038
--- /dev/null
+++ b/arch/arm/mach-omap1/fb.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * File: arch/arm/plat-omap/fb.c
+ *
+ * Framebuffer device registration for TI OMAP platforms
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/memblock.h>
+#include <linux/io.h>
+#include <linux/omapfb.h>
+#include <linux/dma-mapping.h>
+#include <linux/irq.h>
+
+#include <asm/mach/map.h>
+
+#include "irqs.h"
+
+#if IS_ENABLED(CONFIG_FB_OMAP)
+
+static bool omapfb_lcd_configured;
+static struct omapfb_platform_data omapfb_config;
+
+static u64 omap_fb_dma_mask = ~(u32)0;
+
+static struct resource omap_fb_resources[] = {
+ {
+ .name = "irq",
+ .start = INT_LCD_CTRL,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "irq",
+ .start = INT_SOSSI_MATCH,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device omap_fb_device = {
+ .name = "omapfb",
+ .id = -1,
+ .dev = {
+ .dma_mask = &omap_fb_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &omapfb_config,
+ },
+ .num_resources = ARRAY_SIZE(omap_fb_resources),
+ .resource = omap_fb_resources,
+};
+
+void __init omapfb_set_lcd_config(const struct omap_lcd_config *config)
+{
+ omapfb_config.lcd = *config;
+ omapfb_lcd_configured = true;
+}
+
+static int __init omap_init_fb(void)
+{
+ /*
+ * If the board file has not set the lcd config with
+ * omapfb_set_lcd_config(), don't bother registering the omapfb device
+ */
+ if (!omapfb_lcd_configured)
+ return 0;
+
+ return platform_device_register(&omap_fb_device);
+}
+
+arch_initcall(omap_init_fb);
+
+#else
+
+void __init omapfb_set_lcd_config(const struct omap_lcd_config *config)
+{
+}
+
+#endif
diff --git a/arch/arm/mach-omap1/flash.c b/arch/arm/mach-omap1/flash.c
new file mode 100644
index 0000000000..0a3ddb3b66
--- /dev/null
+++ b/arch/arm/mach-omap1/flash.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Flash support for OMAP1
+ */
+
+#include <linux/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/soc/ti/omap1-io.h>
+
+#include "tc.h"
+
+#include "flash.h"
+
+
+void omap1_set_vpp(struct platform_device *pdev, int enable)
+{
+ u32 l;
+
+ l = omap_readl(EMIFS_CONFIG);
+ if (enable)
+ l |= OMAP_EMIFS_CONFIG_WP;
+ else
+ l &= ~OMAP_EMIFS_CONFIG_WP;
+ omap_writel(l, EMIFS_CONFIG);
+}
diff --git a/arch/arm/mach-omap1/flash.h b/arch/arm/mach-omap1/flash.h
new file mode 100644
index 0000000000..7077224f65
--- /dev/null
+++ b/arch/arm/mach-omap1/flash.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Flash support for OMAP1
+ */
+
+#ifndef __OMAP_FLASH_H
+#define __OMAP_FLASH_H
+
+#include <linux/mtd/map.h>
+
+struct platform_device;
+extern void omap1_set_vpp(struct platform_device *pdev, int enable);
+
+#endif
diff --git a/arch/arm/mach-omap1/gpio15xx.c b/arch/arm/mach-omap1/gpio15xx.c
new file mode 100644
index 0000000000..6724af4925
--- /dev/null
+++ b/arch/arm/mach-omap1/gpio15xx.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * OMAP15xx specific gpio init
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ * Author:
+ * Charulatha V <charu@ti.com>
+ */
+
+#include <linux/platform_data/gpio-omap.h>
+#include <linux/soc/ti/omap1-soc.h>
+#include <asm/irq.h>
+
+#include "irqs.h"
+
+#define OMAP1_MPUIO_VBASE OMAP1_MPUIO_BASE
+#define OMAP1510_GPIO_BASE 0xFFFCE000
+
+/* gpio1 */
+static struct resource omap15xx_mpu_gpio_resources[] = {
+ {
+ .start = OMAP1_MPUIO_VBASE,
+ .end = OMAP1_MPUIO_VBASE + SZ_2K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_MPUIO,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct omap_gpio_reg_offs omap15xx_mpuio_regs = {
+ .revision = USHRT_MAX,
+ .direction = OMAP_MPUIO_IO_CNTL,
+ .datain = OMAP_MPUIO_INPUT_LATCH,
+ .dataout = OMAP_MPUIO_OUTPUT,
+ .irqstatus = OMAP_MPUIO_GPIO_INT,
+ .irqenable = OMAP_MPUIO_GPIO_MASKIT,
+ .irqenable_inv = true,
+ .irqctrl = OMAP_MPUIO_GPIO_INT_EDGE,
+};
+
+static struct omap_gpio_platform_data omap15xx_mpu_gpio_config = {
+ .is_mpuio = true,
+ .bank_width = 16,
+ .bank_stride = 1,
+ .regs = &omap15xx_mpuio_regs,
+};
+
+static struct platform_device omap15xx_mpu_gpio = {
+ .name = "omap_gpio",
+ .id = 0,
+ .dev = {
+ .platform_data = &omap15xx_mpu_gpio_config,
+ },
+ .num_resources = ARRAY_SIZE(omap15xx_mpu_gpio_resources),
+ .resource = omap15xx_mpu_gpio_resources,
+};
+
+/* gpio2 */
+static struct resource omap15xx_gpio_resources[] = {
+ {
+ .start = OMAP1510_GPIO_BASE,
+ .end = OMAP1510_GPIO_BASE + SZ_2K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_GPIO_BANK1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct omap_gpio_reg_offs omap15xx_gpio_regs = {
+ .revision = USHRT_MAX,
+ .direction = OMAP1510_GPIO_DIR_CONTROL,
+ .datain = OMAP1510_GPIO_DATA_INPUT,
+ .dataout = OMAP1510_GPIO_DATA_OUTPUT,
+ .irqstatus = OMAP1510_GPIO_INT_STATUS,
+ .irqenable = OMAP1510_GPIO_INT_MASK,
+ .irqenable_inv = true,
+ .irqctrl = OMAP1510_GPIO_INT_CONTROL,
+ .pinctrl = OMAP1510_GPIO_PIN_CONTROL,
+};
+
+static struct omap_gpio_platform_data omap15xx_gpio_config = {
+ .bank_width = 16,
+ .regs = &omap15xx_gpio_regs,
+};
+
+static struct platform_device omap15xx_gpio = {
+ .name = "omap_gpio",
+ .id = 1,
+ .dev = {
+ .platform_data = &omap15xx_gpio_config,
+ },
+ .num_resources = ARRAY_SIZE(omap15xx_gpio_resources),
+ .resource = omap15xx_gpio_resources,
+};
+
+/*
+ * omap15xx_gpio_init needs to be done before
+ * machine_init functions access gpio APIs.
+ * Hence omap15xx_gpio_init is a postcore_initcall.
+ */
+static int __init omap15xx_gpio_init(void)
+{
+ if (!cpu_is_omap15xx())
+ return -EINVAL;
+
+ platform_device_register(&omap15xx_mpu_gpio);
+ platform_device_register(&omap15xx_gpio);
+
+ return 0;
+}
+postcore_initcall(omap15xx_gpio_init);
diff --git a/arch/arm/mach-omap1/gpio16xx.c b/arch/arm/mach-omap1/gpio16xx.c
new file mode 100644
index 0000000000..55acec22fe
--- /dev/null
+++ b/arch/arm/mach-omap1/gpio16xx.c
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * OMAP16xx specific gpio init
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ * Author:
+ * Charulatha V <charu@ti.com>
+ */
+
+#include <linux/platform_data/gpio-omap.h>
+#include <linux/soc/ti/omap1-io.h>
+
+#include "hardware.h"
+#include "irqs.h"
+#include "soc.h"
+
+#define OMAP1610_GPIO1_BASE 0xfffbe400
+#define OMAP1610_GPIO2_BASE 0xfffbec00
+#define OMAP1610_GPIO3_BASE 0xfffbb400
+#define OMAP1610_GPIO4_BASE 0xfffbbc00
+#define OMAP1_MPUIO_VBASE OMAP1_MPUIO_BASE
+
+/* smart idle, enable wakeup */
+#define SYSCONFIG_WORD 0x14
+
+/* mpu gpio */
+static struct resource omap16xx_mpu_gpio_resources[] = {
+ {
+ .start = OMAP1_MPUIO_VBASE,
+ .end = OMAP1_MPUIO_VBASE + SZ_2K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_MPUIO,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct omap_gpio_reg_offs omap16xx_mpuio_regs = {
+ .revision = USHRT_MAX,
+ .direction = OMAP_MPUIO_IO_CNTL,
+ .datain = OMAP_MPUIO_INPUT_LATCH,
+ .dataout = OMAP_MPUIO_OUTPUT,
+ .irqstatus = OMAP_MPUIO_GPIO_INT,
+ .irqenable = OMAP_MPUIO_GPIO_MASKIT,
+ .irqenable_inv = true,
+ .irqctrl = OMAP_MPUIO_GPIO_INT_EDGE,
+};
+
+static struct omap_gpio_platform_data omap16xx_mpu_gpio_config = {
+ .is_mpuio = true,
+ .bank_width = 16,
+ .bank_stride = 1,
+ .regs = &omap16xx_mpuio_regs,
+};
+
+static struct platform_device omap16xx_mpu_gpio = {
+ .name = "omap_gpio",
+ .id = 0,
+ .dev = {
+ .platform_data = &omap16xx_mpu_gpio_config,
+ },
+ .num_resources = ARRAY_SIZE(omap16xx_mpu_gpio_resources),
+ .resource = omap16xx_mpu_gpio_resources,
+};
+
+/* gpio1 */
+static struct resource omap16xx_gpio1_resources[] = {
+ {
+ .start = OMAP1610_GPIO1_BASE,
+ .end = OMAP1610_GPIO1_BASE + SZ_2K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_GPIO_BANK1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct omap_gpio_reg_offs omap16xx_gpio_regs = {
+ .revision = OMAP1610_GPIO_REVISION,
+ .direction = OMAP1610_GPIO_DIRECTION,
+ .set_dataout = OMAP1610_GPIO_SET_DATAOUT,
+ .clr_dataout = OMAP1610_GPIO_CLEAR_DATAOUT,
+ .datain = OMAP1610_GPIO_DATAIN,
+ .dataout = OMAP1610_GPIO_DATAOUT,
+ .irqstatus = OMAP1610_GPIO_IRQSTATUS1,
+ .irqenable = OMAP1610_GPIO_IRQENABLE1,
+ .set_irqenable = OMAP1610_GPIO_SET_IRQENABLE1,
+ .clr_irqenable = OMAP1610_GPIO_CLEAR_IRQENABLE1,
+ .wkup_en = OMAP1610_GPIO_WAKEUPENABLE,
+ .edgectrl1 = OMAP1610_GPIO_EDGE_CTRL1,
+ .edgectrl2 = OMAP1610_GPIO_EDGE_CTRL2,
+};
+
+static struct omap_gpio_platform_data omap16xx_gpio1_config = {
+ .bank_width = 16,
+ .regs = &omap16xx_gpio_regs,
+};
+
+static struct platform_device omap16xx_gpio1 = {
+ .name = "omap_gpio",
+ .id = 1,
+ .dev = {
+ .platform_data = &omap16xx_gpio1_config,
+ },
+ .num_resources = ARRAY_SIZE(omap16xx_gpio1_resources),
+ .resource = omap16xx_gpio1_resources,
+};
+
+/* gpio2 */
+static struct resource omap16xx_gpio2_resources[] = {
+ {
+ .start = OMAP1610_GPIO2_BASE,
+ .end = OMAP1610_GPIO2_BASE + SZ_2K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_1610_GPIO_BANK2,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct omap_gpio_platform_data omap16xx_gpio2_config = {
+ .bank_width = 16,
+ .regs = &omap16xx_gpio_regs,
+};
+
+static struct platform_device omap16xx_gpio2 = {
+ .name = "omap_gpio",
+ .id = 2,
+ .dev = {
+ .platform_data = &omap16xx_gpio2_config,
+ },
+ .num_resources = ARRAY_SIZE(omap16xx_gpio2_resources),
+ .resource = omap16xx_gpio2_resources,
+};
+
+/* gpio3 */
+static struct resource omap16xx_gpio3_resources[] = {
+ {
+ .start = OMAP1610_GPIO3_BASE,
+ .end = OMAP1610_GPIO3_BASE + SZ_2K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_1610_GPIO_BANK3,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct omap_gpio_platform_data omap16xx_gpio3_config = {
+ .bank_width = 16,
+ .regs = &omap16xx_gpio_regs,
+};
+
+static struct platform_device omap16xx_gpio3 = {
+ .name = "omap_gpio",
+ .id = 3,
+ .dev = {
+ .platform_data = &omap16xx_gpio3_config,
+ },
+ .num_resources = ARRAY_SIZE(omap16xx_gpio3_resources),
+ .resource = omap16xx_gpio3_resources,
+};
+
+/* gpio4 */
+static struct resource omap16xx_gpio4_resources[] = {
+ {
+ .start = OMAP1610_GPIO4_BASE,
+ .end = OMAP1610_GPIO4_BASE + SZ_2K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_1610_GPIO_BANK4,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct omap_gpio_platform_data omap16xx_gpio4_config = {
+ .bank_width = 16,
+ .regs = &omap16xx_gpio_regs,
+};
+
+static struct platform_device omap16xx_gpio4 = {
+ .name = "omap_gpio",
+ .id = 4,
+ .dev = {
+ .platform_data = &omap16xx_gpio4_config,
+ },
+ .num_resources = ARRAY_SIZE(omap16xx_gpio4_resources),
+ .resource = omap16xx_gpio4_resources,
+};
+
+static struct platform_device *omap16xx_gpio_dev[] __initdata = {
+ &omap16xx_mpu_gpio,
+ &omap16xx_gpio1,
+ &omap16xx_gpio2,
+ &omap16xx_gpio3,
+ &omap16xx_gpio4,
+};
+
+/*
+ * omap16xx_gpio_init needs to be done before
+ * machine_init functions access gpio APIs.
+ * Hence omap16xx_gpio_init is a postcore_initcall.
+ */
+static int __init omap16xx_gpio_init(void)
+{
+ int i;
+ void __iomem *base;
+ struct resource *res;
+ struct platform_device *pdev;
+ struct omap_gpio_platform_data *pdata;
+
+ if (!cpu_is_omap16xx())
+ return -EINVAL;
+
+ /*
+ * Enable system clock for GPIO module.
+ * The CAM_CLK_CTRL *is* really the right place.
+ */
+ omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04,
+ ULPD_CAM_CLK_CTRL);
+
+ for (i = 0; i < ARRAY_SIZE(omap16xx_gpio_dev); i++) {
+ pdev = omap16xx_gpio_dev[i];
+ pdata = pdev->dev.platform_data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(!res)) {
+ dev_err(&pdev->dev, "Invalid mem resource.\n");
+ return -ENODEV;
+ }
+
+ base = ioremap(res->start, resource_size(res));
+ if (unlikely(!base)) {
+ dev_err(&pdev->dev, "ioremap failed.\n");
+ return -ENOMEM;
+ }
+
+ __raw_writel(SYSCONFIG_WORD, base + OMAP1610_GPIO_SYSCONFIG);
+ iounmap(base);
+
+ platform_device_register(omap16xx_gpio_dev[i]);
+ }
+
+ return 0;
+}
+postcore_initcall(omap16xx_gpio_init);
diff --git a/arch/arm/mach-omap1/hardware.h b/arch/arm/mach-omap1/hardware.h
new file mode 100644
index 0000000000..0aa571c9e0
--- /dev/null
+++ b/arch/arm/mach-omap1/hardware.h
@@ -0,0 +1,235 @@
+/*
+ * Hardware definitions for TI OMAP processors and boards
+ *
+ * NOTE: Please put device driver specific defines into a separate header
+ * file for each driver.
+ *
+ * Copyright (C) 2001 RidgeRun, Inc.
+ * Author: RidgeRun, Inc. Greg Lonnon <glonnon@ridgerun.com>
+ *
+ * Reorganized for Linux-2.6 by Tony Lindgren <tony@atomide.com>
+ * and Dirk Behme <dirk.behme@de.bosch.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ASM_ARCH_OMAP_HARDWARE_H
+#define __ASM_ARCH_OMAP_HARDWARE_H
+
+#include <linux/sizes.h>
+#include <linux/soc/ti/omap1-io.h>
+#ifndef __ASSEMBLER__
+#include <asm/types.h>
+#include <linux/soc/ti/omap1-soc.h>
+
+#include "tc.h"
+
+/* Almost all documentation for chip and board memory maps assumes
+ * BM is clear. Most devel boards have a switch to control booting
+ * from NOR flash (using external chipselect 3) rather than mask ROM,
+ * which uses BM to interchange the physical CS0 and CS3 addresses.
+ */
+static inline u32 omap_cs0m_phys(void)
+{
+ return (omap_readl(EMIFS_CONFIG) & OMAP_EMIFS_CONFIG_BM)
+ ? OMAP_CS3_PHYS : 0;
+}
+
+static inline u32 omap_cs3_phys(void)
+{
+ return (omap_readl(EMIFS_CONFIG) & OMAP_EMIFS_CONFIG_BM)
+ ? 0 : OMAP_CS3_PHYS;
+}
+
+#endif /* ifndef __ASSEMBLER__ */
+
+#define OMAP1_IO_OFFSET 0x00f00000 /* Virtual IO = 0xff0b0000 */
+#define OMAP1_IO_ADDRESS(pa) IOMEM((pa) - OMAP1_IO_OFFSET)
+
+#include "serial.h"
+
+/*
+ * ---------------------------------------------------------------------------
+ * Common definitions for all OMAP processors
+ * NOTE: Put all processor or board specific parts to the special header
+ * files.
+ * ---------------------------------------------------------------------------
+ */
+
+/*
+ * ----------------------------------------------------------------------------
+ * Timers
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP_MPU_TIMER1_BASE (0xfffec500)
+#define OMAP_MPU_TIMER2_BASE (0xfffec600)
+#define OMAP_MPU_TIMER3_BASE (0xfffec700)
+#define MPU_TIMER_FREE (1 << 6)
+#define MPU_TIMER_CLOCK_ENABLE (1 << 5)
+#define MPU_TIMER_AR (1 << 1)
+#define MPU_TIMER_ST (1 << 0)
+
+/*
+ * ---------------------------------------------------------------------------
+ * Watchdog timer
+ * ---------------------------------------------------------------------------
+ */
+
+/* Watchdog timer within the OMAP3.2 gigacell */
+#define OMAP_MPU_WATCHDOG_BASE (0xfffec800)
+#define OMAP_WDT_TIMER (OMAP_MPU_WATCHDOG_BASE + 0x0)
+#define OMAP_WDT_LOAD_TIM (OMAP_MPU_WATCHDOG_BASE + 0x4)
+#define OMAP_WDT_READ_TIM (OMAP_MPU_WATCHDOG_BASE + 0x4)
+#define OMAP_WDT_TIMER_MODE (OMAP_MPU_WATCHDOG_BASE + 0x8)
+
+/*
+ * ---------------------------------------------------------------------------
+ * Interrupts
+ * ---------------------------------------------------------------------------
+ */
+#ifdef CONFIG_ARCH_OMAP1
+
+/*
+ * XXX: These probably want to be moved to arch/arm/mach-omap/omap1/irq.c
+ * or something similar.. -- PFM.
+ */
+
+#define OMAP_IH1_BASE 0xfffecb00
+#define OMAP_IH2_BASE 0xfffe0000
+#define OMAP_IH2_0_BASE (0xfffe0000)
+#define OMAP_IH2_1_BASE (0xfffe0100)
+#define OMAP_IH2_2_BASE (0xfffe0200)
+#define OMAP_IH2_3_BASE (0xfffe0300)
+
+#define OMAP_IH1_ITR (OMAP_IH1_BASE + 0x00)
+#define OMAP_IH1_MIR (OMAP_IH1_BASE + 0x04)
+#define OMAP_IH1_SIR_IRQ (OMAP_IH1_BASE + 0x10)
+#define OMAP_IH1_SIR_FIQ (OMAP_IH1_BASE + 0x14)
+#define OMAP_IH1_CONTROL (OMAP_IH1_BASE + 0x18)
+#define OMAP_IH1_ILR0 (OMAP_IH1_BASE + 0x1c)
+#define OMAP_IH1_ISR (OMAP_IH1_BASE + 0x9c)
+
+#define OMAP_IH2_ITR (OMAP_IH2_BASE + 0x00)
+#define OMAP_IH2_MIR (OMAP_IH2_BASE + 0x04)
+#define OMAP_IH2_SIR_IRQ (OMAP_IH2_BASE + 0x10)
+#define OMAP_IH2_SIR_FIQ (OMAP_IH2_BASE + 0x14)
+#define OMAP_IH2_CONTROL (OMAP_IH2_BASE + 0x18)
+#define OMAP_IH2_ILR0 (OMAP_IH2_BASE + 0x1c)
+#define OMAP_IH2_ISR (OMAP_IH2_BASE + 0x9c)
+
+#define OMAP_IH2_0_ITR (OMAP_IH2_0_BASE + 0x00)
+#define OMAP_IH2_0_MIR (OMAP_IH2_0_BASE + 0x04)
+#define OMAP_IH2_0_SIR_IRQ (OMAP_IH2_0_BASE + 0x10)
+#define OMAP_IH2_0_SIR_FIQ (OMAP_IH2_0_BASE + 0x14)
+#define OMAP_IH2_0_CONTROL (OMAP_IH2_0_BASE + 0x18)
+#define OMAP_IH2_0_ILR0 (OMAP_IH2_0_BASE + 0x1c)
+#define OMAP_IH2_0_ISR (OMAP_IH2_0_BASE + 0x9c)
+
+#define OMAP_IH2_1_ITR (OMAP_IH2_1_BASE + 0x00)
+#define OMAP_IH2_1_MIR (OMAP_IH2_1_BASE + 0x04)
+#define OMAP_IH2_1_SIR_IRQ (OMAP_IH2_1_BASE + 0x10)
+#define OMAP_IH2_1_SIR_FIQ (OMAP_IH2_1_BASE + 0x14)
+#define OMAP_IH2_1_CONTROL (OMAP_IH2_1_BASE + 0x18)
+#define OMAP_IH2_1_ILR1 (OMAP_IH2_1_BASE + 0x1c)
+#define OMAP_IH2_1_ISR (OMAP_IH2_1_BASE + 0x9c)
+
+#define OMAP_IH2_2_ITR (OMAP_IH2_2_BASE + 0x00)
+#define OMAP_IH2_2_MIR (OMAP_IH2_2_BASE + 0x04)
+#define OMAP_IH2_2_SIR_IRQ (OMAP_IH2_2_BASE + 0x10)
+#define OMAP_IH2_2_SIR_FIQ (OMAP_IH2_2_BASE + 0x14)
+#define OMAP_IH2_2_CONTROL (OMAP_IH2_2_BASE + 0x18)
+#define OMAP_IH2_2_ILR2 (OMAP_IH2_2_BASE + 0x1c)
+#define OMAP_IH2_2_ISR (OMAP_IH2_2_BASE + 0x9c)
+
+#define OMAP_IH2_3_ITR (OMAP_IH2_3_BASE + 0x00)
+#define OMAP_IH2_3_MIR (OMAP_IH2_3_BASE + 0x04)
+#define OMAP_IH2_3_SIR_IRQ (OMAP_IH2_3_BASE + 0x10)
+#define OMAP_IH2_3_SIR_FIQ (OMAP_IH2_3_BASE + 0x14)
+#define OMAP_IH2_3_CONTROL (OMAP_IH2_3_BASE + 0x18)
+#define OMAP_IH2_3_ILR3 (OMAP_IH2_3_BASE + 0x1c)
+#define OMAP_IH2_3_ISR (OMAP_IH2_3_BASE + 0x9c)
+
+#define IRQ_ITR_REG_OFFSET 0x00
+#define IRQ_MIR_REG_OFFSET 0x04
+#define IRQ_SIR_IRQ_REG_OFFSET 0x10
+#define IRQ_SIR_FIQ_REG_OFFSET 0x14
+#define IRQ_CONTROL_REG_OFFSET 0x18
+#define IRQ_ISR_REG_OFFSET 0x9c
+#define IRQ_ILR0_REG_OFFSET 0x1c
+#define IRQ_GMR_REG_OFFSET 0xa0
+
+#endif
+
+/* Timer32K for 1610 and 1710*/
+#define OMAP_TIMER32K_BASE 0xFFFBC400
+
+/*
+ * ---------------------------------------------------------------------------
+ * TIPB bus interface
+ * ---------------------------------------------------------------------------
+ */
+#define TIPB_PUBLIC_CNTL_BASE 0xfffed300
+#define MPU_PUBLIC_TIPB_CNTL (TIPB_PUBLIC_CNTL_BASE + 0x8)
+#define TIPB_PRIVATE_CNTL_BASE 0xfffeca00
+#define MPU_PRIVATE_TIPB_CNTL (TIPB_PRIVATE_CNTL_BASE + 0x8)
+
+/*
+ * ----------------------------------------------------------------------------
+ * MPUI interface
+ * ----------------------------------------------------------------------------
+ */
+#define MPUI_BASE (0xfffec900)
+#define MPUI_CTRL (MPUI_BASE + 0x0)
+#define MPUI_DEBUG_ADDR (MPUI_BASE + 0x4)
+#define MPUI_DEBUG_DATA (MPUI_BASE + 0x8)
+#define MPUI_DEBUG_FLAG (MPUI_BASE + 0xc)
+#define MPUI_STATUS_REG (MPUI_BASE + 0x10)
+#define MPUI_DSP_STATUS (MPUI_BASE + 0x14)
+#define MPUI_DSP_BOOT_CONFIG (MPUI_BASE + 0x18)
+#define MPUI_DSP_API_CONFIG (MPUI_BASE + 0x1c)
+
+/*
+ * ----------------------------------------------------------------------------
+ * LED Pulse Generator
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP_LPG1_BASE 0xfffbd000
+#define OMAP_LPG2_BASE 0xfffbd800
+#define OMAP_LPG1_LCR (OMAP_LPG1_BASE + 0x00)
+#define OMAP_LPG1_PMR (OMAP_LPG1_BASE + 0x04)
+#define OMAP_LPG2_LCR (OMAP_LPG2_BASE + 0x00)
+#define OMAP_LPG2_PMR (OMAP_LPG2_BASE + 0x04)
+
+/*
+ * ---------------------------------------------------------------------------
+ * DSP
+ * ---------------------------------------------------------------------------
+ */
+
+#define OMAP1_DSP_BASE 0xE0000000
+#define OMAP1_DSP_SIZE 0x28000
+#define OMAP1_DSP_START 0xE0000000
+
+#define OMAP1_DSPREG_BASE 0xE1000000
+#define OMAP1_DSPREG_SIZE SZ_128K
+#define OMAP1_DSPREG_START 0xE1000000
+
+#endif /* __ASM_ARCH_OMAP_HARDWARE_H */
diff --git a/arch/arm/mach-omap1/i2c.c b/arch/arm/mach-omap1/i2c.c
new file mode 100644
index 0000000000..94d3e7883e
--- /dev/null
+++ b/arch/arm/mach-omap1/i2c.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Helper module for board specific I2C bus registration
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/platform_data/i2c-omap.h>
+
+#include "mux.h"
+#include "soc.h"
+#include "i2c.h"
+
+#define OMAP_I2C_SIZE 0x3f
+#define OMAP1_I2C_BASE 0xfffb3800
+
+static const char name[] = "omap_i2c";
+
+static struct resource i2c_resources[2] = {
+};
+
+static struct platform_device omap_i2c_devices[1] = {
+};
+
+static void __init omap1_i2c_mux_pins(int bus_id)
+{
+ omap_cfg_reg(I2C_SDA);
+ omap_cfg_reg(I2C_SCL);
+}
+
+int __init omap_i2c_add_bus(struct omap_i2c_bus_platform_data *pdata,
+ int bus_id)
+{
+ struct platform_device *pdev;
+ struct resource *res;
+
+ if (bus_id > 1)
+ return -EINVAL;
+
+ omap1_i2c_mux_pins(bus_id);
+
+ pdev = &omap_i2c_devices[bus_id - 1];
+ pdev->id = bus_id;
+ pdev->name = name;
+ pdev->num_resources = ARRAY_SIZE(i2c_resources);
+ res = i2c_resources;
+ res[0].start = OMAP1_I2C_BASE;
+ res[0].end = res[0].start + OMAP_I2C_SIZE;
+ res[0].flags = IORESOURCE_MEM;
+ res[1].start = INT_I2C;
+ res[1].flags = IORESOURCE_IRQ;
+ pdev->resource = res;
+
+ /* all OMAP1 have IP version 1 register set */
+ pdata->rev = OMAP_I2C_IP_VERSION_1;
+
+ /* all OMAP1 I2C are implemented like this */
+ pdata->flags = OMAP_I2C_FLAG_NO_FIFO |
+ OMAP_I2C_FLAG_SIMPLE_CLOCK |
+ OMAP_I2C_FLAG_16BIT_DATA_REG |
+ OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK;
+
+ /* how the cpu bus is wired up differs for 7xx only */
+
+ pdata->flags |= OMAP_I2C_FLAG_BUS_SHIFT_2;
+
+ pdev->dev.platform_data = pdata;
+
+ return platform_device_register(pdev);
+}
+
+#define OMAP_I2C_MAX_CONTROLLERS 4
+static struct omap_i2c_bus_platform_data i2c_pdata[OMAP_I2C_MAX_CONTROLLERS];
+
+#define OMAP_I2C_CMDLINE_SETUP (BIT(31))
+
+/**
+ * omap_i2c_bus_setup - Process command line options for the I2C bus speed
+ * @str: String of options
+ *
+ * This function allow to override the default I2C bus speed for given I2C
+ * bus with a command line option.
+ *
+ * Format: i2c_bus=bus_id,clkrate (in kHz)
+ *
+ * Returns 1 on success, 0 otherwise.
+ */
+static int __init omap_i2c_bus_setup(char *str)
+{
+ int ints[3];
+
+ get_options(str, 3, ints);
+ if (ints[0] < 2 || ints[1] < 1 ||
+ ints[1] > OMAP_I2C_MAX_CONTROLLERS)
+ return 0;
+ i2c_pdata[ints[1] - 1].clkrate = ints[2];
+ i2c_pdata[ints[1] - 1].clkrate |= OMAP_I2C_CMDLINE_SETUP;
+
+ return 1;
+}
+__setup("i2c_bus=", omap_i2c_bus_setup);
+
+/*
+ * Register busses defined in command line but that are not registered with
+ * omap_register_i2c_bus from board initialization code.
+ */
+int __init omap_register_i2c_bus_cmdline(void)
+{
+ int i, err = 0;
+
+ for (i = 0; i < ARRAY_SIZE(i2c_pdata); i++)
+ if (i2c_pdata[i].clkrate & OMAP_I2C_CMDLINE_SETUP) {
+ i2c_pdata[i].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
+ err = omap_i2c_add_bus(&i2c_pdata[i], i + 1);
+ if (err)
+ goto out;
+ }
+
+out:
+ return err;
+}
+
+/**
+ * omap_register_i2c_bus - register I2C bus with device descriptors
+ * @bus_id: bus id counting from number 1
+ * @clkrate: clock rate of the bus in kHz
+ * @info: pointer into I2C device descriptor table or NULL
+ * @len: number of descriptors in the table
+ *
+ * Returns 0 on success or an error code.
+ */
+int __init omap_register_i2c_bus(int bus_id, u32 clkrate,
+ struct i2c_board_info const *info,
+ unsigned len)
+{
+ int err;
+
+ BUG_ON(bus_id < 1 || bus_id > OMAP_I2C_MAX_CONTROLLERS);
+
+ if (info) {
+ err = i2c_register_board_info(bus_id, info, len);
+ if (err)
+ return err;
+ }
+
+ if (!i2c_pdata[bus_id - 1].clkrate)
+ i2c_pdata[bus_id - 1].clkrate = clkrate;
+
+ i2c_pdata[bus_id - 1].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;
+
+ return omap_i2c_add_bus(&i2c_pdata[bus_id - 1], bus_id);
+}
+
+static int __init omap_i2c_cmdline(void)
+{
+ return omap_register_i2c_bus_cmdline();
+}
+subsys_initcall(omap_i2c_cmdline);
diff --git a/arch/arm/mach-omap1/i2c.h b/arch/arm/mach-omap1/i2c.h
new file mode 100644
index 0000000000..03e2ac2efe
--- /dev/null
+++ b/arch/arm/mach-omap1/i2c.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Helper module for board specific I2C bus registration
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP1_I2C_H
+#define __ARCH_ARM_MACH_OMAP1_I2C_H
+
+struct i2c_board_info;
+struct omap_i2c_bus_platform_data;
+
+int omap_i2c_add_bus(struct omap_i2c_bus_platform_data *i2c_pdata,
+ int bus_id);
+
+#if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
+extern int omap_register_i2c_bus(int bus_id, u32 clkrate,
+ struct i2c_board_info const *info,
+ unsigned len);
+extern int omap_register_i2c_bus_cmdline(void);
+#else
+static inline int omap_register_i2c_bus(int bus_id, u32 clkrate,
+ struct i2c_board_info const *info,
+ unsigned len)
+{
+ return 0;
+}
+
+static inline int omap_register_i2c_bus_cmdline(void)
+{
+ return 0;
+}
+#endif
+
+#endif /* __ARCH_ARM_MACH_OMAP1_I2C_H */
diff --git a/arch/arm/mach-omap1/id.c b/arch/arm/mach-omap1/id.c
new file mode 100644
index 0000000000..c3bb1b71fd
--- /dev/null
+++ b/arch/arm/mach-omap1/id.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * linux/arch/arm/mach-omap1/id.c
+ *
+ * OMAP1 CPU identification code
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Tony Lindgren <tony@atomide.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/soc/ti/omap1-io.h>
+#include <asm/system_info.h>
+
+#include "soc.h"
+#include "hardware.h"
+#include "common.h"
+
+#define OMAP_DIE_ID_0 0xfffe1800
+#define OMAP_DIE_ID_1 0xfffe1804
+#define OMAP_PRODUCTION_ID_0 0xfffe2000
+#define OMAP_PRODUCTION_ID_1 0xfffe2004
+#define OMAP32_ID_0 0xfffed400
+#define OMAP32_ID_1 0xfffed404
+
+struct omap_id {
+ u16 jtag_id; /* Used to determine OMAP type */
+ u8 die_rev; /* Processor revision */
+ u32 omap_id; /* OMAP revision */
+ u32 type; /* Cpu id bits [31:08], cpu class bits [07:00] */
+};
+
+static unsigned int omap_revision;
+
+/* Register values to detect the OMAP version */
+static struct omap_id omap_ids[] __initdata = {
+ { .jtag_id = 0xb574, .die_rev = 0x2, .omap_id = 0x03310315, .type = 0x03100000},
+ { .jtag_id = 0x355f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300100},
+ { .jtag_id = 0xb55f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300300},
+ { .jtag_id = 0xb62c, .die_rev = 0x1, .omap_id = 0x03320500, .type = 0x08500000},
+ { .jtag_id = 0xb470, .die_rev = 0x0, .omap_id = 0x03310100, .type = 0x15100000},
+ { .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x16100000},
+ { .jtag_id = 0xb576, .die_rev = 0x2, .omap_id = 0x03320100, .type = 0x16110000},
+ { .jtag_id = 0xb576, .die_rev = 0x3, .omap_id = 0x03320100, .type = 0x16100c00},
+ { .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320200, .type = 0x16100d00},
+ { .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00},
+ { .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00},
+ { .jtag_id = 0xb576, .die_rev = 0x1, .omap_id = 0x03320100, .type = 0x16110000},
+ { .jtag_id = 0xb58c, .die_rev = 0x2, .omap_id = 0x03320200, .type = 0x16110b00},
+ { .jtag_id = 0xb58c, .die_rev = 0x3, .omap_id = 0x03320200, .type = 0x16110c00},
+ { .jtag_id = 0xb65f, .die_rev = 0x0, .omap_id = 0x03320400, .type = 0x16212300},
+ { .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320400, .type = 0x16212300},
+ { .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320500, .type = 0x16212300},
+ { .jtag_id = 0xb5f7, .die_rev = 0x0, .omap_id = 0x03330000, .type = 0x17100000},
+ { .jtag_id = 0xb5f7, .die_rev = 0x1, .omap_id = 0x03330100, .type = 0x17100000},
+ { .jtag_id = 0xb5f7, .die_rev = 0x2, .omap_id = 0x03330100, .type = 0x17100000},
+};
+
+unsigned int omap_rev(void)
+{
+ return omap_revision;
+}
+EXPORT_SYMBOL(omap_rev);
+
+/*
+ * Get OMAP type from PROD_ID.
+ * 1710 has the PROD_ID in bits 15:00, not in 16:01 as documented in TRM.
+ * 1510 PROD_ID is empty, and 1610 PROD_ID does not make sense.
+ * Undocumented register in TEST BLOCK is used as fallback; This seems to
+ * work on 1510, 1610 & 1710. The official way hopefully will work in future
+ * processors.
+ */
+static u16 __init omap_get_jtag_id(void)
+{
+ u32 prod_id, omap_id;
+
+ prod_id = omap_readl(OMAP_PRODUCTION_ID_1);
+ omap_id = omap_readl(OMAP32_ID_1);
+
+ /* Check for unusable OMAP_PRODUCTION_ID_1 on 1611B/5912 and 730/850 */
+ if (((prod_id >> 20) == 0) || (prod_id == omap_id))
+ prod_id = 0;
+ else
+ prod_id &= 0xffff;
+
+ if (prod_id)
+ return prod_id;
+
+ /* Use OMAP32_ID_1 as fallback */
+ prod_id = ((omap_id >> 12) & 0xffff);
+
+ return prod_id;
+}
+
+/*
+ * Get OMAP revision from DIE_REV.
+ * Early 1710 processors may have broken OMAP_DIE_ID, it contains PROD_ID.
+ * Undocumented register in the TEST BLOCK is used as fallback.
+ * REVISIT: This does not seem to work on 1510
+ */
+static u8 __init omap_get_die_rev(void)
+{
+ u32 die_rev;
+
+ die_rev = omap_readl(OMAP_DIE_ID_1);
+
+ /* Check for broken OMAP_DIE_ID on early 1710 */
+ if (((die_rev >> 12) & 0xffff) == omap_get_jtag_id())
+ die_rev = 0;
+
+ die_rev = (die_rev >> 17) & 0xf;
+ if (die_rev)
+ return die_rev;
+
+ die_rev = (omap_readl(OMAP32_ID_1) >> 28) & 0xf;
+
+ return die_rev;
+}
+
+void __init omap_check_revision(void)
+{
+ int i;
+ u16 jtag_id;
+ u8 die_rev;
+ u32 omap_id;
+ u8 cpu_type;
+
+ jtag_id = omap_get_jtag_id();
+ die_rev = omap_get_die_rev();
+ omap_id = omap_readl(OMAP32_ID_0);
+
+#ifdef DEBUG
+ printk(KERN_DEBUG "OMAP_DIE_ID_0: 0x%08x\n", omap_readl(OMAP_DIE_ID_0));
+ printk(KERN_DEBUG "OMAP_DIE_ID_1: 0x%08x DIE_REV: %i\n",
+ omap_readl(OMAP_DIE_ID_1),
+ (omap_readl(OMAP_DIE_ID_1) >> 17) & 0xf);
+ printk(KERN_DEBUG "OMAP_PRODUCTION_ID_0: 0x%08x\n",
+ omap_readl(OMAP_PRODUCTION_ID_0));
+ printk(KERN_DEBUG "OMAP_PRODUCTION_ID_1: 0x%08x JTAG_ID: 0x%04x\n",
+ omap_readl(OMAP_PRODUCTION_ID_1),
+ omap_readl(OMAP_PRODUCTION_ID_1) & 0xffff);
+ printk(KERN_DEBUG "OMAP32_ID_0: 0x%08x\n", omap_readl(OMAP32_ID_0));
+ printk(KERN_DEBUG "OMAP32_ID_1: 0x%08x\n", omap_readl(OMAP32_ID_1));
+ printk(KERN_DEBUG "JTAG_ID: 0x%04x DIE_REV: %i\n", jtag_id, die_rev);
+#endif
+
+ system_serial_high = omap_readl(OMAP_DIE_ID_0);
+ system_serial_low = omap_readl(OMAP_DIE_ID_1);
+
+ /* First check only the major version in a safe way */
+ for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
+ if (jtag_id == (omap_ids[i].jtag_id)) {
+ omap_revision = omap_ids[i].type;
+ break;
+ }
+ }
+
+ /* Check if we can find the die revision */
+ for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
+ if (jtag_id == omap_ids[i].jtag_id && die_rev == omap_ids[i].die_rev) {
+ omap_revision = omap_ids[i].type;
+ break;
+ }
+ }
+
+ /* Finally check also the omap_id */
+ for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
+ if (jtag_id == omap_ids[i].jtag_id
+ && die_rev == omap_ids[i].die_rev
+ && omap_id == omap_ids[i].omap_id) {
+ omap_revision = omap_ids[i].type;
+ break;
+ }
+ }
+
+ /* Add the cpu class info (7xx, 15xx, 16xx, 24xx) */
+ cpu_type = omap_revision >> 24;
+
+ switch (cpu_type) {
+ case 0x07:
+ case 0x08:
+ omap_revision |= 0x07;
+ break;
+ case 0x03:
+ case 0x15:
+ omap_revision |= 0x15;
+ break;
+ case 0x16:
+ case 0x17:
+ omap_revision |= 0x16;
+ break;
+ default:
+ printk(KERN_INFO "Unknown OMAP cpu type: 0x%02x\n", cpu_type);
+ }
+
+ pr_info("OMAP%04x", omap_revision >> 16);
+ if ((omap_revision >> 8) & 0xff)
+ pr_cont("%x", (omap_revision >> 8) & 0xff);
+ pr_cont(" revision %i handled as %02xxx id: %08x%08x\n",
+ die_rev, omap_revision & 0xff, system_serial_low,
+ system_serial_high);
+}
+
diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c
new file mode 100644
index 0000000000..1f20fe99be
--- /dev/null
+++ b/arch/arm/mach-omap1/io.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * linux/arch/arm/mach-omap1/io.c
+ *
+ * OMAP1 I/O mapping code
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/omap-dma.h>
+
+#include <asm/tlb.h>
+#include <asm/mach/map.h>
+
+#include "tc.h"
+#include "iomap.h"
+#include "common.h"
+
+/*
+ * The machine specific code may provide the extra mapping besides the
+ * default mapping provided here.
+ */
+static struct map_desc omap1_io_desc[] __initdata = {
+ {
+ .virtual = OMAP1_IO_VIRT,
+ .pfn = __phys_to_pfn(OMAP1_IO_PHYS),
+ .length = OMAP1_IO_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = OMAP1_DSP_BASE,
+ .pfn = __phys_to_pfn(OMAP1_DSP_START),
+ .length = OMAP1_DSP_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = OMAP1_DSPREG_BASE,
+ .pfn = __phys_to_pfn(OMAP1_DSPREG_START),
+ .length = OMAP1_DSPREG_SIZE,
+ .type = MT_DEVICE
+ }
+};
+
+/*
+ * Maps common IO regions for omap1
+ */
+void __init omap1_map_io(void)
+{
+ iotable_init(omap1_io_desc, ARRAY_SIZE(omap1_io_desc));
+}
+
+/*
+ * Common low-level hardware init for omap1.
+ */
+void __init omap1_init_early(void)
+{
+ omap_check_revision();
+
+ /* REVISIT: Refer to OMAP5910 Errata, Advisory SYS_1: "Timeout Abort
+ * on a Posted Write in the TIPB Bridge".
+ */
+ omap_writew(0x0, MPU_PUBLIC_TIPB_CNTL);
+ omap_writew(0x0, MPU_PRIVATE_TIPB_CNTL);
+}
+
+void __init omap1_init_late(void)
+{
+ omap_serial_wakeup_init();
+}
+
+/*
+ * NOTE: Please use ioremap + __raw_read/write where possible instead of these
+ */
+
+u8 omap_readb(u32 pa)
+{
+ return __raw_readb(OMAP1_IO_ADDRESS(pa));
+}
+EXPORT_SYMBOL(omap_readb);
+
+u16 omap_readw(u32 pa)
+{
+ return __raw_readw(OMAP1_IO_ADDRESS(pa));
+}
+EXPORT_SYMBOL(omap_readw);
+
+u32 omap_readl(u32 pa)
+{
+ return __raw_readl(OMAP1_IO_ADDRESS(pa));
+}
+EXPORT_SYMBOL(omap_readl);
+
+void omap_writeb(u8 v, u32 pa)
+{
+ __raw_writeb(v, OMAP1_IO_ADDRESS(pa));
+}
+EXPORT_SYMBOL(omap_writeb);
+
+void omap_writew(u16 v, u32 pa)
+{
+ __raw_writew(v, OMAP1_IO_ADDRESS(pa));
+}
+EXPORT_SYMBOL(omap_writew);
+
+void omap_writel(u32 v, u32 pa)
+{
+ __raw_writel(v, OMAP1_IO_ADDRESS(pa));
+}
+EXPORT_SYMBOL(omap_writel);
diff --git a/arch/arm/mach-omap1/iomap.h b/arch/arm/mach-omap1/iomap.h
new file mode 100644
index 0000000000..f4e2d7a213
--- /dev/null
+++ b/arch/arm/mach-omap1/iomap.h
@@ -0,0 +1,33 @@
+/*
+ * IO mappings for OMAP1
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * ----------------------------------------------------------------------------
+ * Omap1 specific IO mapping
+ * ----------------------------------------------------------------------------
+ */
+
+#define OMAP1_IO_PHYS 0xFFFB0000
+#define OMAP1_IO_SIZE 0x40000
+#define OMAP1_IO_VIRT (OMAP1_IO_PHYS - OMAP1_IO_OFFSET)
diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c
new file mode 100644
index 0000000000..9b587ecebb
--- /dev/null
+++ b/arch/arm/mach-omap1/irq.c
@@ -0,0 +1,259 @@
+/*
+ * linux/arch/arm/mach-omap1/irq.c
+ *
+ * Interrupt handler for all OMAP boards
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Tony Lindgren <tony@atomide.com>
+ * Major cleanups by Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * Completely re-written to support various OMAP chips with bank specific
+ * interrupt handlers.
+ *
+ * Some snippets of the code taken from the older OMAP interrupt handler
+ * Copyright (C) 2001 RidgeRun, Inc. Greg Lonnon <glonnon@ridgerun.com>
+ *
+ * GPIO interrupt handler moved to gpio.c by Juha Yrjola
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irqdomain.h>
+
+#include <asm/irq.h>
+#include <asm/exception.h>
+#include <asm/mach/irq.h>
+
+#include "soc.h"
+#include "hardware.h"
+#include "common.h"
+
+#define IRQ_BANK(irq) ((irq) >> 5)
+#define IRQ_BIT(irq) ((irq) & 0x1f)
+
+struct omap_irq_bank {
+ unsigned long base_reg;
+ void __iomem *va;
+ unsigned long trigger_map;
+ unsigned long wake_enable;
+};
+
+static u32 omap_l2_irq;
+static unsigned int irq_bank_count;
+static struct omap_irq_bank *irq_banks;
+static struct irq_domain *domain;
+
+static inline unsigned int irq_bank_readl(int bank, int offset)
+{
+ return readl_relaxed(irq_banks[bank].va + offset);
+}
+static inline void irq_bank_writel(unsigned long value, int bank, int offset)
+{
+ writel_relaxed(value, irq_banks[bank].va + offset);
+}
+
+static void omap_ack_irq(int irq)
+{
+ if (irq > 31)
+ writel_relaxed(0x1, irq_banks[1].va + IRQ_CONTROL_REG_OFFSET);
+
+ writel_relaxed(0x1, irq_banks[0].va + IRQ_CONTROL_REG_OFFSET);
+}
+
+static void omap_mask_ack_irq(struct irq_data *d)
+{
+ struct irq_chip_type *ct = irq_data_get_chip_type(d);
+
+ ct->chip.irq_mask(d);
+ omap_ack_irq(d->irq);
+}
+
+/*
+ * Allows tuning the IRQ type and priority
+ *
+ * NOTE: There is currently no OMAP fiq handler for Linux. Read the
+ * mailing list threads on FIQ handlers if you are planning to
+ * add a FIQ handler for OMAP.
+ */
+static void omap_irq_set_cfg(int irq, int fiq, int priority, int trigger)
+{
+ signed int bank;
+ unsigned long val, offset;
+
+ bank = IRQ_BANK(irq);
+ /* FIQ is only available on bank 0 interrupts */
+ fiq = bank ? 0 : (fiq & 0x1);
+ val = fiq | ((priority & 0x1f) << 2) | ((trigger & 0x1) << 1);
+ offset = IRQ_ILR0_REG_OFFSET + IRQ_BIT(irq) * 0x4;
+ irq_bank_writel(val, bank, offset);
+}
+
+#ifdef CONFIG_ARCH_OMAP15XX
+static struct omap_irq_bank omap1510_irq_banks[] = {
+ { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3febfff },
+ { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xffbfffed },
+};
+static struct omap_irq_bank omap310_irq_banks[] = {
+ { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3faefc3 },
+ { .base_reg = OMAP_IH2_BASE, .trigger_map = 0x65b3c061 },
+};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP16XX)
+
+static struct omap_irq_bank omap1610_irq_banks[] = {
+ { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3fefe8f },
+ { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb7c1fd },
+ { .base_reg = OMAP_IH2_BASE + 0x100, .trigger_map = 0xffffb7ff },
+ { .base_reg = OMAP_IH2_BASE + 0x200, .trigger_map = 0xffffffff },
+};
+#endif
+
+asmlinkage void __exception_irq_entry omap1_handle_irq(struct pt_regs *regs)
+{
+ void __iomem *l1 = irq_banks[0].va;
+ void __iomem *l2 = irq_banks[1].va;
+ u32 irqnr;
+
+ do {
+ irqnr = readl_relaxed(l1 + IRQ_ITR_REG_OFFSET);
+ irqnr &= ~(readl_relaxed(l1 + IRQ_MIR_REG_OFFSET) & 0xffffffff);
+ if (!irqnr)
+ break;
+
+ irqnr = readl_relaxed(l1 + IRQ_SIR_FIQ_REG_OFFSET);
+ if (irqnr)
+ goto irq;
+
+ irqnr = readl_relaxed(l1 + IRQ_SIR_IRQ_REG_OFFSET);
+ if (irqnr == omap_l2_irq) {
+ irqnr = readl_relaxed(l2 + IRQ_SIR_IRQ_REG_OFFSET);
+ if (irqnr)
+ irqnr += 32;
+ }
+irq:
+ if (irqnr)
+ generic_handle_domain_irq(domain, irqnr);
+ else
+ break;
+ } while (irqnr);
+}
+
+static __init void
+omap_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
+{
+ struct irq_chip_generic *gc;
+ struct irq_chip_type *ct;
+
+ gc = irq_alloc_generic_chip("MPU", 1, irq_start, base,
+ handle_level_irq);
+ ct = gc->chip_types;
+ ct->chip.irq_ack = omap_mask_ack_irq;
+ ct->chip.irq_mask = irq_gc_mask_set_bit;
+ ct->chip.irq_unmask = irq_gc_mask_clr_bit;
+ ct->chip.irq_set_wake = irq_gc_set_wake;
+ ct->regs.mask = IRQ_MIR_REG_OFFSET;
+ irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
+ IRQ_NOREQUEST | IRQ_NOPROBE, 0);
+}
+
+void __init omap1_init_irq(void)
+{
+ struct irq_chip_type *ct;
+ struct irq_data *d = NULL;
+ int i, j, irq_base;
+ unsigned long nr_irqs;
+
+#ifdef CONFIG_ARCH_OMAP15XX
+ if (cpu_is_omap1510()) {
+ irq_banks = omap1510_irq_banks;
+ irq_bank_count = ARRAY_SIZE(omap1510_irq_banks);
+ }
+ if (cpu_is_omap310()) {
+ irq_banks = omap310_irq_banks;
+ irq_bank_count = ARRAY_SIZE(omap310_irq_banks);
+ }
+#endif
+#if defined(CONFIG_ARCH_OMAP16XX)
+ if (cpu_is_omap16xx()) {
+ irq_banks = omap1610_irq_banks;
+ irq_bank_count = ARRAY_SIZE(omap1610_irq_banks);
+ }
+#endif
+
+ for (i = 0; i < irq_bank_count; i++) {
+ irq_banks[i].va = ioremap(irq_banks[i].base_reg, 0xff);
+ if (WARN_ON(!irq_banks[i].va))
+ return;
+ }
+
+ nr_irqs = irq_bank_count * 32;
+
+ irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
+ if (irq_base < 0) {
+ pr_warn("Couldn't allocate IRQ numbers\n");
+ irq_base = 0;
+ }
+ omap_l2_irq = irq_base;
+ omap_l2_irq -= NR_IRQS_LEGACY;
+
+ domain = irq_domain_add_legacy(NULL, nr_irqs, irq_base, 0,
+ &irq_domain_simple_ops, NULL);
+
+ pr_info("Total of %lu interrupts in %i interrupt banks\n",
+ nr_irqs, irq_bank_count);
+
+ /* Mask and clear all interrupts */
+ for (i = 0; i < irq_bank_count; i++) {
+ irq_bank_writel(~0x0, i, IRQ_MIR_REG_OFFSET);
+ irq_bank_writel(0x0, i, IRQ_ITR_REG_OFFSET);
+ }
+
+ /* Clear any pending interrupts */
+ irq_bank_writel(0x03, 0, IRQ_CONTROL_REG_OFFSET);
+ irq_bank_writel(0x03, 1, IRQ_CONTROL_REG_OFFSET);
+
+ /* Install the interrupt handlers for each bank */
+ for (i = 0; i < irq_bank_count; i++) {
+ for (j = i * 32; j < (i + 1) * 32; j++) {
+ int irq_trigger;
+
+ irq_trigger = irq_banks[i].trigger_map >> IRQ_BIT(j);
+ omap_irq_set_cfg(j, 0, 0, irq_trigger);
+ irq_clear_status_flags(j, IRQ_NOREQUEST);
+ }
+ omap_alloc_gc(irq_banks[i].va, irq_base + i * 32, 32);
+ }
+
+ /* Unmask level 2 handler */
+ d = irq_get_irq_data(irq_find_mapping(domain, omap_l2_irq));
+ if (d) {
+ ct = irq_data_get_chip_type(d);
+ ct->chip.irq_unmask(d);
+ }
+
+ set_handle_irq(omap1_handle_irq);
+}
diff --git a/arch/arm/mach-omap1/irqs.h b/arch/arm/mach-omap1/irqs.h
new file mode 100644
index 0000000000..3ab7050b1b
--- /dev/null
+++ b/arch/arm/mach-omap1/irqs.h
@@ -0,0 +1,240 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) Greg Lonnon 2001
+ * Updated for OMAP-1610 by Tony Lindgren <tony@atomide.com>
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * NOTE: The interrupt vectors for the OMAP-1509, OMAP-1510, and OMAP-1610
+ * are different.
+ */
+
+#ifndef __ASM_ARCH_OMAP15XX_IRQS_H
+#define __ASM_ARCH_OMAP15XX_IRQS_H
+
+/*
+ * IRQ numbers for interrupt handler 1
+ *
+ * NOTE: See also the OMAP-1510 and 1610 specific IRQ numbers below
+ *
+ */
+#define INT_CAMERA (NR_IRQS_LEGACY + 1)
+#define INT_FIQ (NR_IRQS_LEGACY + 3)
+#define INT_RTDX (NR_IRQS_LEGACY + 6)
+#define INT_DSP_MMU_ABORT (NR_IRQS_LEGACY + 7)
+#define INT_HOST (NR_IRQS_LEGACY + 8)
+#define INT_ABORT (NR_IRQS_LEGACY + 9)
+#define INT_BRIDGE_PRIV (NR_IRQS_LEGACY + 13)
+#define INT_GPIO_BANK1 (NR_IRQS_LEGACY + 14)
+#define INT_UART3 (NR_IRQS_LEGACY + 15)
+#define INT_TIMER3 (NR_IRQS_LEGACY + 16)
+#define INT_DMA_CH0_6 (NR_IRQS_LEGACY + 19)
+#define INT_DMA_CH1_7 (NR_IRQS_LEGACY + 20)
+#define INT_DMA_CH2_8 (NR_IRQS_LEGACY + 21)
+#define INT_DMA_CH3 (NR_IRQS_LEGACY + 22)
+#define INT_DMA_CH4 (NR_IRQS_LEGACY + 23)
+#define INT_DMA_CH5 (NR_IRQS_LEGACY + 24)
+#define INT_TIMER1 (NR_IRQS_LEGACY + 26)
+#define INT_WD_TIMER (NR_IRQS_LEGACY + 27)
+#define INT_BRIDGE_PUB (NR_IRQS_LEGACY + 28)
+#define INT_TIMER2 (NR_IRQS_LEGACY + 30)
+#define INT_LCD_CTRL (NR_IRQS_LEGACY + 31)
+
+/*
+ * OMAP-1510 specific IRQ numbers for interrupt handler 1
+ */
+#define INT_1510_IH2_IRQ (NR_IRQS_LEGACY + 0)
+#define INT_1510_RES2 (NR_IRQS_LEGACY + 2)
+#define INT_1510_SPI_TX (NR_IRQS_LEGACY + 4)
+#define INT_1510_SPI_RX (NR_IRQS_LEGACY + 5)
+#define INT_1510_DSP_MAILBOX1 (NR_IRQS_LEGACY + 10)
+#define INT_1510_DSP_MAILBOX2 (NR_IRQS_LEGACY + 11)
+#define INT_1510_RES12 (NR_IRQS_LEGACY + 12)
+#define INT_1510_LB_MMU (NR_IRQS_LEGACY + 17)
+#define INT_1510_RES18 (NR_IRQS_LEGACY + 18)
+#define INT_1510_LOCAL_BUS (NR_IRQS_LEGACY + 29)
+
+/*
+ * OMAP-1610 specific IRQ numbers for interrupt handler 1
+ */
+#define INT_1610_IH2_IRQ INT_1510_IH2_IRQ
+#define INT_1610_IH2_FIQ (NR_IRQS_LEGACY + 2)
+#define INT_1610_McBSP2_TX (NR_IRQS_LEGACY + 4)
+#define INT_1610_McBSP2_RX (NR_IRQS_LEGACY + 5)
+#define INT_1610_DSP_MAILBOX1 (NR_IRQS_LEGACY + 10)
+#define INT_1610_DSP_MAILBOX2 (NR_IRQS_LEGACY + 11)
+#define INT_1610_LCD_LINE (NR_IRQS_LEGACY + 12)
+#define INT_1610_GPTIMER1 (NR_IRQS_LEGACY + 17)
+#define INT_1610_GPTIMER2 (NR_IRQS_LEGACY + 18)
+#define INT_1610_SSR_FIFO_0 (NR_IRQS_LEGACY + 29)
+
+/*
+ * OMAP-7xx specific IRQ numbers for interrupt handler 1
+ */
+#define INT_7XX_IH2_FIQ (NR_IRQS_LEGACY + 0)
+#define INT_7XX_IH2_IRQ (NR_IRQS_LEGACY + 1)
+#define INT_7XX_USB_NON_ISO (NR_IRQS_LEGACY + 2)
+#define INT_7XX_USB_ISO (NR_IRQS_LEGACY + 3)
+#define INT_7XX_ICR (NR_IRQS_LEGACY + 4)
+#define INT_7XX_EAC (NR_IRQS_LEGACY + 5)
+#define INT_7XX_GPIO_BANK1 (NR_IRQS_LEGACY + 6)
+#define INT_7XX_GPIO_BANK2 (NR_IRQS_LEGACY + 7)
+#define INT_7XX_GPIO_BANK3 (NR_IRQS_LEGACY + 8)
+#define INT_7XX_McBSP2TX (NR_IRQS_LEGACY + 10)
+#define INT_7XX_McBSP2RX (NR_IRQS_LEGACY + 11)
+#define INT_7XX_McBSP2RX_OVF (NR_IRQS_LEGACY + 12)
+#define INT_7XX_LCD_LINE (NR_IRQS_LEGACY + 14)
+#define INT_7XX_GSM_PROTECT (NR_IRQS_LEGACY + 15)
+#define INT_7XX_TIMER3 (NR_IRQS_LEGACY + 16)
+#define INT_7XX_GPIO_BANK5 (NR_IRQS_LEGACY + 17)
+#define INT_7XX_GPIO_BANK6 (NR_IRQS_LEGACY + 18)
+#define INT_7XX_SPGIO_WR (NR_IRQS_LEGACY + 29)
+
+/*
+ * IRQ numbers for interrupt handler 2
+ *
+ * NOTE: See also the OMAP-1510 and 1610 specific IRQ numbers below
+ */
+#define IH2_BASE (NR_IRQS_LEGACY + 32)
+
+#define INT_KEYBOARD (1 + IH2_BASE)
+#define INT_uWireTX (2 + IH2_BASE)
+#define INT_uWireRX (3 + IH2_BASE)
+#define INT_I2C (4 + IH2_BASE)
+#define INT_MPUIO (5 + IH2_BASE)
+#define INT_USB_HHC_1 (6 + IH2_BASE)
+#define INT_McBSP3TX (10 + IH2_BASE)
+#define INT_McBSP3RX (11 + IH2_BASE)
+#define INT_McBSP1TX (12 + IH2_BASE)
+#define INT_McBSP1RX (13 + IH2_BASE)
+#define INT_UART1 (14 + IH2_BASE)
+#define INT_UART2 (15 + IH2_BASE)
+#define INT_BT_MCSI1TX (16 + IH2_BASE)
+#define INT_BT_MCSI1RX (17 + IH2_BASE)
+#define INT_SOSSI_MATCH (19 + IH2_BASE)
+#define INT_USB_W2FC (20 + IH2_BASE)
+#define INT_1WIRE (21 + IH2_BASE)
+#define INT_OS_TIMER (22 + IH2_BASE)
+#define INT_MMC (23 + IH2_BASE)
+#define INT_GAUGE_32K (24 + IH2_BASE)
+#define INT_RTC_TIMER (25 + IH2_BASE)
+#define INT_RTC_ALARM (26 + IH2_BASE)
+#define INT_MEM_STICK (27 + IH2_BASE)
+
+/*
+ * OMAP-1510 specific IRQ numbers for interrupt handler 2
+ */
+#define INT_1510_DSP_MMU (28 + IH2_BASE)
+#define INT_1510_COM_SPI_RO (31 + IH2_BASE)
+
+/*
+ * OMAP-1610 specific IRQ numbers for interrupt handler 2
+ */
+#define INT_1610_FAC (0 + IH2_BASE)
+#define INT_1610_USB_HHC_2 (7 + IH2_BASE)
+#define INT_1610_USB_OTG (8 + IH2_BASE)
+#define INT_1610_SoSSI (9 + IH2_BASE)
+#define INT_1610_SoSSI_MATCH (19 + IH2_BASE)
+#define INT_1610_DSP_MMU (28 + IH2_BASE)
+#define INT_1610_McBSP2RX_OF (31 + IH2_BASE)
+#define INT_1610_STI (32 + IH2_BASE)
+#define INT_1610_STI_WAKEUP (33 + IH2_BASE)
+#define INT_1610_GPTIMER3 (34 + IH2_BASE)
+#define INT_1610_GPTIMER4 (35 + IH2_BASE)
+#define INT_1610_GPTIMER5 (36 + IH2_BASE)
+#define INT_1610_GPTIMER6 (37 + IH2_BASE)
+#define INT_1610_GPTIMER7 (38 + IH2_BASE)
+#define INT_1610_GPTIMER8 (39 + IH2_BASE)
+#define INT_1610_GPIO_BANK2 (40 + IH2_BASE)
+#define INT_1610_GPIO_BANK3 (41 + IH2_BASE)
+#define INT_1610_MMC2 (42 + IH2_BASE)
+#define INT_1610_CF (43 + IH2_BASE)
+#define INT_1610_WAKE_UP_REQ (46 + IH2_BASE)
+#define INT_1610_GPIO_BANK4 (48 + IH2_BASE)
+#define INT_1610_SPI (49 + IH2_BASE)
+#define INT_1610_DMA_CH6 (53 + IH2_BASE)
+#define INT_1610_DMA_CH7 (54 + IH2_BASE)
+#define INT_1610_DMA_CH8 (55 + IH2_BASE)
+#define INT_1610_DMA_CH9 (56 + IH2_BASE)
+#define INT_1610_DMA_CH10 (57 + IH2_BASE)
+#define INT_1610_DMA_CH11 (58 + IH2_BASE)
+#define INT_1610_DMA_CH12 (59 + IH2_BASE)
+#define INT_1610_DMA_CH13 (60 + IH2_BASE)
+#define INT_1610_DMA_CH14 (61 + IH2_BASE)
+#define INT_1610_DMA_CH15 (62 + IH2_BASE)
+#define INT_1610_NAND (63 + IH2_BASE)
+#define INT_1610_SHA1MD5 (91 + IH2_BASE)
+
+/*
+ * OMAP-7xx specific IRQ numbers for interrupt handler 2
+ */
+#define INT_7XX_HW_ERRORS (0 + IH2_BASE)
+#define INT_7XX_NFIQ_PWR_FAIL (1 + IH2_BASE)
+#define INT_7XX_CFCD (2 + IH2_BASE)
+#define INT_7XX_CFIREQ (3 + IH2_BASE)
+#define INT_7XX_I2C (4 + IH2_BASE)
+#define INT_7XX_PCC (5 + IH2_BASE)
+#define INT_7XX_MPU_EXT_NIRQ (6 + IH2_BASE)
+#define INT_7XX_SPI_100K_1 (7 + IH2_BASE)
+#define INT_7XX_SYREN_SPI (8 + IH2_BASE)
+#define INT_7XX_VLYNQ (9 + IH2_BASE)
+#define INT_7XX_GPIO_BANK4 (10 + IH2_BASE)
+#define INT_7XX_McBSP1TX (11 + IH2_BASE)
+#define INT_7XX_McBSP1RX (12 + IH2_BASE)
+#define INT_7XX_McBSP1RX_OF (13 + IH2_BASE)
+#define INT_7XX_UART_MODEM_IRDA_2 (14 + IH2_BASE)
+#define INT_7XX_UART_MODEM_1 (15 + IH2_BASE)
+#define INT_7XX_MCSI (16 + IH2_BASE)
+#define INT_7XX_uWireTX (17 + IH2_BASE)
+#define INT_7XX_uWireRX (18 + IH2_BASE)
+#define INT_7XX_SMC_CD (19 + IH2_BASE)
+#define INT_7XX_SMC_IREQ (20 + IH2_BASE)
+#define INT_7XX_HDQ_1WIRE (21 + IH2_BASE)
+#define INT_7XX_TIMER32K (22 + IH2_BASE)
+#define INT_7XX_MMC_SDIO (23 + IH2_BASE)
+#define INT_7XX_UPLD (24 + IH2_BASE)
+#define INT_7XX_USB_HHC_1 (27 + IH2_BASE)
+#define INT_7XX_USB_HHC_2 (28 + IH2_BASE)
+#define INT_7XX_USB_GENI (29 + IH2_BASE)
+#define INT_7XX_USB_OTG (30 + IH2_BASE)
+#define INT_7XX_CAMERA_IF (31 + IH2_BASE)
+#define INT_7XX_RNG (32 + IH2_BASE)
+#define INT_7XX_DUAL_MODE_TIMER (33 + IH2_BASE)
+#define INT_7XX_DBB_RF_EN (34 + IH2_BASE)
+#define INT_7XX_MPUIO_KEYPAD (35 + IH2_BASE)
+#define INT_7XX_SHA1_MD5 (36 + IH2_BASE)
+#define INT_7XX_SPI_100K_2 (37 + IH2_BASE)
+#define INT_7XX_RNG_IDLE (38 + IH2_BASE)
+#define INT_7XX_MPUIO (39 + IH2_BASE)
+#define INT_7XX_LLPC_LCD_CTRL_CAN_BE_OFF (40 + IH2_BASE)
+#define INT_7XX_LLPC_OE_FALLING (41 + IH2_BASE)
+#define INT_7XX_LLPC_OE_RISING (42 + IH2_BASE)
+#define INT_7XX_LLPC_VSYNC (43 + IH2_BASE)
+#define INT_7XX_WAKE_UP_REQ (46 + IH2_BASE)
+#define INT_7XX_DMA_CH6 (53 + IH2_BASE)
+#define INT_7XX_DMA_CH7 (54 + IH2_BASE)
+#define INT_7XX_DMA_CH8 (55 + IH2_BASE)
+#define INT_7XX_DMA_CH9 (56 + IH2_BASE)
+#define INT_7XX_DMA_CH10 (57 + IH2_BASE)
+#define INT_7XX_DMA_CH11 (58 + IH2_BASE)
+#define INT_7XX_DMA_CH12 (59 + IH2_BASE)
+#define INT_7XX_DMA_CH13 (60 + IH2_BASE)
+#define INT_7XX_DMA_CH14 (61 + IH2_BASE)
+#define INT_7XX_DMA_CH15 (62 + IH2_BASE)
+#define INT_7XX_NAND (63 + IH2_BASE)
+
+/* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730/850) and
+ * 16 MPUIO lines */
+#define OMAP_MAX_GPIO_LINES 192
+#define IH_GPIO_BASE (128 + IH2_BASE)
+#define IH_MPUIO_BASE (OMAP_MAX_GPIO_LINES + IH_GPIO_BASE)
+#define OMAP_IRQ_END (IH_MPUIO_BASE + 16)
+
+#define OMAP_IRQ_BIT(irq) (1 << ((irq - NR_IRQS_LEGACY) % 32))
+
+#ifdef CONFIG_FIQ
+#define FIQ_START 1024
+#endif
+
+#endif
diff --git a/arch/arm/mach-omap1/mcbsp.c b/arch/arm/mach-omap1/mcbsp.c
new file mode 100644
index 0000000000..37863bdce9
--- /dev/null
+++ b/arch/arm/mach-omap1/mcbsp.c
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * linux/arch/arm/mach-omap1/mcbsp.c
+ *
+ * Copyright (C) 2008 Instituto Nokia de Tecnologia
+ * Contact: Eduardo Valentin <eduardo.valentin@indt.org.br>
+ *
+ * Multichannel mode not supported.
+ */
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/omap-dma.h>
+#include <linux/soc/ti/omap1-io.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
+
+#include "mux.h"
+#include "soc.h"
+#include "irqs.h"
+#include "iomap.h"
+
+#define DPS_RSTCT2_PER_EN (1 << 0)
+#define DSP_RSTCT2_WD_PER_EN (1 << 1)
+
+static int dsp_use;
+static struct clk *api_clk;
+static struct clk *dsp_clk;
+static struct platform_device **omap_mcbsp_devices;
+
+static void omap1_mcbsp_request(unsigned int id)
+{
+ /*
+ * On 1510, 1610 and 1710, McBSP1 and McBSP3
+ * are DSP public peripherals.
+ */
+ if (id == 0 || id == 2) {
+ if (dsp_use++ == 0) {
+ api_clk = clk_get(NULL, "api_ck");
+ dsp_clk = clk_get(NULL, "dsp_ck");
+ if (!IS_ERR(api_clk) && !IS_ERR(dsp_clk)) {
+ clk_prepare_enable(api_clk);
+ clk_prepare_enable(dsp_clk);
+
+ /*
+ * DSP external peripheral reset
+ * FIXME: This should be moved to dsp code
+ */
+ __raw_writew(__raw_readw(DSP_RSTCT2) | DPS_RSTCT2_PER_EN |
+ DSP_RSTCT2_WD_PER_EN, DSP_RSTCT2);
+ }
+ }
+ }
+}
+
+static void omap1_mcbsp_free(unsigned int id)
+{
+ if (id == 0 || id == 2) {
+ if (--dsp_use == 0) {
+ if (!IS_ERR(api_clk)) {
+ clk_disable_unprepare(api_clk);
+ clk_put(api_clk);
+ }
+ if (!IS_ERR(dsp_clk)) {
+ clk_disable_unprepare(dsp_clk);
+ clk_put(dsp_clk);
+ }
+ }
+ }
+}
+
+static struct omap_mcbsp_ops omap1_mcbsp_ops = {
+ .request = omap1_mcbsp_request,
+ .free = omap1_mcbsp_free,
+};
+
+#define OMAP7XX_MCBSP1_BASE 0xfffb1000
+#define OMAP7XX_MCBSP2_BASE 0xfffb1800
+
+#define OMAP1510_MCBSP1_BASE 0xe1011800
+#define OMAP1510_MCBSP2_BASE 0xfffb1000
+#define OMAP1510_MCBSP3_BASE 0xe1017000
+
+#define OMAP1610_MCBSP1_BASE 0xe1011800
+#define OMAP1610_MCBSP2_BASE 0xfffb1000
+#define OMAP1610_MCBSP3_BASE 0xe1017000
+
+struct resource omap15xx_mcbsp_res[][6] = {
+ {
+ {
+ .start = OMAP1510_MCBSP1_BASE,
+ .end = OMAP1510_MCBSP1_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "rx",
+ .start = INT_McBSP1RX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "tx",
+ .start = INT_McBSP1TX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rx",
+ .start = 9,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .name = "tx",
+ .start = 8,
+ .flags = IORESOURCE_DMA,
+ },
+ },
+ {
+ {
+ .start = OMAP1510_MCBSP2_BASE,
+ .end = OMAP1510_MCBSP2_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "rx",
+ .start = INT_1510_SPI_RX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "tx",
+ .start = INT_1510_SPI_TX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rx",
+ .start = 17,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .name = "tx",
+ .start = 16,
+ .flags = IORESOURCE_DMA,
+ },
+ },
+ {
+ {
+ .start = OMAP1510_MCBSP3_BASE,
+ .end = OMAP1510_MCBSP3_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "rx",
+ .start = INT_McBSP3RX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "tx",
+ .start = INT_McBSP3TX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rx",
+ .start = 11,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .name = "tx",
+ .start = 10,
+ .flags = IORESOURCE_DMA,
+ },
+ },
+};
+
+#define omap15xx_mcbsp_res_0 omap15xx_mcbsp_res[0]
+
+static struct omap_mcbsp_platform_data omap15xx_mcbsp_pdata[] = {
+ {
+ .ops = &omap1_mcbsp_ops,
+ },
+ {
+ .ops = &omap1_mcbsp_ops,
+ },
+ {
+ .ops = &omap1_mcbsp_ops,
+ },
+};
+#define OMAP15XX_MCBSP_RES_SZ ARRAY_SIZE(omap15xx_mcbsp_res[1])
+#define OMAP15XX_MCBSP_COUNT ARRAY_SIZE(omap15xx_mcbsp_res)
+
+struct resource omap16xx_mcbsp_res[][6] = {
+ {
+ {
+ .start = OMAP1610_MCBSP1_BASE,
+ .end = OMAP1610_MCBSP1_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "rx",
+ .start = INT_McBSP1RX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "tx",
+ .start = INT_McBSP1TX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rx",
+ .start = 9,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .name = "tx",
+ .start = 8,
+ .flags = IORESOURCE_DMA,
+ },
+ },
+ {
+ {
+ .start = OMAP1610_MCBSP2_BASE,
+ .end = OMAP1610_MCBSP2_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "rx",
+ .start = INT_1610_McBSP2_RX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "tx",
+ .start = INT_1610_McBSP2_TX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rx",
+ .start = 17,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .name = "tx",
+ .start = 16,
+ .flags = IORESOURCE_DMA,
+ },
+ },
+ {
+ {
+ .start = OMAP1610_MCBSP3_BASE,
+ .end = OMAP1610_MCBSP3_BASE + SZ_256,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "rx",
+ .start = INT_McBSP3RX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "tx",
+ .start = INT_McBSP3TX,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "rx",
+ .start = 11,
+ .flags = IORESOURCE_DMA,
+ },
+ {
+ .name = "tx",
+ .start = 10,
+ .flags = IORESOURCE_DMA,
+ },
+ },
+};
+
+#define omap16xx_mcbsp_res_0 omap16xx_mcbsp_res[0]
+
+static struct omap_mcbsp_platform_data omap16xx_mcbsp_pdata[] = {
+ {
+ .ops = &omap1_mcbsp_ops,
+ },
+ {
+ .ops = &omap1_mcbsp_ops,
+ },
+ {
+ .ops = &omap1_mcbsp_ops,
+ },
+};
+#define OMAP16XX_MCBSP_RES_SZ ARRAY_SIZE(omap16xx_mcbsp_res[1])
+#define OMAP16XX_MCBSP_COUNT ARRAY_SIZE(omap16xx_mcbsp_res)
+
+static void omap_mcbsp_register_board_cfg(struct resource *res, int res_count,
+ struct omap_mcbsp_platform_data *config, int size)
+{
+ int i;
+
+ omap_mcbsp_devices = kcalloc(size, sizeof(struct platform_device *),
+ GFP_KERNEL);
+ if (!omap_mcbsp_devices) {
+ printk(KERN_ERR "Could not register McBSP devices\n");
+ return;
+ }
+
+ for (i = 0; i < size; i++) {
+ struct platform_device *new_mcbsp;
+ int ret;
+
+ new_mcbsp = platform_device_alloc("omap-mcbsp", i + 1);
+ if (!new_mcbsp)
+ continue;
+ platform_device_add_resources(new_mcbsp, &res[i * res_count],
+ res_count);
+ config[i].reg_size = 2;
+ config[i].reg_step = 2;
+ new_mcbsp->dev.platform_data = &config[i];
+ ret = platform_device_add(new_mcbsp);
+ if (ret) {
+ platform_device_put(new_mcbsp);
+ continue;
+ }
+ omap_mcbsp_devices[i] = new_mcbsp;
+ }
+}
+
+static int __init omap1_mcbsp_init(void)
+{
+ if (!cpu_class_is_omap1())
+ return -ENODEV;
+
+ if (cpu_is_omap15xx())
+ omap_mcbsp_register_board_cfg(omap15xx_mcbsp_res_0,
+ OMAP15XX_MCBSP_RES_SZ,
+ omap15xx_mcbsp_pdata,
+ OMAP15XX_MCBSP_COUNT);
+
+ if (cpu_is_omap16xx())
+ omap_mcbsp_register_board_cfg(omap16xx_mcbsp_res_0,
+ OMAP16XX_MCBSP_RES_SZ,
+ omap16xx_mcbsp_pdata,
+ OMAP16XX_MCBSP_COUNT);
+
+ return 0;
+}
+
+arch_initcall(omap1_mcbsp_init);
diff --git a/arch/arm/mach-omap1/mmc.h b/arch/arm/mach-omap1/mmc.h
new file mode 100644
index 0000000000..043bd02f3f
--- /dev/null
+++ b/arch/arm/mach-omap1/mmc.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/mmc/host.h>
+#include <linux/platform_data/mmc-omap.h>
+
+#define OMAP15XX_NR_MMC 1
+#define OMAP16XX_NR_MMC 2
+#define OMAP1_MMC_SIZE 0x080
+#define OMAP1_MMC1_BASE 0xfffb7800
+#define OMAP1_MMC2_BASE 0xfffb7c00 /* omap16xx only */
+
+#if IS_ENABLED(CONFIG_MMC_OMAP)
+void omap1_init_mmc(struct omap_mmc_platform_data **mmc_data,
+ int nr_controllers);
+#else
+static inline void omap1_init_mmc(struct omap_mmc_platform_data **mmc_data,
+ int nr_controllers)
+{
+}
+#endif
diff --git a/arch/arm/mach-omap1/mtd-xip.h b/arch/arm/mach-omap1/mtd-xip.h
new file mode 100644
index 0000000000..cbeda46dd5
--- /dev/null
+++ b/arch/arm/mach-omap1/mtd-xip.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * MTD primitives for XIP support. Architecture specific functions.
+ *
+ * Do not include this file directly. It's included from linux/mtd/xip.h
+ *
+ * Author: Vladimir Barinov <vbarinov@embeddedalley.com>
+ *
+ * (c) 2005 MontaVista Software, Inc.
+ */
+
+#ifndef __ARCH_OMAP_MTD_XIP_H__
+#define __ARCH_OMAP_MTD_XIP_H__
+
+#include "hardware.h"
+#include <linux/soc/ti/omap1-io.h>
+#define OMAP_MPU_TIMER_BASE (0xfffec500)
+#define OMAP_MPU_TIMER_OFFSET 0x100
+
+typedef struct {
+ u32 cntl; /* CNTL_TIMER, R/W */
+ u32 load_tim; /* LOAD_TIM, W */
+ u32 read_tim; /* READ_TIM, R */
+} xip_omap_mpu_timer_regs_t;
+
+#define xip_omap_mpu_timer_base(n) \
+((volatile xip_omap_mpu_timer_regs_t*)OMAP1_IO_ADDRESS(OMAP_MPU_TIMER_BASE + \
+ (n)*OMAP_MPU_TIMER_OFFSET))
+
+static inline unsigned long xip_omap_mpu_timer_read(int nr)
+{
+ volatile xip_omap_mpu_timer_regs_t* timer = xip_omap_mpu_timer_base(nr);
+ return timer->read_tim;
+}
+
+#define xip_irqpending() \
+ (omap_readl(OMAP_IH1_ITR) & ~omap_readl(OMAP_IH1_MIR))
+#define xip_currtime() (~xip_omap_mpu_timer_read(0))
+
+/*
+ * It's permitted to do approximation for xip_elapsed_since macro
+ * (see linux/mtd/xip.h)
+ */
+
+#define xip_elapsed_since(x) (signed)((~xip_omap_mpu_timer_read(0) - (x)) / 6)
+
+/*
+ * xip_cpu_idle() is used when waiting for a delay equal or larger than
+ * the system timer tick period. This should put the CPU into idle mode
+ * to save power and to be woken up only when some interrupts are pending.
+ * As above, this should not rely upon standard kernel code.
+ */
+
+#define xip_cpu_idle() asm volatile ("mcr p15, 0, %0, c7, c0, 4" :: "r" (1))
+
+#endif /* __ARCH_OMAP_MTD_XIP_H__ */
diff --git a/arch/arm/mach-omap1/mux.c b/arch/arm/mach-omap1/mux.c
new file mode 100644
index 0000000000..4456fbc8aa
--- /dev/null
+++ b/arch/arm/mach-omap1/mux.c
@@ -0,0 +1,459 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * linux/arch/arm/mach-omap1/mux.c
+ *
+ * OMAP1 pin multiplexing configurations
+ *
+ * Copyright (C) 2003 - 2008 Nokia Corporation
+ *
+ * Written by Tony Lindgren
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/soc/ti/omap1-io.h>
+
+#include "hardware.h"
+#include "mux.h"
+
+#ifdef CONFIG_OMAP_MUX
+
+static struct omap_mux_cfg arch_mux_cfg;
+
+#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
+static struct pin_config omap1xxx_pins[] = {
+/*
+ * description mux mode mux pull pull pull pu_pd pu dbg
+ * reg offset mode reg bit ena reg
+ */
+MUX_CFG("UART1_TX", 9, 21, 1, 2, 3, 0, NA, 0, 0)
+MUX_CFG("UART1_RTS", 9, 12, 1, 2, 0, 0, NA, 0, 0)
+
+/* UART2 (COM_UART_GATING), conflicts with USB2 */
+MUX_CFG("UART2_TX", C, 27, 1, 3, 3, 0, NA, 0, 0)
+MUX_CFG("UART2_RX", C, 18, 0, 3, 1, 1, NA, 0, 0)
+MUX_CFG("UART2_CTS", C, 21, 0, 3, 1, 1, NA, 0, 0)
+MUX_CFG("UART2_RTS", C, 24, 1, 3, 2, 0, NA, 0, 0)
+
+/* UART3 (GIGA_UART_GATING) */
+MUX_CFG("UART3_TX", 6, 0, 1, 0, 30, 0, NA, 0, 0)
+MUX_CFG("UART3_RX", 6, 3, 0, 0, 31, 1, NA, 0, 0)
+MUX_CFG("UART3_CTS", 5, 12, 2, 0, 24, 0, NA, 0, 0)
+MUX_CFG("UART3_RTS", 5, 15, 2, 0, 25, 0, NA, 0, 0)
+MUX_CFG("UART3_CLKREQ", 9, 27, 0, 2, 5, 0, NA, 0, 0)
+MUX_CFG("UART3_BCLK", A, 0, 0, 2, 6, 0, NA, 0, 0)
+MUX_CFG("Y15_1610_UART3_RTS", A, 0, 1, 2, 6, 0, NA, 0, 0)
+
+/* PWT & PWL, conflicts with UART3 */
+MUX_CFG("PWT", 6, 0, 2, 0, 30, 0, NA, 0, 0)
+MUX_CFG("PWL", 6, 3, 1, 0, 31, 1, NA, 0, 0)
+
+/* USB internal master generic */
+MUX_CFG("R18_USB_VBUS", 7, 9, 2, 1, 11, 0, NA, 0, 1)
+MUX_CFG("R18_1510_USB_GPIO0", 7, 9, 0, 1, 11, 1, NA, 0, 1)
+/* works around erratum: W4_USB_PUEN and W4_USB_PUDIS are switched! */
+MUX_CFG("W4_USB_PUEN", D, 3, 3, 3, 5, 1, NA, 0, 1)
+MUX_CFG("W4_USB_CLKO", D, 3, 1, 3, 5, 0, NA, 0, 1)
+MUX_CFG("W4_USB_HIGHZ", D, 3, 4, 3, 5, 0, 3, 0, 1)
+MUX_CFG("W4_GPIO58", D, 3, 7, 3, 5, 0, 3, 0, 1)
+
+/* USB1 master */
+MUX_CFG("USB1_SUSP", 8, 27, 2, 1, 27, 0, NA, 0, 1)
+MUX_CFG("USB1_SE0", 9, 0, 2, 1, 28, 0, NA, 0, 1)
+MUX_CFG("W13_1610_USB1_SE0", 9, 0, 4, 1, 28, 0, NA, 0, 1)
+MUX_CFG("USB1_TXEN", 9, 3, 2, 1, 29, 0, NA, 0, 1)
+MUX_CFG("USB1_TXD", 9, 24, 1, 2, 4, 0, NA, 0, 1)
+MUX_CFG("USB1_VP", A, 3, 1, 2, 7, 0, NA, 0, 1)
+MUX_CFG("USB1_VM", A, 6, 1, 2, 8, 0, NA, 0, 1)
+MUX_CFG("USB1_RCV", A, 9, 1, 2, 9, 0, NA, 0, 1)
+MUX_CFG("USB1_SPEED", A, 12, 2, 2, 10, 0, NA, 0, 1)
+MUX_CFG("R13_1610_USB1_SPEED", A, 12, 5, 2, 10, 0, NA, 0, 1)
+MUX_CFG("R13_1710_USB1_SEO", A, 12, 5, 2, 10, 0, NA, 0, 1)
+
+/* USB2 master */
+MUX_CFG("USB2_SUSP", B, 3, 1, 2, 17, 0, NA, 0, 1)
+MUX_CFG("USB2_VP", B, 6, 1, 2, 18, 0, NA, 0, 1)
+MUX_CFG("USB2_TXEN", B, 9, 1, 2, 19, 0, NA, 0, 1)
+MUX_CFG("USB2_VM", C, 18, 1, 3, 0, 0, NA, 0, 1)
+MUX_CFG("USB2_RCV", C, 21, 1, 3, 1, 0, NA, 0, 1)
+MUX_CFG("USB2_SE0", C, 24, 2, 3, 2, 0, NA, 0, 1)
+MUX_CFG("USB2_TXD", C, 27, 2, 3, 3, 0, NA, 0, 1)
+
+/* OMAP-1510 GPIO */
+MUX_CFG("R18_1510_GPIO0", 7, 9, 0, 1, 11, 1, 0, 0, 1)
+MUX_CFG("R19_1510_GPIO1", 7, 6, 0, 1, 10, 1, 0, 0, 1)
+MUX_CFG("M14_1510_GPIO2", 7, 3, 0, 1, 9, 1, 0, 0, 1)
+
+/* OMAP1610 GPIO */
+MUX_CFG("P18_1610_GPIO3", 7, 0, 0, 1, 8, 0, NA, 0, 1)
+MUX_CFG("Y15_1610_GPIO17", A, 0, 7, 2, 6, 0, NA, 0, 1)
+
+/* OMAP-1710 GPIO */
+MUX_CFG("R18_1710_GPIO0", 7, 9, 0, 1, 11, 1, 1, 1, 1)
+MUX_CFG("V2_1710_GPIO10", F, 27, 1, 4, 3, 1, 4, 1, 1)
+MUX_CFG("N21_1710_GPIO14", 6, 9, 0, 1, 1, 1, 1, 1, 1)
+MUX_CFG("W15_1710_GPIO40", 9, 27, 7, 2, 5, 1, 2, 1, 1)
+
+/* MPUIO */
+MUX_CFG("MPUIO2", 7, 18, 0, 1, 14, 1, NA, 0, 1)
+MUX_CFG("N15_1610_MPUIO2", 7, 18, 0, 1, 14, 1, 1, 0, 1)
+MUX_CFG("MPUIO4", 7, 15, 0, 1, 13, 1, NA, 0, 1)
+MUX_CFG("MPUIO5", 7, 12, 0, 1, 12, 1, NA, 0, 1)
+
+MUX_CFG("T20_1610_MPUIO5", 7, 12, 0, 1, 12, 0, 3, 0, 1)
+MUX_CFG("W11_1610_MPUIO6", 10, 15, 2, 3, 8, 0, 3, 0, 1)
+MUX_CFG("V10_1610_MPUIO7", A, 24, 2, 2, 14, 0, 2, 0, 1)
+MUX_CFG("W11_1610_MPUIO9", 10, 15, 1, 3, 8, 0, 3, 0, 1)
+MUX_CFG("V10_1610_MPUIO10", A, 24, 1, 2, 14, 0, 2, 0, 1)
+MUX_CFG("W10_1610_MPUIO11", A, 18, 2, 2, 11, 0, 2, 0, 1)
+MUX_CFG("E20_1610_MPUIO13", 3, 21, 1, 0, 7, 0, 0, 0, 1)
+MUX_CFG("U20_1610_MPUIO14", 9, 6, 6, 0, 30, 0, 0, 0, 1)
+MUX_CFG("E19_1610_MPUIO15", 3, 18, 1, 0, 6, 0, 0, 0, 1)
+
+/* MCBSP2 */
+MUX_CFG("MCBSP2_CLKR", C, 6, 0, 2, 27, 1, NA, 0, 1)
+MUX_CFG("MCBSP2_CLKX", C, 9, 0, 2, 29, 1, NA, 0, 1)
+MUX_CFG("MCBSP2_DR", C, 0, 0, 2, 26, 1, NA, 0, 1)
+MUX_CFG("MCBSP2_DX", C, 15, 0, 2, 31, 1, NA, 0, 1)
+MUX_CFG("MCBSP2_FSR", C, 12, 0, 2, 30, 1, NA, 0, 1)
+MUX_CFG("MCBSP2_FSX", C, 3, 0, 2, 27, 1, NA, 0, 1)
+
+/* MCBSP3 NOTE: Mode must 1 for clock */
+MUX_CFG("MCBSP3_CLKX", 9, 3, 1, 1, 29, 0, NA, 0, 1)
+
+/* Misc ballouts */
+MUX_CFG("BALLOUT_V8_ARMIO3", B, 18, 0, 2, 25, 1, NA, 0, 1)
+MUX_CFG("N20_HDQ", 6, 18, 1, 1, 4, 0, 1, 4, 0)
+
+/* OMAP-1610 MMC2 */
+MUX_CFG("W8_1610_MMC2_DAT0", B, 21, 6, 2, 23, 1, 2, 1, 1)
+MUX_CFG("V8_1610_MMC2_DAT1", B, 27, 6, 2, 25, 1, 2, 1, 1)
+MUX_CFG("W15_1610_MMC2_DAT2", 9, 12, 6, 2, 5, 1, 2, 1, 1)
+MUX_CFG("R10_1610_MMC2_DAT3", B, 18, 6, 2, 22, 1, 2, 1, 1)
+MUX_CFG("Y10_1610_MMC2_CLK", B, 3, 6, 2, 17, 0, 2, 0, 1)
+MUX_CFG("Y8_1610_MMC2_CMD", B, 24, 6, 2, 24, 1, 2, 1, 1)
+MUX_CFG("V9_1610_MMC2_CMDDIR", B, 12, 6, 2, 20, 0, 2, 1, 1)
+MUX_CFG("V5_1610_MMC2_DATDIR0", B, 15, 6, 2, 21, 0, 2, 1, 1)
+MUX_CFG("W19_1610_MMC2_DATDIR1", 8, 15, 6, 1, 23, 0, 1, 1, 1)
+MUX_CFG("R18_1610_MMC2_CLKIN", 7, 9, 6, 1, 11, 0, 1, 11, 1)
+
+/* OMAP-1610 External Trace Interface */
+MUX_CFG("M19_1610_ETM_PSTAT0", 5, 27, 1, 0, 29, 0, 0, 0, 1)
+MUX_CFG("L15_1610_ETM_PSTAT1", 5, 24, 1, 0, 28, 0, 0, 0, 1)
+MUX_CFG("L18_1610_ETM_PSTAT2", 5, 21, 1, 0, 27, 0, 0, 0, 1)
+MUX_CFG("L19_1610_ETM_D0", 5, 18, 1, 0, 26, 0, 0, 0, 1)
+MUX_CFG("J19_1610_ETM_D6", 5, 0, 1, 0, 20, 0, 0, 0, 1)
+MUX_CFG("J18_1610_ETM_D7", 5, 27, 1, 0, 19, 0, 0, 0, 1)
+
+/* OMAP16XX GPIO */
+MUX_CFG("P20_1610_GPIO4", 6, 27, 0, 1, 7, 0, 1, 1, 1)
+MUX_CFG("V9_1610_GPIO7", B, 12, 1, 2, 20, 0, 2, 1, 1)
+MUX_CFG("W8_1610_GPIO9", B, 21, 0, 2, 23, 0, 2, 1, 1)
+MUX_CFG("N20_1610_GPIO11", 6, 18, 0, 1, 4, 0, 1, 1, 1)
+MUX_CFG("N19_1610_GPIO13", 6, 12, 0, 1, 2, 0, 1, 1, 1)
+MUX_CFG("P10_1610_GPIO22", C, 0, 7, 2, 26, 0, 2, 1, 1)
+MUX_CFG("V5_1610_GPIO24", B, 15, 7, 2, 21, 0, 2, 1, 1)
+MUX_CFG("AA20_1610_GPIO_41", 9, 9, 7, 1, 31, 0, 1, 1, 1)
+MUX_CFG("W19_1610_GPIO48", 8, 15, 7, 1, 23, 1, 1, 0, 1)
+MUX_CFG("M7_1610_GPIO62", 10, 0, 0, 4, 24, 0, 4, 0, 1)
+MUX_CFG("V14_16XX_GPIO37", 9, 18, 7, 2, 2, 0, 2, 2, 0)
+MUX_CFG("R9_16XX_GPIO18", C, 18, 7, 3, 0, 0, 3, 0, 0)
+MUX_CFG("L14_16XX_GPIO49", 6, 3, 7, 0, 31, 0, 0, 31, 0)
+
+/* OMAP-1610 uWire */
+MUX_CFG("V19_1610_UWIRE_SCLK", 8, 6, 0, 1, 20, 0, 1, 1, 1)
+MUX_CFG("U18_1610_UWIRE_SDI", 8, 0, 0, 1, 18, 0, 1, 1, 1)
+MUX_CFG("W21_1610_UWIRE_SDO", 8, 3, 0, 1, 19, 0, 1, 1, 1)
+MUX_CFG("N14_1610_UWIRE_CS0", 8, 9, 1, 1, 21, 0, 1, 1, 1)
+MUX_CFG("P15_1610_UWIRE_CS3", 8, 12, 1, 1, 22, 0, 1, 1, 1)
+MUX_CFG("N15_1610_UWIRE_CS1", 7, 18, 2, 1, 14, 0, NA, 0, 1)
+
+/* OMAP-1610 SPI */
+MUX_CFG("U19_1610_SPIF_SCK", 7, 21, 6, 1, 15, 0, 1, 1, 1)
+MUX_CFG("U18_1610_SPIF_DIN", 8, 0, 6, 1, 18, 1, 1, 0, 1)
+MUX_CFG("P20_1610_SPIF_DIN", 6, 27, 4, 1, 7, 1, 1, 0, 1)
+MUX_CFG("W21_1610_SPIF_DOUT", 8, 3, 6, 1, 19, 0, 1, 0, 1)
+MUX_CFG("R18_1610_SPIF_DOUT", 7, 9, 3, 1, 11, 0, 1, 0, 1)
+MUX_CFG("N14_1610_SPIF_CS0", 8, 9, 6, 1, 21, 0, 1, 1, 1)
+MUX_CFG("N15_1610_SPIF_CS1", 7, 18, 6, 1, 14, 0, 1, 1, 1)
+MUX_CFG("T19_1610_SPIF_CS2", 7, 15, 4, 1, 13, 0, 1, 1, 1)
+MUX_CFG("P15_1610_SPIF_CS3", 8, 12, 3, 1, 22, 0, 1, 1, 1)
+
+/* OMAP-1610 Flash */
+MUX_CFG("L3_1610_FLASH_CS2B_OE",10, 6, 1, NA, 0, 0, NA, 0, 1)
+MUX_CFG("M8_1610_FLASH_CS2B_WE",10, 3, 1, NA, 0, 0, NA, 0, 1)
+
+/* First MMC interface, same on 1510, 1610 and 1710 */
+MUX_CFG("MMC_CMD", A, 27, 0, 2, 15, 1, 2, 1, 1)
+MUX_CFG("MMC_DAT1", A, 24, 0, 2, 14, 1, 2, 1, 1)
+MUX_CFG("MMC_DAT2", A, 18, 0, 2, 12, 1, 2, 1, 1)
+MUX_CFG("MMC_DAT0", B, 0, 0, 2, 16, 1, 2, 1, 1)
+MUX_CFG("MMC_CLK", A, 21, 0, NA, 0, 0, NA, 0, 1)
+MUX_CFG("MMC_DAT3", 10, 15, 0, 3, 8, 1, 3, 1, 1)
+MUX_CFG("M15_1710_MMC_CLKI", 6, 21, 2, 0, 0, 0, NA, 0, 1)
+MUX_CFG("P19_1710_MMC_CMDDIR", 6, 24, 6, 0, 0, 0, NA, 0, 1)
+MUX_CFG("P20_1710_MMC_DATDIR0", 6, 27, 5, 0, 0, 0, NA, 0, 1)
+
+/* OMAP-1610 USB0 alternate configuration */
+MUX_CFG("W9_USB0_TXEN", B, 9, 5, 2, 19, 0, 2, 0, 1)
+MUX_CFG("AA9_USB0_VP", B, 6, 5, 2, 18, 0, 2, 0, 1)
+MUX_CFG("Y5_USB0_RCV", C, 21, 5, 3, 1, 0, 1, 0, 1)
+MUX_CFG("R9_USB0_VM", C, 18, 5, 3, 0, 0, 3, 0, 1)
+MUX_CFG("V6_USB0_TXD", C, 27, 5, 3, 3, 0, 3, 0, 1)
+MUX_CFG("W5_USB0_SE0", C, 24, 5, 3, 2, 0, 3, 0, 1)
+MUX_CFG("V9_USB0_SPEED", B, 12, 5, 2, 20, 0, 2, 0, 1)
+MUX_CFG("Y10_USB0_SUSP", B, 3, 5, 2, 17, 0, 2, 0, 1)
+
+/* USB2 interface */
+MUX_CFG("W9_USB2_TXEN", B, 9, 1, NA, 0, 0, NA, 0, 1)
+MUX_CFG("AA9_USB2_VP", B, 6, 1, NA, 0, 0, NA, 0, 1)
+MUX_CFG("Y5_USB2_RCV", C, 21, 1, NA, 0, 0, NA, 0, 1)
+MUX_CFG("R9_USB2_VM", C, 18, 1, NA, 0, 0, NA, 0, 1)
+MUX_CFG("V6_USB2_TXD", C, 27, 2, NA, 0, 0, NA, 0, 1)
+MUX_CFG("W5_USB2_SE0", C, 24, 2, NA, 0, 0, NA, 0, 1)
+
+/* 16XX UART */
+MUX_CFG("R13_1610_UART1_TX", A, 12, 6, 2, 10, 0, 2, 10, 1)
+MUX_CFG("V14_16XX_UART1_RX", 9, 18, 0, 2, 2, 0, 2, 2, 1)
+MUX_CFG("R14_1610_UART1_CTS", 9, 15, 0, 2, 1, 0, 2, 1, 1)
+MUX_CFG("AA15_1610_UART1_RTS", 9, 12, 1, 2, 0, 0, 2, 0, 1)
+MUX_CFG("R9_16XX_UART2_RX", C, 18, 0, 3, 0, 0, 3, 0, 1)
+MUX_CFG("L14_16XX_UART3_RX", 6, 3, 0, 0, 31, 0, 0, 31, 1)
+
+/* I2C interface */
+MUX_CFG("I2C_SCL", 7, 24, 0, NA, 0, 0, NA, 0, 0)
+MUX_CFG("I2C_SDA", 7, 27, 0, NA, 0, 0, NA, 0, 0)
+
+/* Keypad */
+MUX_CFG("F18_1610_KBC0", 3, 15, 0, 0, 5, 1, 0, 0, 0)
+MUX_CFG("D20_1610_KBC1", 3, 12, 0, 0, 4, 1, 0, 0, 0)
+MUX_CFG("D19_1610_KBC2", 3, 9, 0, 0, 3, 1, 0, 0, 0)
+MUX_CFG("E18_1610_KBC3", 3, 6, 0, 0, 2, 1, 0, 0, 0)
+MUX_CFG("C21_1610_KBC4", 3, 3, 0, 0, 1, 1, 0, 0, 0)
+MUX_CFG("G18_1610_KBR0", 4, 0, 0, 0, 10, 1, 0, 1, 0)
+MUX_CFG("F19_1610_KBR1", 3, 27, 0, 0, 9, 1, 0, 1, 0)
+MUX_CFG("H14_1610_KBR2", 3, 24, 0, 0, 8, 1, 0, 1, 0)
+MUX_CFG("E20_1610_KBR3", 3, 21, 0, 0, 7, 1, 0, 1, 0)
+MUX_CFG("E19_1610_KBR4", 3, 18, 0, 0, 6, 1, 0, 1, 0)
+MUX_CFG("N19_1610_KBR5", 6, 12, 1, 1, 2, 1, 1, 1, 0)
+
+/* Power management */
+MUX_CFG("T20_1610_LOW_PWR", 7, 12, 1, NA, 0, 0, NA, 0, 0)
+
+/* MCLK Settings */
+MUX_CFG("V5_1710_MCLK_ON", B, 15, 0, NA, 0, 0, NA, 0, 0)
+MUX_CFG("V5_1710_MCLK_OFF", B, 15, 6, NA, 0, 0, NA, 0, 0)
+MUX_CFG("R10_1610_MCLK_ON", B, 18, 0, NA, 22, 0, NA, 1, 0)
+MUX_CFG("R10_1610_MCLK_OFF", B, 18, 6, 2, 22, 1, 2, 1, 1)
+
+/* CompactFlash controller, conflicts with MMC1 */
+MUX_CFG("P11_1610_CF_CD2", A, 27, 3, 2, 15, 1, 2, 1, 1)
+MUX_CFG("R11_1610_CF_IOIS16", B, 0, 3, 2, 16, 1, 2, 1, 1)
+MUX_CFG("V10_1610_CF_IREQ", A, 24, 3, 2, 14, 0, 2, 0, 1)
+MUX_CFG("W10_1610_CF_RESET", A, 18, 3, 2, 12, 1, 2, 1, 1)
+MUX_CFG("W11_1610_CF_CD1", 10, 15, 3, 3, 8, 1, 3, 1, 1)
+
+/* parallel camera */
+MUX_CFG("J15_1610_CAM_LCLK", 4, 24, 0, 0, 18, 1, 0, 0, 0)
+MUX_CFG("J18_1610_CAM_D7", 4, 27, 0, 0, 19, 1, 0, 0, 0)
+MUX_CFG("J19_1610_CAM_D6", 5, 0, 0, 0, 20, 1, 0, 0, 0)
+MUX_CFG("J14_1610_CAM_D5", 5, 3, 0, 0, 21, 1, 0, 0, 0)
+MUX_CFG("K18_1610_CAM_D4", 5, 6, 0, 0, 22, 1, 0, 0, 0)
+MUX_CFG("K19_1610_CAM_D3", 5, 9, 0, 0, 23, 1, 0, 0, 0)
+MUX_CFG("K15_1610_CAM_D2", 5, 12, 0, 0, 24, 1, 0, 0, 0)
+MUX_CFG("K14_1610_CAM_D1", 5, 15, 0, 0, 25, 1, 0, 0, 0)
+MUX_CFG("L19_1610_CAM_D0", 5, 18, 0, 0, 26, 1, 0, 0, 0)
+MUX_CFG("L18_1610_CAM_VS", 5, 21, 0, 0, 27, 1, 0, 0, 0)
+MUX_CFG("L15_1610_CAM_HS", 5, 24, 0, 0, 28, 1, 0, 0, 0)
+MUX_CFG("M19_1610_CAM_RSTZ", 5, 27, 0, 0, 29, 0, 0, 0, 0)
+MUX_CFG("Y15_1610_CAM_OUTCLK", A, 0, 6, 2, 6, 0, 2, 0, 0)
+
+/* serial camera */
+MUX_CFG("H19_1610_CAM_EXCLK", 4, 21, 0, 0, 17, 0, 0, 0, 0)
+ /* REVISIT 5912 spec sez CCP_* can't pullup or pulldown ... ? */
+MUX_CFG("Y12_1610_CCP_CLKP", 8, 18, 6, 1, 24, 1, 1, 0, 0)
+MUX_CFG("W13_1610_CCP_CLKM", 9, 0, 6, 1, 28, 1, 1, 0, 0)
+MUX_CFG("W14_1610_CCP_DATAP", 9, 24, 6, 2, 4, 1, 2, 0, 0)
+MUX_CFG("Y14_1610_CCP_DATAM", 9, 21, 6, 2, 3, 1, 2, 0, 0)
+};
+#define OMAP1XXX_PINS_SZ ARRAY_SIZE(omap1xxx_pins)
+#else
+#define omap1xxx_pins NULL
+#define OMAP1XXX_PINS_SZ 0
+#endif /* CONFIG_ARCH_OMAP15XX || CONFIG_ARCH_OMAP16XX */
+
+static int omap1_cfg_reg(const struct pin_config *cfg)
+{
+ static DEFINE_SPINLOCK(mux_spin_lock);
+ unsigned long flags;
+ unsigned int reg_orig = 0, reg = 0, pu_pd_orig = 0, pu_pd = 0,
+ pull_orig = 0, pull = 0;
+ unsigned int mask, warn = 0;
+
+ /* Check the mux register in question */
+ if (cfg->mux_reg) {
+ unsigned tmp1, tmp2;
+
+ spin_lock_irqsave(&mux_spin_lock, flags);
+ reg_orig = omap_readl(cfg->mux_reg);
+
+ /* The mux registers always seem to be 3 bits long */
+ mask = (0x7 << cfg->mask_offset);
+ tmp1 = reg_orig & mask;
+ reg = reg_orig & ~mask;
+
+ tmp2 = (cfg->mask << cfg->mask_offset);
+ reg |= tmp2;
+
+ if (tmp1 != tmp2)
+ warn = 1;
+
+ omap_writel(reg, cfg->mux_reg);
+ spin_unlock_irqrestore(&mux_spin_lock, flags);
+ }
+
+ /* Check for pull up or pull down selection on 1610 */
+ if (!cpu_is_omap15xx()) {
+ if (cfg->pu_pd_reg && cfg->pull_val) {
+ spin_lock_irqsave(&mux_spin_lock, flags);
+ pu_pd_orig = omap_readl(cfg->pu_pd_reg);
+ mask = 1 << cfg->pull_bit;
+
+ if (cfg->pu_pd_val) {
+ if (!(pu_pd_orig & mask))
+ warn = 1;
+ /* Use pull up */
+ pu_pd = pu_pd_orig | mask;
+ } else {
+ if (pu_pd_orig & mask)
+ warn = 1;
+ /* Use pull down */
+ pu_pd = pu_pd_orig & ~mask;
+ }
+ omap_writel(pu_pd, cfg->pu_pd_reg);
+ spin_unlock_irqrestore(&mux_spin_lock, flags);
+ }
+ }
+
+ /* Check for an associated pull down register */
+ if (cfg->pull_reg) {
+ spin_lock_irqsave(&mux_spin_lock, flags);
+ pull_orig = omap_readl(cfg->pull_reg);
+ mask = 1 << cfg->pull_bit;
+
+ if (cfg->pull_val) {
+ if (pull_orig & mask)
+ warn = 1;
+ /* Low bit = pull enabled */
+ pull = pull_orig & ~mask;
+ } else {
+ if (!(pull_orig & mask))
+ warn = 1;
+ /* High bit = pull disabled */
+ pull = pull_orig | mask;
+ }
+
+ omap_writel(pull, cfg->pull_reg);
+ spin_unlock_irqrestore(&mux_spin_lock, flags);
+ }
+
+ if (warn) {
+#ifdef CONFIG_OMAP_MUX_WARNINGS
+ printk(KERN_WARNING "MUX: initialized %s\n", cfg->name);
+#endif
+ }
+
+#ifdef CONFIG_OMAP_MUX_DEBUG
+ if (cfg->debug || warn) {
+ printk("MUX: Setting register %s\n", cfg->name);
+ printk(" %s (0x%08x) = 0x%08x -> 0x%08x\n",
+ cfg->mux_reg_name, cfg->mux_reg, reg_orig, reg);
+
+ if (!cpu_is_omap15xx()) {
+ if (cfg->pu_pd_reg && cfg->pull_val) {
+ printk(" %s (0x%08x) = 0x%08x -> 0x%08x\n",
+ cfg->pu_pd_name, cfg->pu_pd_reg,
+ pu_pd_orig, pu_pd);
+ }
+ }
+
+ if (cfg->pull_reg)
+ printk(" %s (0x%08x) = 0x%08x -> 0x%08x\n",
+ cfg->pull_name, cfg->pull_reg, pull_orig, pull);
+ }
+#endif
+
+#ifdef CONFIG_OMAP_MUX_WARNINGS
+ return warn ? -ETXTBSY : 0;
+#else
+ return 0;
+#endif
+}
+
+static struct omap_mux_cfg *mux_cfg;
+
+int __init omap_mux_register(struct omap_mux_cfg *arch_mux_cfg)
+{
+ if (!arch_mux_cfg || !arch_mux_cfg->pins || arch_mux_cfg->size == 0
+ || !arch_mux_cfg->cfg_reg) {
+ printk(KERN_ERR "Invalid pin table\n");
+ return -EINVAL;
+ }
+
+ mux_cfg = arch_mux_cfg;
+
+ return 0;
+}
+
+/*
+ * Sets the Omap MUX and PULL_DWN registers based on the table
+ */
+int omap_cfg_reg(const unsigned long index)
+{
+ struct pin_config *reg;
+
+ if (!cpu_class_is_omap1()) {
+ printk(KERN_ERR "mux: Broken omap_cfg_reg(%lu) entry\n",
+ index);
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ if (mux_cfg == NULL) {
+ printk(KERN_ERR "Pin mux table not initialized\n");
+ return -ENODEV;
+ }
+
+ if (index >= mux_cfg->size) {
+ printk(KERN_ERR "Invalid pin mux index: %lu (%lu)\n",
+ index, mux_cfg->size);
+ dump_stack();
+ return -ENODEV;
+ }
+
+ reg = &mux_cfg->pins[index];
+
+ if (!mux_cfg->cfg_reg)
+ return -ENODEV;
+
+ return mux_cfg->cfg_reg(reg);
+}
+EXPORT_SYMBOL(omap_cfg_reg);
+
+int __init omap1_mux_init(void)
+{
+ if (cpu_is_omap15xx() || cpu_is_omap16xx()) {
+ arch_mux_cfg.pins = omap1xxx_pins;
+ arch_mux_cfg.size = OMAP1XXX_PINS_SZ;
+ arch_mux_cfg.cfg_reg = omap1_cfg_reg;
+ }
+
+ return omap_mux_register(&arch_mux_cfg);
+}
+
+#else
+#define omap_mux_init() do {} while(0)
+#define omap_cfg_reg(x) do {} while(0)
+#endif /* CONFIG_OMAP_MUX */
+
diff --git a/arch/arm/mach-omap1/mux.h b/arch/arm/mach-omap1/mux.h
new file mode 100644
index 0000000000..3e7ed3348a
--- /dev/null
+++ b/arch/arm/mach-omap1/mux.h
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Table of the Omap register configurations for the FUNC_MUX and
+ * PULL_DWN combinations.
+ *
+ * Copyright (C) 2004 - 2008 Texas Instruments Inc.
+ * Copyright (C) 2003 - 2008 Nokia Corporation
+ *
+ * Written by Tony Lindgren
+ *
+ * NOTE: Please use the following naming style for new pin entries.
+ * For example, W8_1610_MMC2_DAT0, where:
+ * - W8 = ball
+ * - 1610 = 1510 or 1610, none if common for both 1510 and 1610
+ * - MMC2_DAT0 = function
+ */
+
+#ifndef __ASM_ARCH_MUX_H
+#define __ASM_ARCH_MUX_H
+
+#include <linux/soc/ti/omap1-mux.h>
+
+#define PU_PD_SEL_NA 0 /* No pu_pd reg available */
+#define PULL_DWN_CTRL_NA 0 /* No pull-down control needed */
+
+#ifdef CONFIG_OMAP_MUX_DEBUG
+#define MUX_REG(reg, mode_offset, mode) .mux_reg_name = "FUNC_MUX_CTRL_"#reg, \
+ .mux_reg = FUNC_MUX_CTRL_##reg, \
+ .mask_offset = mode_offset, \
+ .mask = mode,
+
+#define PULL_REG(reg, bit, status) .pull_name = "PULL_DWN_CTRL_"#reg, \
+ .pull_reg = PULL_DWN_CTRL_##reg, \
+ .pull_bit = bit, \
+ .pull_val = status,
+
+#define PU_PD_REG(reg, status) .pu_pd_name = "PU_PD_SEL_"#reg, \
+ .pu_pd_reg = PU_PD_SEL_##reg, \
+ .pu_pd_val = status,
+
+#define MUX_REG_7XX(reg, mode_offset, mode) .mux_reg_name = "OMAP7XX_IO_CONF_"#reg, \
+ .mux_reg = OMAP7XX_IO_CONF_##reg, \
+ .mask_offset = mode_offset, \
+ .mask = mode,
+
+#define PULL_REG_7XX(reg, bit, status) .pull_name = "OMAP7XX_IO_CONF_"#reg, \
+ .pull_reg = OMAP7XX_IO_CONF_##reg, \
+ .pull_bit = bit, \
+ .pull_val = status,
+
+#else
+
+#define MUX_REG(reg, mode_offset, mode) .mux_reg = FUNC_MUX_CTRL_##reg, \
+ .mask_offset = mode_offset, \
+ .mask = mode,
+
+#define PULL_REG(reg, bit, status) .pull_reg = PULL_DWN_CTRL_##reg, \
+ .pull_bit = bit, \
+ .pull_val = status,
+
+#define PU_PD_REG(reg, status) .pu_pd_reg = PU_PD_SEL_##reg, \
+ .pu_pd_val = status,
+
+#define MUX_REG_7XX(reg, mode_offset, mode) \
+ .mux_reg = OMAP7XX_IO_CONF_##reg, \
+ .mask_offset = mode_offset, \
+ .mask = mode,
+
+#define PULL_REG_7XX(reg, bit, status) .pull_reg = OMAP7XX_IO_CONF_##reg, \
+ .pull_bit = bit, \
+ .pull_val = status,
+
+#endif /* CONFIG_OMAP_MUX_DEBUG */
+
+#define MUX_CFG(desc, mux_reg, mode_offset, mode, \
+ pull_reg, pull_bit, pull_status, \
+ pu_pd_reg, pu_pd_status, debug_status) \
+{ \
+ .name = desc, \
+ .debug = debug_status, \
+ MUX_REG(mux_reg, mode_offset, mode) \
+ PULL_REG(pull_reg, pull_bit, pull_status) \
+ PU_PD_REG(pu_pd_reg, pu_pd_status) \
+},
+
+
+/*
+ * OMAP730/850 has a slightly different config for the pin mux.
+ * - config regs are the OMAP7XX_IO_CONF_x regs (see omap7xx.h) regs and
+ * not the FUNC_MUX_CTRL_x regs from hardware.h
+ * - for pull-up/down, only has one enable bit which is in the same register
+ * as mux config
+ */
+#define MUX_CFG_7XX(desc, mux_reg, mode_offset, mode, \
+ pull_bit, pull_status, debug_status)\
+{ \
+ .name = desc, \
+ .debug = debug_status, \
+ MUX_REG_7XX(mux_reg, mode_offset, mode) \
+ PULL_REG_7XX(mux_reg, pull_bit, pull_status) \
+ PU_PD_REG(NA, 0) \
+},
+
+struct pin_config {
+ char *name;
+ const unsigned int mux_reg;
+ unsigned char debug;
+
+ const unsigned char mask_offset;
+ const unsigned char mask;
+
+ const char *pull_name;
+ const unsigned int pull_reg;
+ const unsigned char pull_val;
+ const unsigned char pull_bit;
+
+ const char *pu_pd_name;
+ const unsigned int pu_pd_reg;
+ const unsigned char pu_pd_val;
+
+#if defined(CONFIG_OMAP_MUX_DEBUG) || defined(CONFIG_OMAP_MUX_WARNINGS)
+ const char *mux_reg_name;
+#endif
+
+};
+
+struct omap_mux_cfg {
+ struct pin_config *pins;
+ unsigned long size;
+ int (*cfg_reg)(const struct pin_config *cfg);
+};
+
+#ifdef CONFIG_OMAP_MUX
+/* setup pin muxing in Linux */
+extern int omap1_mux_init(void);
+extern int omap_mux_register(struct omap_mux_cfg *);
+#else
+/* boot loader does it all (no warnings from CONFIG_OMAP_MUX_WARNINGS) */
+static inline int omap1_mux_init(void) { return 0; }
+#endif
+
+extern int omap2_mux_init(void);
+
+#endif
diff --git a/arch/arm/mach-omap1/ocpi.c b/arch/arm/mach-omap1/ocpi.c
new file mode 100644
index 0000000000..d48f726571
--- /dev/null
+++ b/arch/arm/mach-omap1/ocpi.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * linux/arch/arm/plat-omap/ocpi.c
+ *
+ * Minimal OCP bus support for omap16xx
+ *
+ * Copyright (C) 2003 - 2005 Nokia Corporation
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ * Written by Tony Lindgren <tony@atomide.com>
+ *
+ * Modified for clock framework by Paul Mundt <paul.mundt@nokia.com>.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/soc/ti/omap1-io.h>
+
+#include "hardware.h"
+#include "common.h"
+
+#define OCPI_BASE 0xfffec320
+#define OCPI_FAULT (OCPI_BASE + 0x00)
+#define OCPI_CMD_FAULT (OCPI_BASE + 0x04)
+#define OCPI_SINT0 (OCPI_BASE + 0x08)
+#define OCPI_TABORT (OCPI_BASE + 0x0c)
+#define OCPI_SINT1 (OCPI_BASE + 0x10)
+#define OCPI_PROT (OCPI_BASE + 0x14)
+#define OCPI_SEC (OCPI_BASE + 0x18)
+
+/* USB OHCI OCPI access error registers */
+#define HOSTUEADDR 0xfffba0e0
+#define HOSTUESTATUS 0xfffba0e4
+
+static struct clk *ocpi_ck;
+
+/*
+ * Enables device access to OMAP buses via the OCPI bridge
+ */
+int ocpi_enable(void)
+{
+ unsigned int val;
+
+ if (!cpu_is_omap16xx())
+ return -ENODEV;
+
+ /* Enable access for OHCI in OCPI */
+ val = omap_readl(OCPI_PROT);
+ val &= ~0xff;
+ /* val &= (1 << 0); Allow access only to EMIFS */
+ omap_writel(val, OCPI_PROT);
+
+ val = omap_readl(OCPI_SEC);
+ val &= ~0xff;
+ omap_writel(val, OCPI_SEC);
+
+ return 0;
+}
+EXPORT_SYMBOL(ocpi_enable);
+
+static int __init omap_ocpi_init(void)
+{
+ if (!cpu_is_omap16xx())
+ return -ENODEV;
+
+ ocpi_ck = clk_get(NULL, "l3_ocpi_ck");
+ if (IS_ERR(ocpi_ck))
+ return PTR_ERR(ocpi_ck);
+
+ clk_prepare_enable(ocpi_ck);
+ ocpi_enable();
+ pr_info("OMAP OCPI interconnect driver loaded\n");
+
+ return 0;
+}
+
+static void __exit omap_ocpi_exit(void)
+{
+ /* REVISIT: Disable OCPI */
+
+ if (!cpu_is_omap16xx())
+ return;
+
+ clk_disable_unprepare(ocpi_ck);
+ clk_put(ocpi_ck);
+}
+
+MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
+MODULE_DESCRIPTION("OMAP OCPI bus controller module");
+MODULE_LICENSE("GPL");
+module_init(omap_ocpi_init);
+module_exit(omap_ocpi_exit);
diff --git a/arch/arm/mach-omap1/omap-dma.c b/arch/arm/mach-omap1/omap-dma.c
new file mode 100644
index 0000000000..9ee472f8ea
--- /dev/null
+++ b/arch/arm/mach-omap1/omap-dma.c
@@ -0,0 +1,882 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * linux/arch/arm/plat-omap/dma.c
+ *
+ * Copyright (C) 2003 - 2008 Nokia Corporation
+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ * DMA channel linking for 1610 by Samuel Ortiz <samuel.ortiz@nokia.com>
+ * Graphics DMA and LCD DMA graphics tranformations
+ * by Imre Deak <imre.deak@nokia.com>
+ * OMAP2/3 support Copyright (C) 2004-2007 Texas Instruments, Inc.
+ * Merged to support both OMAP1 and OMAP2 by Tony Lindgren <tony@atomide.com>
+ * Some functions based on earlier dma-omap.c Copyright (C) 2001 RidgeRun, Inc.
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * Support functions for the OMAP internal DMA channels.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com/
+ * Converted DMA library into DMA platform driver.
+ * - G, Manjunath Kondaiah <manjugk@ti.com>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <linux/omap-dma.h>
+
+#include <linux/soc/ti/omap1-io.h>
+#include <linux/soc/ti/omap1-soc.h>
+
+#include "tc.h"
+
+/*
+ * MAX_LOGICAL_DMA_CH_COUNT: the maximum number of logical DMA
+ * channels that an instance of the SDMA IP block can support. Used
+ * to size arrays. (The actual maximum on a particular SoC may be less
+ * than this -- for example, OMAP1 SDMA instances only support 17 logical
+ * DMA channels.)
+ */
+#define MAX_LOGICAL_DMA_CH_COUNT 32
+
+#undef DEBUG
+
+#define OMAP_DMA_ACTIVE 0x01
+
+#define OMAP_FUNC_MUX_ARM_BASE (0xfffe1000 + 0xec)
+
+static struct omap_system_dma_plat_info *p;
+static struct omap_dma_dev_attr *d;
+static int enable_1510_mode;
+static u32 errata;
+
+struct dma_link_info {
+ int *linked_dmach_q;
+ int no_of_lchs_linked;
+
+ int q_count;
+ int q_tail;
+ int q_head;
+
+ int chain_state;
+ int chain_mode;
+
+};
+
+static int dma_lch_count;
+static int dma_chan_count;
+static int omap_dma_reserve_channels;
+
+static DEFINE_SPINLOCK(dma_chan_lock);
+static struct omap_dma_lch *dma_chan;
+
+static inline void omap_disable_channel_irq(int lch)
+{
+ /* disable channel interrupts */
+ p->dma_write(0, CICR, lch);
+ /* Clear CSR */
+ p->dma_read(CSR, lch);
+}
+
+static inline void set_gdma_dev(int req, int dev)
+{
+ u32 reg = OMAP_FUNC_MUX_ARM_BASE + ((req - 1) / 5) * 4;
+ int shift = ((req - 1) % 5) * 6;
+ u32 l;
+
+ l = omap_readl(reg);
+ l &= ~(0x3f << shift);
+ l |= (dev - 1) << shift;
+ omap_writel(l, reg);
+}
+
+#if IS_ENABLED(CONFIG_FB_OMAP)
+void omap_set_dma_priority(int lch, int dst_port, int priority)
+{
+ unsigned long reg;
+ u32 l;
+
+ if (dma_omap1()) {
+ switch (dst_port) {
+ case OMAP_DMA_PORT_OCP_T1: /* FFFECC00 */
+ reg = OMAP_TC_OCPT1_PRIOR;
+ break;
+ case OMAP_DMA_PORT_OCP_T2: /* FFFECCD0 */
+ reg = OMAP_TC_OCPT2_PRIOR;
+ break;
+ case OMAP_DMA_PORT_EMIFF: /* FFFECC08 */
+ reg = OMAP_TC_EMIFF_PRIOR;
+ break;
+ case OMAP_DMA_PORT_EMIFS: /* FFFECC04 */
+ reg = OMAP_TC_EMIFS_PRIOR;
+ break;
+ default:
+ BUG();
+ return;
+ }
+ l = omap_readl(reg);
+ l &= ~(0xf << 8);
+ l |= (priority & 0xf) << 8;
+ omap_writel(l, reg);
+ }
+}
+EXPORT_SYMBOL(omap_set_dma_priority);
+#endif
+
+#if IS_ENABLED(CONFIG_USB_OMAP)
+#ifdef CONFIG_ARCH_OMAP15XX
+/* Returns 1 if the DMA module is in OMAP1510-compatible mode, 0 otherwise */
+static int omap_dma_in_1510_mode(void)
+{
+ return enable_1510_mode;
+}
+#else
+#define omap_dma_in_1510_mode() 0
+#endif
+
+void omap_set_dma_transfer_params(int lch, int data_type, int elem_count,
+ int frame_count, int sync_mode,
+ int dma_trigger, int src_or_dst_synch)
+{
+ u32 l;
+ u16 ccr;
+
+ l = p->dma_read(CSDP, lch);
+ l &= ~0x03;
+ l |= data_type;
+ p->dma_write(l, CSDP, lch);
+
+ ccr = p->dma_read(CCR, lch);
+ ccr &= ~(1 << 5);
+ if (sync_mode == OMAP_DMA_SYNC_FRAME)
+ ccr |= 1 << 5;
+ p->dma_write(ccr, CCR, lch);
+
+ ccr = p->dma_read(CCR2, lch);
+ ccr &= ~(1 << 2);
+ if (sync_mode == OMAP_DMA_SYNC_BLOCK)
+ ccr |= 1 << 2;
+ p->dma_write(ccr, CCR2, lch);
+ p->dma_write(elem_count, CEN, lch);
+ p->dma_write(frame_count, CFN, lch);
+}
+EXPORT_SYMBOL(omap_set_dma_transfer_params);
+
+void omap_set_dma_channel_mode(int lch, enum omap_dma_channel_mode mode)
+{
+ if (!dma_omap15xx()) {
+ u32 l;
+
+ l = p->dma_read(LCH_CTRL, lch);
+ l &= ~0x7;
+ l |= mode;
+ p->dma_write(l, LCH_CTRL, lch);
+ }
+}
+EXPORT_SYMBOL(omap_set_dma_channel_mode);
+
+/* Note that src_port is only for omap1 */
+void omap_set_dma_src_params(int lch, int src_port, int src_amode,
+ unsigned long src_start,
+ int src_ei, int src_fi)
+{
+ u32 l;
+ u16 w;
+
+ w = p->dma_read(CSDP, lch);
+ w &= ~(0x1f << 2);
+ w |= src_port << 2;
+ p->dma_write(w, CSDP, lch);
+
+ l = p->dma_read(CCR, lch);
+ l &= ~(0x03 << 12);
+ l |= src_amode << 12;
+ p->dma_write(l, CCR, lch);
+
+ p->dma_write(src_start, CSSA, lch);
+
+ p->dma_write(src_ei, CSEI, lch);
+ p->dma_write(src_fi, CSFI, lch);
+}
+EXPORT_SYMBOL(omap_set_dma_src_params);
+
+void omap_set_dma_src_data_pack(int lch, int enable)
+{
+ u32 l;
+
+ l = p->dma_read(CSDP, lch);
+ l &= ~(1 << 6);
+ if (enable)
+ l |= (1 << 6);
+ p->dma_write(l, CSDP, lch);
+}
+EXPORT_SYMBOL(omap_set_dma_src_data_pack);
+
+void omap_set_dma_src_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
+{
+ unsigned int burst = 0;
+ u32 l;
+
+ l = p->dma_read(CSDP, lch);
+ l &= ~(0x03 << 7);
+
+ switch (burst_mode) {
+ case OMAP_DMA_DATA_BURST_DIS:
+ break;
+ case OMAP_DMA_DATA_BURST_4:
+ burst = 0x2;
+ break;
+ case OMAP_DMA_DATA_BURST_8:
+ /*
+ * not supported by current hardware on OMAP1
+ * w |= (0x03 << 7);
+ */
+ fallthrough;
+ case OMAP_DMA_DATA_BURST_16:
+ /* OMAP1 don't support burst 16 */
+ fallthrough;
+ default:
+ BUG();
+ }
+
+ l |= (burst << 7);
+ p->dma_write(l, CSDP, lch);
+}
+EXPORT_SYMBOL(omap_set_dma_src_burst_mode);
+
+/* Note that dest_port is only for OMAP1 */
+void omap_set_dma_dest_params(int lch, int dest_port, int dest_amode,
+ unsigned long dest_start,
+ int dst_ei, int dst_fi)
+{
+ u32 l;
+
+ l = p->dma_read(CSDP, lch);
+ l &= ~(0x1f << 9);
+ l |= dest_port << 9;
+ p->dma_write(l, CSDP, lch);
+
+ l = p->dma_read(CCR, lch);
+ l &= ~(0x03 << 14);
+ l |= dest_amode << 14;
+ p->dma_write(l, CCR, lch);
+
+ p->dma_write(dest_start, CDSA, lch);
+
+ p->dma_write(dst_ei, CDEI, lch);
+ p->dma_write(dst_fi, CDFI, lch);
+}
+EXPORT_SYMBOL(omap_set_dma_dest_params);
+
+void omap_set_dma_dest_data_pack(int lch, int enable)
+{
+ u32 l;
+
+ l = p->dma_read(CSDP, lch);
+ l &= ~(1 << 13);
+ if (enable)
+ l |= 1 << 13;
+ p->dma_write(l, CSDP, lch);
+}
+EXPORT_SYMBOL(omap_set_dma_dest_data_pack);
+
+void omap_set_dma_dest_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
+{
+ unsigned int burst = 0;
+ u32 l;
+
+ l = p->dma_read(CSDP, lch);
+ l &= ~(0x03 << 14);
+
+ switch (burst_mode) {
+ case OMAP_DMA_DATA_BURST_DIS:
+ break;
+ case OMAP_DMA_DATA_BURST_4:
+ burst = 0x2;
+ break;
+ case OMAP_DMA_DATA_BURST_8:
+ burst = 0x3;
+ break;
+ case OMAP_DMA_DATA_BURST_16:
+ /* OMAP1 don't support burst 16 */
+ fallthrough;
+ default:
+ printk(KERN_ERR "Invalid DMA burst mode\n");
+ BUG();
+ return;
+ }
+ l |= (burst << 14);
+ p->dma_write(l, CSDP, lch);
+}
+EXPORT_SYMBOL(omap_set_dma_dest_burst_mode);
+
+static inline void omap_enable_channel_irq(int lch)
+{
+ /* Clear CSR */
+ p->dma_read(CSR, lch);
+
+ /* Enable some nice interrupts. */
+ p->dma_write(dma_chan[lch].enabled_irqs, CICR, lch);
+}
+
+void omap_disable_dma_irq(int lch, u16 bits)
+{
+ dma_chan[lch].enabled_irqs &= ~bits;
+}
+EXPORT_SYMBOL(omap_disable_dma_irq);
+
+static inline void enable_lnk(int lch)
+{
+ u32 l;
+
+ l = p->dma_read(CLNK_CTRL, lch);
+
+ l &= ~(1 << 14);
+
+ /* Set the ENABLE_LNK bits */
+ if (dma_chan[lch].next_lch != -1)
+ l = dma_chan[lch].next_lch | (1 << 15);
+
+ p->dma_write(l, CLNK_CTRL, lch);
+}
+
+static inline void disable_lnk(int lch)
+{
+ u32 l;
+
+ l = p->dma_read(CLNK_CTRL, lch);
+
+ /* Disable interrupts */
+ omap_disable_channel_irq(lch);
+
+ /* Set the STOP_LNK bit */
+ l |= 1 << 14;
+
+ p->dma_write(l, CLNK_CTRL, lch);
+ dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
+}
+#endif
+
+int omap_request_dma(int dev_id, const char *dev_name,
+ void (*callback)(int lch, u16 ch_status, void *data),
+ void *data, int *dma_ch_out)
+{
+ int ch, free_ch = -1;
+ unsigned long flags;
+ struct omap_dma_lch *chan;
+
+ WARN(strcmp(dev_name, "DMA engine"), "Using deprecated platform DMA API - please update to DMA engine");
+
+ spin_lock_irqsave(&dma_chan_lock, flags);
+ for (ch = 0; ch < dma_chan_count; ch++) {
+ if (free_ch == -1 && dma_chan[ch].dev_id == -1) {
+ free_ch = ch;
+ /* Exit after first free channel found */
+ break;
+ }
+ }
+ if (free_ch == -1) {
+ spin_unlock_irqrestore(&dma_chan_lock, flags);
+ return -EBUSY;
+ }
+ chan = dma_chan + free_ch;
+ chan->dev_id = dev_id;
+
+ if (p->clear_lch_regs)
+ p->clear_lch_regs(free_ch);
+
+ spin_unlock_irqrestore(&dma_chan_lock, flags);
+
+ chan->dev_name = dev_name;
+ chan->callback = callback;
+ chan->data = data;
+ chan->flags = 0;
+
+ chan->enabled_irqs = OMAP_DMA_DROP_IRQ | OMAP_DMA_BLOCK_IRQ;
+
+ chan->enabled_irqs |= OMAP1_DMA_TOUT_IRQ;
+
+ if (dma_omap16xx()) {
+ /* If the sync device is set, configure it dynamically. */
+ if (dev_id != 0) {
+ set_gdma_dev(free_ch + 1, dev_id);
+ dev_id = free_ch + 1;
+ }
+ /*
+ * Disable the 1510 compatibility mode and set the sync device
+ * id.
+ */
+ p->dma_write(dev_id | (1 << 10), CCR, free_ch);
+ } else {
+ p->dma_write(dev_id, CCR, free_ch);
+ }
+
+ *dma_ch_out = free_ch;
+
+ return 0;
+}
+EXPORT_SYMBOL(omap_request_dma);
+
+void omap_free_dma(int lch)
+{
+ unsigned long flags;
+
+ if (dma_chan[lch].dev_id == -1) {
+ pr_err("omap_dma: trying to free unallocated DMA channel %d\n",
+ lch);
+ return;
+ }
+
+ /* Disable all DMA interrupts for the channel. */
+ omap_disable_channel_irq(lch);
+
+ /* Make sure the DMA transfer is stopped. */
+ p->dma_write(0, CCR, lch);
+
+ spin_lock_irqsave(&dma_chan_lock, flags);
+ dma_chan[lch].dev_id = -1;
+ dma_chan[lch].next_lch = -1;
+ dma_chan[lch].callback = NULL;
+ spin_unlock_irqrestore(&dma_chan_lock, flags);
+}
+EXPORT_SYMBOL(omap_free_dma);
+
+/*
+ * Clears any DMA state so the DMA engine is ready to restart with new buffers
+ * through omap_start_dma(). Any buffers in flight are discarded.
+ */
+static void omap_clear_dma(int lch)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ p->clear_dma(lch);
+ local_irq_restore(flags);
+}
+
+#if IS_ENABLED(CONFIG_USB_OMAP)
+void omap_start_dma(int lch)
+{
+ u32 l;
+
+ /*
+ * The CPC/CDAC register needs to be initialized to zero
+ * before starting dma transfer.
+ */
+ if (dma_omap15xx())
+ p->dma_write(0, CPC, lch);
+ else
+ p->dma_write(0, CDAC, lch);
+
+ if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
+ int next_lch, cur_lch;
+ char dma_chan_link_map[MAX_LOGICAL_DMA_CH_COUNT];
+
+ /* Set the link register of the first channel */
+ enable_lnk(lch);
+
+ memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map));
+ dma_chan_link_map[lch] = 1;
+
+ cur_lch = dma_chan[lch].next_lch;
+ do {
+ next_lch = dma_chan[cur_lch].next_lch;
+
+ /* The loop case: we've been here already */
+ if (dma_chan_link_map[cur_lch])
+ break;
+ /* Mark the current channel */
+ dma_chan_link_map[cur_lch] = 1;
+
+ enable_lnk(cur_lch);
+ omap_enable_channel_irq(cur_lch);
+
+ cur_lch = next_lch;
+ } while (next_lch != -1);
+ } else if (IS_DMA_ERRATA(DMA_ERRATA_PARALLEL_CHANNELS))
+ p->dma_write(lch, CLNK_CTRL, lch);
+
+ omap_enable_channel_irq(lch);
+
+ l = p->dma_read(CCR, lch);
+
+ if (IS_DMA_ERRATA(DMA_ERRATA_IFRAME_BUFFERING))
+ l |= OMAP_DMA_CCR_BUFFERING_DISABLE;
+ l |= OMAP_DMA_CCR_EN;
+
+ /*
+ * As dma_write() uses IO accessors which are weakly ordered, there
+ * is no guarantee that data in coherent DMA memory will be visible
+ * to the DMA device. Add a memory barrier here to ensure that any
+ * such data is visible prior to enabling DMA.
+ */
+ mb();
+ p->dma_write(l, CCR, lch);
+
+ dma_chan[lch].flags |= OMAP_DMA_ACTIVE;
+}
+EXPORT_SYMBOL(omap_start_dma);
+
+void omap_stop_dma(int lch)
+{
+ u32 l;
+
+ /* Disable all interrupts on the channel */
+ omap_disable_channel_irq(lch);
+
+ l = p->dma_read(CCR, lch);
+ if (IS_DMA_ERRATA(DMA_ERRATA_i541) &&
+ (l & OMAP_DMA_CCR_SEL_SRC_DST_SYNC)) {
+ int i = 0;
+ u32 sys_cf;
+
+ /* Configure No-Standby */
+ l = p->dma_read(OCP_SYSCONFIG, lch);
+ sys_cf = l;
+ l &= ~DMA_SYSCONFIG_MIDLEMODE_MASK;
+ l |= DMA_SYSCONFIG_MIDLEMODE(DMA_IDLEMODE_NO_IDLE);
+ p->dma_write(l , OCP_SYSCONFIG, 0);
+
+ l = p->dma_read(CCR, lch);
+ l &= ~OMAP_DMA_CCR_EN;
+ p->dma_write(l, CCR, lch);
+
+ /* Wait for sDMA FIFO drain */
+ l = p->dma_read(CCR, lch);
+ while (i < 100 && (l & (OMAP_DMA_CCR_RD_ACTIVE |
+ OMAP_DMA_CCR_WR_ACTIVE))) {
+ udelay(5);
+ i++;
+ l = p->dma_read(CCR, lch);
+ }
+ if (i >= 100)
+ pr_err("DMA drain did not complete on lch %d\n", lch);
+ /* Restore OCP_SYSCONFIG */
+ p->dma_write(sys_cf, OCP_SYSCONFIG, lch);
+ } else {
+ l &= ~OMAP_DMA_CCR_EN;
+ p->dma_write(l, CCR, lch);
+ }
+
+ /*
+ * Ensure that data transferred by DMA is visible to any access
+ * after DMA has been disabled. This is important for coherent
+ * DMA regions.
+ */
+ mb();
+
+ if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
+ int next_lch, cur_lch = lch;
+ char dma_chan_link_map[MAX_LOGICAL_DMA_CH_COUNT];
+
+ memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map));
+ do {
+ /* The loop case: we've been here already */
+ if (dma_chan_link_map[cur_lch])
+ break;
+ /* Mark the current channel */
+ dma_chan_link_map[cur_lch] = 1;
+
+ disable_lnk(cur_lch);
+
+ next_lch = dma_chan[cur_lch].next_lch;
+ cur_lch = next_lch;
+ } while (next_lch != -1);
+ }
+
+ dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
+}
+EXPORT_SYMBOL(omap_stop_dma);
+
+/*
+ * Allows changing the DMA callback function or data. This may be needed if
+ * the driver shares a single DMA channel for multiple dma triggers.
+ */
+/*
+ * Returns current physical source address for the given DMA channel.
+ * If the channel is running the caller must disable interrupts prior calling
+ * this function and process the returned value before re-enabling interrupt to
+ * prevent races with the interrupt handler. Note that in continuous mode there
+ * is a chance for CSSA_L register overflow between the two reads resulting
+ * in incorrect return value.
+ */
+dma_addr_t omap_get_dma_src_pos(int lch)
+{
+ dma_addr_t offset = 0;
+
+ if (dma_omap15xx())
+ offset = p->dma_read(CPC, lch);
+ else
+ offset = p->dma_read(CSAC, lch);
+
+ if (IS_DMA_ERRATA(DMA_ERRATA_3_3) && offset == 0)
+ offset = p->dma_read(CSAC, lch);
+
+ if (!dma_omap15xx()) {
+ /*
+ * CDAC == 0 indicates that the DMA transfer on the channel has
+ * not been started (no data has been transferred so far).
+ * Return the programmed source start address in this case.
+ */
+ if (likely(p->dma_read(CDAC, lch)))
+ offset = p->dma_read(CSAC, lch);
+ else
+ offset = p->dma_read(CSSA, lch);
+ }
+
+ offset |= (p->dma_read(CSSA, lch) & 0xFFFF0000);
+
+ return offset;
+}
+EXPORT_SYMBOL(omap_get_dma_src_pos);
+
+/*
+ * Returns current physical destination address for the given DMA channel.
+ * If the channel is running the caller must disable interrupts prior calling
+ * this function and process the returned value before re-enabling interrupt to
+ * prevent races with the interrupt handler. Note that in continuous mode there
+ * is a chance for CDSA_L register overflow between the two reads resulting
+ * in incorrect return value.
+ */
+dma_addr_t omap_get_dma_dst_pos(int lch)
+{
+ dma_addr_t offset = 0;
+
+ if (dma_omap15xx())
+ offset = p->dma_read(CPC, lch);
+ else
+ offset = p->dma_read(CDAC, lch);
+
+ /*
+ * omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is
+ * read before the DMA controller finished disabling the channel.
+ */
+ if (!dma_omap15xx() && offset == 0) {
+ offset = p->dma_read(CDAC, lch);
+ /*
+ * CDAC == 0 indicates that the DMA transfer on the channel has
+ * not been started (no data has been transferred so far).
+ * Return the programmed destination start address in this case.
+ */
+ if (unlikely(!offset))
+ offset = p->dma_read(CDSA, lch);
+ }
+
+ offset |= (p->dma_read(CDSA, lch) & 0xFFFF0000);
+
+ return offset;
+}
+EXPORT_SYMBOL(omap_get_dma_dst_pos);
+
+int omap_get_dma_active_status(int lch)
+{
+ return (p->dma_read(CCR, lch) & OMAP_DMA_CCR_EN) != 0;
+}
+EXPORT_SYMBOL(omap_get_dma_active_status);
+#endif
+
+int omap_dma_running(void)
+{
+ int lch;
+
+ if (omap_lcd_dma_running())
+ return 1;
+
+ for (lch = 0; lch < dma_chan_count; lch++)
+ if (p->dma_read(CCR, lch) & OMAP_DMA_CCR_EN)
+ return 1;
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int omap1_dma_handle_ch(int ch)
+{
+ u32 csr;
+
+ if (enable_1510_mode && ch >= 6) {
+ csr = dma_chan[ch].saved_csr;
+ dma_chan[ch].saved_csr = 0;
+ } else
+ csr = p->dma_read(CSR, ch);
+ if (enable_1510_mode && ch <= 2 && (csr >> 7) != 0) {
+ dma_chan[ch + 6].saved_csr = csr >> 7;
+ csr &= 0x7f;
+ }
+ if ((csr & 0x3f) == 0)
+ return 0;
+ if (unlikely(dma_chan[ch].dev_id == -1)) {
+ pr_warn("Spurious interrupt from DMA channel %d (CSR %04x)\n",
+ ch, csr);
+ return 0;
+ }
+ if (unlikely(csr & OMAP1_DMA_TOUT_IRQ))
+ pr_warn("DMA timeout with device %d\n", dma_chan[ch].dev_id);
+ if (unlikely(csr & OMAP_DMA_DROP_IRQ))
+ pr_warn("DMA synchronization event drop occurred with device %d\n",
+ dma_chan[ch].dev_id);
+ if (likely(csr & OMAP_DMA_BLOCK_IRQ))
+ dma_chan[ch].flags &= ~OMAP_DMA_ACTIVE;
+ if (likely(dma_chan[ch].callback != NULL))
+ dma_chan[ch].callback(ch, csr, dma_chan[ch].data);
+
+ return 1;
+}
+
+static irqreturn_t omap1_dma_irq_handler(int irq, void *dev_id)
+{
+ int ch = ((int) dev_id) - 1;
+ int handled = 0;
+
+ for (;;) {
+ int handled_now = 0;
+
+ handled_now += omap1_dma_handle_ch(ch);
+ if (enable_1510_mode && dma_chan[ch + 6].saved_csr)
+ handled_now += omap1_dma_handle_ch(ch + 6);
+ if (!handled_now)
+ break;
+ handled += handled_now;
+ }
+
+ return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+struct omap_system_dma_plat_info *omap_get_plat_info(void)
+{
+ return p;
+}
+EXPORT_SYMBOL_GPL(omap_get_plat_info);
+
+static int omap_system_dma_probe(struct platform_device *pdev)
+{
+ int ch, ret = 0;
+ int dma_irq;
+ char irq_name[4];
+
+ p = pdev->dev.platform_data;
+ if (!p) {
+ dev_err(&pdev->dev,
+ "%s: System DMA initialized without platform data\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ d = p->dma_attr;
+ errata = p->errata;
+
+ if ((d->dev_caps & RESERVE_CHANNEL) && omap_dma_reserve_channels
+ && (omap_dma_reserve_channels < d->lch_count))
+ d->lch_count = omap_dma_reserve_channels;
+
+ dma_lch_count = d->lch_count;
+ dma_chan_count = dma_lch_count;
+ enable_1510_mode = d->dev_caps & ENABLE_1510_MODE;
+
+ dma_chan = devm_kcalloc(&pdev->dev, dma_lch_count,
+ sizeof(*dma_chan), GFP_KERNEL);
+ if (!dma_chan)
+ return -ENOMEM;
+
+ for (ch = 0; ch < dma_chan_count; ch++) {
+ omap_clear_dma(ch);
+
+ dma_chan[ch].dev_id = -1;
+ dma_chan[ch].next_lch = -1;
+
+ if (ch >= 6 && enable_1510_mode)
+ continue;
+
+ /*
+ * request_irq() doesn't like dev_id (ie. ch) being
+ * zero, so we have to kludge around this.
+ */
+ sprintf(&irq_name[0], "%d", ch);
+ dma_irq = platform_get_irq_byname(pdev, irq_name);
+
+ if (dma_irq < 0) {
+ ret = dma_irq;
+ goto exit_dma_irq_fail;
+ }
+
+ /* INT_DMA_LCD is handled in lcd_dma.c */
+ if (dma_irq == INT_DMA_LCD)
+ continue;
+
+ ret = request_irq(dma_irq,
+ omap1_dma_irq_handler, 0, "DMA",
+ (void *) (ch + 1));
+ if (ret != 0)
+ goto exit_dma_irq_fail;
+ }
+
+ /* reserve dma channels 0 and 1 in high security devices on 34xx */
+ if (d->dev_caps & HS_CHANNELS_RESERVED) {
+ pr_info("Reserving DMA channels 0 and 1 for HS ROM code\n");
+ dma_chan[0].dev_id = 0;
+ dma_chan[1].dev_id = 1;
+ }
+ p->show_dma_caps();
+ return 0;
+
+exit_dma_irq_fail:
+ return ret;
+}
+
+static void omap_system_dma_remove(struct platform_device *pdev)
+{
+ int dma_irq, irq_rel = 0;
+
+ for ( ; irq_rel < dma_chan_count; irq_rel++) {
+ dma_irq = platform_get_irq(pdev, irq_rel);
+ free_irq(dma_irq, (void *)(irq_rel + 1));
+ }
+}
+
+static struct platform_driver omap_system_dma_driver = {
+ .probe = omap_system_dma_probe,
+ .remove_new = omap_system_dma_remove,
+ .driver = {
+ .name = "omap_dma_system"
+ },
+};
+
+static int __init omap_system_dma_init(void)
+{
+ return platform_driver_register(&omap_system_dma_driver);
+}
+arch_initcall(omap_system_dma_init);
+
+static void __exit omap_system_dma_exit(void)
+{
+ platform_driver_unregister(&omap_system_dma_driver);
+}
+
+MODULE_DESCRIPTION("OMAP SYSTEM DMA DRIVER");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Texas Instruments Inc");
+
+/*
+ * Reserve the omap SDMA channels using cmdline bootarg
+ * "omap_dma_reserve_ch=". The valid range is 1 to 32
+ */
+static int __init omap_dma_cmdline_reserve_ch(char *str)
+{
+ if (get_option(&str, &omap_dma_reserve_channels) != 1)
+ omap_dma_reserve_channels = 0;
+ return 1;
+}
+
+__setup("omap_dma_reserve_ch=", omap_dma_cmdline_reserve_ch);
+
+
diff --git a/arch/arm/mach-omap1/opp.h b/arch/arm/mach-omap1/opp.h
new file mode 100644
index 0000000000..5b8b9c8edf
--- /dev/null
+++ b/arch/arm/mach-omap1/opp.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * linux/arch/arm/mach-omap1/opp.h
+ *
+ * Copyright (C) 2004 - 2005 Nokia corporation
+ * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ * Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, Inc
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP1_OPP_H
+#define __ARCH_ARM_MACH_OMAP1_OPP_H
+
+#include <linux/types.h>
+
+struct mpu_rate {
+ unsigned long rate;
+ unsigned long xtal;
+ unsigned long pll_rate;
+ __u16 ckctl_val;
+ __u16 dpllctl_val;
+ u32 flags;
+};
+
+extern struct mpu_rate omap1_rate_table[];
+
+#endif
diff --git a/arch/arm/mach-omap1/opp_data.c b/arch/arm/mach-omap1/opp_data.c
new file mode 100644
index 0000000000..a27ca7dc03
--- /dev/null
+++ b/arch/arm/mach-omap1/opp_data.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * linux/arch/arm/mach-omap1/opp_data.c
+ *
+ * Copyright (C) 2004 - 2005 Nokia corporation
+ * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ * Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, Inc
+ */
+
+#include "clock.h"
+#include "opp.h"
+
+/*-------------------------------------------------------------------------
+ * Omap1 MPU rate table
+ *-------------------------------------------------------------------------*/
+struct mpu_rate omap1_rate_table[] = {
+ /* MPU MHz, xtal MHz, dpll1 MHz, CKCTL, DPLL_CTL
+ * NOTE: Comment order here is different from bits in CKCTL value:
+ * armdiv, dspdiv, dspmmu, tcdiv, perdiv, lcddiv
+ */
+ { 216000000, 12000000, 216000000, 0x050d, 0x2910, /* 1/1/2/2/2/8 */
+ CK_1710 },
+ { 195000000, 13000000, 195000000, 0x050e, 0x2790, /* 1/1/2/2/4/8 */
+ CK_7XX },
+ { 192000000, 19200000, 192000000, 0x050f, 0x2510, /* 1/1/2/2/8/8 */
+ CK_16XX },
+ { 192000000, 12000000, 192000000, 0x050f, 0x2810, /* 1/1/2/2/8/8 */
+ CK_16XX },
+ { 96000000, 12000000, 192000000, 0x055f, 0x2810, /* 2/2/2/2/8/8 */
+ CK_16XX },
+ { 48000000, 12000000, 192000000, 0x0baf, 0x2810, /* 4/4/4/8/8/8 */
+ CK_16XX },
+ { 24000000, 12000000, 192000000, 0x0fff, 0x2810, /* 8/8/8/8/8/8 */
+ CK_16XX },
+ { 182000000, 13000000, 182000000, 0x050e, 0x2710, /* 1/1/2/2/4/8 */
+ CK_7XX },
+ { 168000000, 12000000, 168000000, 0x010f, 0x2710, /* 1/1/1/2/8/8 */
+ CK_16XX|CK_7XX },
+ { 150000000, 12000000, 150000000, 0x010a, 0x2cb0, /* 1/1/1/2/4/4 */
+ CK_1510 },
+ { 120000000, 12000000, 120000000, 0x010a, 0x2510, /* 1/1/1/2/4/4 */
+ CK_16XX|CK_1510|CK_310|CK_7XX },
+ { 96000000, 12000000, 96000000, 0x0005, 0x2410, /* 1/1/1/1/2/2 */
+ CK_16XX|CK_1510|CK_310|CK_7XX },
+ { 60000000, 12000000, 60000000, 0x0005, 0x2290, /* 1/1/1/1/2/2 */
+ CK_16XX|CK_1510|CK_310|CK_7XX },
+ { 30000000, 12000000, 60000000, 0x0555, 0x2290, /* 2/2/2/2/2/2 */
+ CK_16XX|CK_1510|CK_310|CK_7XX },
+ { 0, 0, 0, 0, 0 },
+};
+
diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c
new file mode 100644
index 0000000000..6a5815aa05
--- /dev/null
+++ b/arch/arm/mach-omap1/pm.c
@@ -0,0 +1,644 @@
+/*
+ * linux/arch/arm/mach-omap1/pm.c
+ *
+ * OMAP Power Management Routines
+ *
+ * Original code for the SA11x0:
+ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
+ *
+ * Modified for the PXA250 by Nicolas Pitre:
+ * Copyright (c) 2002 Monta Vista Software, Inc.
+ *
+ * Modified for the OMAP1510 by David Singleton:
+ * Copyright (c) 2002 Monta Vista Software, Inc.
+ *
+ * Cleanup 2004 for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/suspend.h>
+#include <linux/sched.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/interrupt.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/atomic.h>
+#include <linux/cpu.h>
+
+#include <asm/fncpy.h>
+#include <asm/system_misc.h>
+#include <asm/irq.h>
+#include <asm/mach/time.h>
+#include <asm/mach/irq.h>
+
+#include <linux/soc/ti/omap1-io.h>
+#include "tc.h"
+#include <linux/omap-dma.h>
+#include <clocksource/timer-ti-dm.h>
+
+#include "hardware.h"
+#include "mux.h"
+#include "irqs.h"
+#include "iomap.h"
+#include "clock.h"
+#include "pm.h"
+#include "soc.h"
+#include "sram.h"
+
+static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
+static unsigned short dsp_sleep_save[DSP_SLEEP_SAVE_SIZE];
+static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE];
+static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE];
+static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
+
+static unsigned short enable_dyn_sleep;
+
+static ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%hu\n", enable_dyn_sleep);
+}
+
+static ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char * buf, size_t n)
+{
+ unsigned short value;
+ if (sscanf(buf, "%hu", &value) != 1 ||
+ (value != 0 && value != 1) ||
+ (value != 0 && !IS_ENABLED(CONFIG_OMAP_32K_TIMER))) {
+ pr_err("idle_sleep_store: Invalid value\n");
+ return -EINVAL;
+ }
+ enable_dyn_sleep = value;
+ return n;
+}
+
+static struct kobj_attribute sleep_while_idle_attr =
+ __ATTR(sleep_while_idle, 0644, idle_show, idle_store);
+
+
+static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
+
+/*
+ * Let's power down on idle, but only if we are really
+ * idle, because once we start down the path of
+ * going idle we continue to do idle even if we get
+ * a clock tick interrupt . .
+ */
+void omap1_pm_idle(void)
+{
+ extern __u32 arm_idlect1_mask;
+ __u32 use_idlect1 = arm_idlect1_mask;
+
+ local_fiq_disable();
+
+#if defined(CONFIG_OMAP_MPU_TIMER) && !defined(CONFIG_OMAP_DM_TIMER)
+ use_idlect1 = use_idlect1 & ~(1 << 9);
+#endif
+
+#ifdef CONFIG_OMAP_DM_TIMER
+ use_idlect1 = omap_dm_timer_modify_idlect_mask(use_idlect1);
+#endif
+
+ if (omap_dma_running())
+ use_idlect1 &= ~(1 << 6);
+
+ /*
+ * We should be able to remove the do_sleep variable and multiple
+ * tests above as soon as drivers, timer and DMA code have been fixed.
+ * Even the sleep block count should become obsolete.
+ */
+ if ((use_idlect1 != ~0) || !enable_dyn_sleep) {
+
+ __u32 saved_idlect1 = omap_readl(ARM_IDLECT1);
+ if (cpu_is_omap15xx())
+ use_idlect1 &= OMAP1510_BIG_SLEEP_REQUEST;
+ else
+ use_idlect1 &= OMAP1610_IDLECT1_SLEEP_VAL;
+ omap_writel(use_idlect1, ARM_IDLECT1);
+ __asm__ volatile ("mcr p15, 0, r0, c7, c0, 4");
+ omap_writel(saved_idlect1, ARM_IDLECT1);
+
+ local_fiq_enable();
+ return;
+ }
+ omap_sram_suspend(omap_readl(ARM_IDLECT1),
+ omap_readl(ARM_IDLECT2));
+
+ local_fiq_enable();
+}
+
+/*
+ * Configuration of the wakeup event is board specific. For the
+ * moment we put it into this helper function. Later it may move
+ * to board specific files.
+ */
+static void omap_pm_wakeup_setup(void)
+{
+ u32 level1_wake = 0;
+ u32 level2_wake = OMAP_IRQ_BIT(INT_UART2);
+
+ /*
+ * Turn off all interrupts except GPIO bank 1, L1-2nd level cascade,
+ * and the L2 wakeup interrupts: keypad and UART2. Note that the
+ * drivers must still separately call omap_set_gpio_wakeup() to
+ * wake up to a GPIO interrupt.
+ */
+ if (cpu_is_omap15xx())
+ level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
+ OMAP_IRQ_BIT(INT_1510_IH2_IRQ);
+ else if (cpu_is_omap16xx())
+ level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
+ OMAP_IRQ_BIT(INT_1610_IH2_IRQ);
+
+ omap_writel(~level1_wake, OMAP_IH1_MIR);
+
+ if (cpu_is_omap15xx()) {
+ level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
+ omap_writel(~level2_wake, OMAP_IH2_MIR);
+ } else if (cpu_is_omap16xx()) {
+ level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
+ omap_writel(~level2_wake, OMAP_IH2_0_MIR);
+
+ /* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */
+ omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ),
+ OMAP_IH2_1_MIR);
+ omap_writel(~0x0, OMAP_IH2_2_MIR);
+ omap_writel(~0x0, OMAP_IH2_3_MIR);
+ }
+
+ /* New IRQ agreement, recalculate in cascade order */
+ omap_writel(1, OMAP_IH2_CONTROL);
+ omap_writel(1, OMAP_IH1_CONTROL);
+}
+
+#define EN_DSPCK 13 /* ARM_CKCTL */
+#define EN_APICK 6 /* ARM_IDLECT2 */
+#define DSP_EN 1 /* ARM_RSTCT1 */
+
+void omap1_pm_suspend(void)
+{
+ unsigned long arg0 = 0, arg1 = 0;
+
+ printk(KERN_INFO "PM: OMAP%x is trying to enter deep sleep...\n",
+ omap_rev());
+
+ omap_serial_wake_trigger(1);
+
+ if (!cpu_is_omap15xx())
+ omap_writew(0xffff, ULPD_SOFT_DISABLE_REQ_REG);
+
+ /*
+ * Step 1: turn off interrupts (FIXME: NOTE: already disabled)
+ */
+
+ local_irq_disable();
+ local_fiq_disable();
+
+ /*
+ * Step 2: save registers
+ *
+ * The omap is a strange/beautiful device. The caches, memory
+ * and register state are preserved across power saves.
+ * We have to save and restore very little register state to
+ * idle the omap.
+ *
+ * Save interrupt, MPUI, ARM and UPLD control registers.
+ */
+
+ if (cpu_is_omap15xx()) {
+ MPUI1510_SAVE(OMAP_IH1_MIR);
+ MPUI1510_SAVE(OMAP_IH2_MIR);
+ MPUI1510_SAVE(MPUI_CTRL);
+ MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
+ MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
+ MPUI1510_SAVE(EMIFS_CONFIG);
+ MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
+ } else if (cpu_is_omap16xx()) {
+ MPUI1610_SAVE(OMAP_IH1_MIR);
+ MPUI1610_SAVE(OMAP_IH2_0_MIR);
+ MPUI1610_SAVE(OMAP_IH2_1_MIR);
+ MPUI1610_SAVE(OMAP_IH2_2_MIR);
+ MPUI1610_SAVE(OMAP_IH2_3_MIR);
+ MPUI1610_SAVE(MPUI_CTRL);
+ MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
+ MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
+ MPUI1610_SAVE(EMIFS_CONFIG);
+ MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
+ }
+
+ ARM_SAVE(ARM_CKCTL);
+ ARM_SAVE(ARM_IDLECT1);
+ ARM_SAVE(ARM_IDLECT2);
+ if (!(cpu_is_omap15xx()))
+ ARM_SAVE(ARM_IDLECT3);
+ ARM_SAVE(ARM_EWUPCT);
+ ARM_SAVE(ARM_RSTCT1);
+ ARM_SAVE(ARM_RSTCT2);
+ ARM_SAVE(ARM_SYSST);
+ ULPD_SAVE(ULPD_CLOCK_CTRL);
+ ULPD_SAVE(ULPD_STATUS_REQ);
+
+ /* (Step 3 removed - we now allow deep sleep by default) */
+
+ /*
+ * Step 4: OMAP DSP Shutdown
+ */
+
+ /* stop DSP */
+ omap_writew(omap_readw(ARM_RSTCT1) & ~(1 << DSP_EN), ARM_RSTCT1);
+
+ /* shut down dsp_ck */
+ omap_writew(omap_readw(ARM_CKCTL) & ~(1 << EN_DSPCK), ARM_CKCTL);
+
+ /* temporarily enabling api_ck to access DSP registers */
+ omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2);
+
+ /* save DSP registers */
+ DSP_SAVE(DSP_IDLECT2);
+
+ /* Stop all DSP domain clocks */
+ __raw_writew(0, DSP_IDLECT2);
+
+ /*
+ * Step 5: Wakeup Event Setup
+ */
+
+ omap_pm_wakeup_setup();
+
+ /*
+ * Step 6: ARM and Traffic controller shutdown
+ */
+
+ /* disable ARM watchdog */
+ omap_writel(0x00F5, OMAP_WDT_TIMER_MODE);
+ omap_writel(0x00A0, OMAP_WDT_TIMER_MODE);
+
+ /*
+ * Step 6b: ARM and Traffic controller shutdown
+ *
+ * Step 6 continues here. Prepare jump to power management
+ * assembly code in internal SRAM.
+ *
+ * Since the omap_cpu_suspend routine has been copied to
+ * SRAM, we'll do an indirect procedure call to it and pass the
+ * contents of arm_idlect1 and arm_idlect2 so it can restore
+ * them when it wakes up and it will return.
+ */
+
+ arg0 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT1];
+ arg1 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT2];
+
+ /*
+ * Step 6c: ARM and Traffic controller shutdown
+ *
+ * Jump to assembly code. The processor will stay there
+ * until wake up.
+ */
+ omap_sram_suspend(arg0, arg1);
+
+ /*
+ * If we are here, processor is woken up!
+ */
+
+ /*
+ * Restore DSP clocks
+ */
+
+ /* again temporarily enabling api_ck to access DSP registers */
+ omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2);
+
+ /* Restore DSP domain clocks */
+ DSP_RESTORE(DSP_IDLECT2);
+
+ /*
+ * Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did
+ */
+
+ if (!(cpu_is_omap15xx()))
+ ARM_RESTORE(ARM_IDLECT3);
+ ARM_RESTORE(ARM_CKCTL);
+ ARM_RESTORE(ARM_EWUPCT);
+ ARM_RESTORE(ARM_RSTCT1);
+ ARM_RESTORE(ARM_RSTCT2);
+ ARM_RESTORE(ARM_SYSST);
+ ULPD_RESTORE(ULPD_CLOCK_CTRL);
+ ULPD_RESTORE(ULPD_STATUS_REQ);
+
+ if (cpu_is_omap15xx()) {
+ MPUI1510_RESTORE(MPUI_CTRL);
+ MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG);
+ MPUI1510_RESTORE(MPUI_DSP_API_CONFIG);
+ MPUI1510_RESTORE(EMIFS_CONFIG);
+ MPUI1510_RESTORE(EMIFF_SDRAM_CONFIG);
+ MPUI1510_RESTORE(OMAP_IH1_MIR);
+ MPUI1510_RESTORE(OMAP_IH2_MIR);
+ } else if (cpu_is_omap16xx()) {
+ MPUI1610_RESTORE(MPUI_CTRL);
+ MPUI1610_RESTORE(MPUI_DSP_BOOT_CONFIG);
+ MPUI1610_RESTORE(MPUI_DSP_API_CONFIG);
+ MPUI1610_RESTORE(EMIFS_CONFIG);
+ MPUI1610_RESTORE(EMIFF_SDRAM_CONFIG);
+
+ MPUI1610_RESTORE(OMAP_IH1_MIR);
+ MPUI1610_RESTORE(OMAP_IH2_0_MIR);
+ MPUI1610_RESTORE(OMAP_IH2_1_MIR);
+ MPUI1610_RESTORE(OMAP_IH2_2_MIR);
+ MPUI1610_RESTORE(OMAP_IH2_3_MIR);
+ }
+
+ if (!cpu_is_omap15xx())
+ omap_writew(0, ULPD_SOFT_DISABLE_REQ_REG);
+
+ /*
+ * Re-enable interrupts
+ */
+
+ local_irq_enable();
+ local_fiq_enable();
+
+ omap_serial_wake_trigger(0);
+
+ printk(KERN_INFO "PM: OMAP%x is re-starting from deep sleep...\n",
+ omap_rev());
+}
+
+#ifdef CONFIG_DEBUG_FS
+/*
+ * Read system PM registers for debugging
+ */
+static int omap_pm_debug_show(struct seq_file *m, void *v)
+{
+ ARM_SAVE(ARM_CKCTL);
+ ARM_SAVE(ARM_IDLECT1);
+ ARM_SAVE(ARM_IDLECT2);
+ if (!(cpu_is_omap15xx()))
+ ARM_SAVE(ARM_IDLECT3);
+ ARM_SAVE(ARM_EWUPCT);
+ ARM_SAVE(ARM_RSTCT1);
+ ARM_SAVE(ARM_RSTCT2);
+ ARM_SAVE(ARM_SYSST);
+
+ ULPD_SAVE(ULPD_IT_STATUS);
+ ULPD_SAVE(ULPD_CLOCK_CTRL);
+ ULPD_SAVE(ULPD_SOFT_REQ);
+ ULPD_SAVE(ULPD_STATUS_REQ);
+ ULPD_SAVE(ULPD_DPLL_CTRL);
+ ULPD_SAVE(ULPD_POWER_CTRL);
+
+ if (cpu_is_omap15xx()) {
+ MPUI1510_SAVE(MPUI_CTRL);
+ MPUI1510_SAVE(MPUI_DSP_STATUS);
+ MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
+ MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
+ MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
+ MPUI1510_SAVE(EMIFS_CONFIG);
+ } else if (cpu_is_omap16xx()) {
+ MPUI1610_SAVE(MPUI_CTRL);
+ MPUI1610_SAVE(MPUI_DSP_STATUS);
+ MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
+ MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
+ MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
+ MPUI1610_SAVE(EMIFS_CONFIG);
+ }
+
+ seq_printf(m,
+ "ARM_CKCTL_REG: 0x%-8x \n"
+ "ARM_IDLECT1_REG: 0x%-8x \n"
+ "ARM_IDLECT2_REG: 0x%-8x \n"
+ "ARM_IDLECT3_REG: 0x%-8x \n"
+ "ARM_EWUPCT_REG: 0x%-8x \n"
+ "ARM_RSTCT1_REG: 0x%-8x \n"
+ "ARM_RSTCT2_REG: 0x%-8x \n"
+ "ARM_SYSST_REG: 0x%-8x \n"
+ "ULPD_IT_STATUS_REG: 0x%-4x \n"
+ "ULPD_CLOCK_CTRL_REG: 0x%-4x \n"
+ "ULPD_SOFT_REQ_REG: 0x%-4x \n"
+ "ULPD_DPLL_CTRL_REG: 0x%-4x \n"
+ "ULPD_STATUS_REQ_REG: 0x%-4x \n"
+ "ULPD_POWER_CTRL_REG: 0x%-4x \n",
+ ARM_SHOW(ARM_CKCTL),
+ ARM_SHOW(ARM_IDLECT1),
+ ARM_SHOW(ARM_IDLECT2),
+ ARM_SHOW(ARM_IDLECT3),
+ ARM_SHOW(ARM_EWUPCT),
+ ARM_SHOW(ARM_RSTCT1),
+ ARM_SHOW(ARM_RSTCT2),
+ ARM_SHOW(ARM_SYSST),
+ ULPD_SHOW(ULPD_IT_STATUS),
+ ULPD_SHOW(ULPD_CLOCK_CTRL),
+ ULPD_SHOW(ULPD_SOFT_REQ),
+ ULPD_SHOW(ULPD_DPLL_CTRL),
+ ULPD_SHOW(ULPD_STATUS_REQ),
+ ULPD_SHOW(ULPD_POWER_CTRL));
+
+ if (cpu_is_omap15xx()) {
+ seq_printf(m,
+ "MPUI1510_CTRL_REG 0x%-8x \n"
+ "MPUI1510_DSP_STATUS_REG: 0x%-8x \n"
+ "MPUI1510_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
+ "MPUI1510_DSP_API_CONFIG_REG: 0x%-8x \n"
+ "MPUI1510_SDRAM_CONFIG_REG: 0x%-8x \n"
+ "MPUI1510_EMIFS_CONFIG_REG: 0x%-8x \n",
+ MPUI1510_SHOW(MPUI_CTRL),
+ MPUI1510_SHOW(MPUI_DSP_STATUS),
+ MPUI1510_SHOW(MPUI_DSP_BOOT_CONFIG),
+ MPUI1510_SHOW(MPUI_DSP_API_CONFIG),
+ MPUI1510_SHOW(EMIFF_SDRAM_CONFIG),
+ MPUI1510_SHOW(EMIFS_CONFIG));
+ } else if (cpu_is_omap16xx()) {
+ seq_printf(m,
+ "MPUI1610_CTRL_REG 0x%-8x \n"
+ "MPUI1610_DSP_STATUS_REG: 0x%-8x \n"
+ "MPUI1610_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
+ "MPUI1610_DSP_API_CONFIG_REG: 0x%-8x \n"
+ "MPUI1610_SDRAM_CONFIG_REG: 0x%-8x \n"
+ "MPUI1610_EMIFS_CONFIG_REG: 0x%-8x \n",
+ MPUI1610_SHOW(MPUI_CTRL),
+ MPUI1610_SHOW(MPUI_DSP_STATUS),
+ MPUI1610_SHOW(MPUI_DSP_BOOT_CONFIG),
+ MPUI1610_SHOW(MPUI_DSP_API_CONFIG),
+ MPUI1610_SHOW(EMIFF_SDRAM_CONFIG),
+ MPUI1610_SHOW(EMIFS_CONFIG));
+ }
+
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(omap_pm_debug);
+
+static void omap_pm_init_debugfs(void)
+{
+ struct dentry *d;
+
+ d = debugfs_create_dir("pm_debug", NULL);
+ debugfs_create_file("omap_pm", S_IWUSR | S_IRUGO, d, NULL,
+ &omap_pm_debug_fops);
+}
+
+#endif /* CONFIG_DEBUG_FS */
+
+/*
+ * omap_pm_prepare - Do preliminary suspend work.
+ *
+ */
+static int omap_pm_prepare(void)
+{
+ /* We cannot sleep in idle until we have resumed */
+ cpu_idle_poll_ctrl(true);
+ return 0;
+}
+
+
+/*
+ * omap_pm_enter - Actually enter a sleep state.
+ * @state: State we're entering.
+ *
+ */
+
+static int omap_pm_enter(suspend_state_t state)
+{
+ switch (state)
+ {
+ case PM_SUSPEND_MEM:
+ omap1_pm_suspend();
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+/**
+ * omap_pm_finish - Finish up suspend sequence.
+ *
+ * This is called after we wake back up (or if entering the sleep state
+ * failed).
+ */
+
+static void omap_pm_finish(void)
+{
+ cpu_idle_poll_ctrl(false);
+}
+
+
+static irqreturn_t omap_wakeup_interrupt(int irq, void *dev)
+{
+ return IRQ_HANDLED;
+}
+
+
+
+static const struct platform_suspend_ops omap_pm_ops = {
+ .prepare = omap_pm_prepare,
+ .enter = omap_pm_enter,
+ .finish = omap_pm_finish,
+ .valid = suspend_valid_only_mem,
+};
+
+static int __init omap_pm_init(void)
+{
+ int error = 0;
+ int irq;
+
+ if (!cpu_class_is_omap1())
+ return -ENODEV;
+
+ pr_info("Power Management for TI OMAP.\n");
+
+ if (!IS_ENABLED(CONFIG_OMAP_32K_TIMER))
+ pr_info("OMAP1 PM: sleep states in idle disabled due to no 32KiHz timer\n");
+
+ if (!IS_ENABLED(CONFIG_OMAP_DM_TIMER))
+ pr_info("OMAP1 PM: sleep states in idle disabled due to no DMTIMER support\n");
+
+ if (IS_ENABLED(CONFIG_OMAP_32K_TIMER) &&
+ IS_ENABLED(CONFIG_OMAP_DM_TIMER)) {
+ /* OMAP16xx only */
+ pr_info("OMAP1 PM: sleep states in idle enabled\n");
+ enable_dyn_sleep = 1;
+ }
+
+ /*
+ * We copy the assembler sleep/wakeup routines to SRAM.
+ * These routines need to be in SRAM as that's the only
+ * memory the MPU can see when it wakes up.
+ */
+ if (cpu_is_omap15xx()) {
+ omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend,
+ omap1510_cpu_suspend_sz);
+ } else if (cpu_is_omap16xx()) {
+ omap_sram_suspend = omap_sram_push(omap1610_cpu_suspend,
+ omap1610_cpu_suspend_sz);
+ }
+
+ if (omap_sram_suspend == NULL) {
+ printk(KERN_ERR "PM not initialized: Missing SRAM support\n");
+ return -ENODEV;
+ }
+
+ arm_pm_idle = omap1_pm_idle;
+
+ if (cpu_is_omap16xx())
+ irq = INT_1610_WAKE_UP_REQ;
+ else
+ irq = -1;
+
+ if (irq >= 0) {
+ if (request_irq(irq, omap_wakeup_interrupt, 0, "peripheral wakeup", NULL))
+ pr_err("Failed to request irq %d (peripheral wakeup)\n", irq);
+ }
+
+ /* Program new power ramp-up time
+ * (0 for most boards since we don't lower voltage when in deep sleep)
+ */
+ omap_writew(ULPD_SETUP_ANALOG_CELL_3_VAL, ULPD_SETUP_ANALOG_CELL_3);
+
+ /* Setup ULPD POWER_CTRL_REG - enter deep sleep whenever possible */
+ omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL);
+
+ /* Configure IDLECT3 */
+ if (cpu_is_omap16xx())
+ omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3);
+
+ suspend_set_ops(&omap_pm_ops);
+
+#ifdef CONFIG_DEBUG_FS
+ omap_pm_init_debugfs();
+#endif
+
+ error = sysfs_create_file(power_kobj, &sleep_while_idle_attr.attr);
+ if (error)
+ pr_err("sysfs_create_file failed: %d\n", error);
+
+ if (cpu_is_omap16xx()) {
+ /* configure LOW_PWR pin */
+ omap_cfg_reg(T20_1610_LOW_PWR);
+ }
+
+ return error;
+}
+__initcall(omap_pm_init);
diff --git a/arch/arm/mach-omap1/pm.h b/arch/arm/mach-omap1/pm.h
new file mode 100644
index 0000000000..d4373a5c46
--- /dev/null
+++ b/arch/arm/mach-omap1/pm.h
@@ -0,0 +1,241 @@
+/*
+ * arch/arm/mach-omap1/pm.h
+ *
+ * Header file for OMAP1 Power Management Routines
+ *
+ * Author: MontaVista Software, Inc.
+ * support@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ * Cleanup 2004 for Linux 2.6 by Dirk Behme <dirk.behme@de.bosch.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP1_PM_H
+#define __ARCH_ARM_MACH_OMAP1_PM_H
+
+#include <linux/soc/ti/omap1-io.h>
+
+/*
+ * ----------------------------------------------------------------------------
+ * Register and offset definitions to be used in PM assembler code
+ * ----------------------------------------------------------------------------
+ */
+#define CLKGEN_REG_ASM_BASE OMAP1_IO_ADDRESS(0xfffece00)
+#define ARM_IDLECT1_ASM_OFFSET 0x04
+#define ARM_IDLECT2_ASM_OFFSET 0x08
+
+#define TCMIF_ASM_BASE OMAP1_IO_ADDRESS(0xfffecc00)
+#define EMIFS_CONFIG_ASM_OFFSET 0x0c
+#define EMIFF_SDRAM_CONFIG_ASM_OFFSET 0x20
+
+/*
+ * ----------------------------------------------------------------------------
+ * Power management bitmasks
+ * ----------------------------------------------------------------------------
+ */
+#define IDLE_WAIT_CYCLES 0x00000fff
+#define PERIPHERAL_ENABLE 0x2
+
+#define SELF_REFRESH_MODE 0x0c000001
+#define IDLE_EMIFS_REQUEST 0xc
+#define MODEM_32K_EN 0x1
+#define PER_EN 0x1
+
+#define CPU_SUSPEND_SIZE 200
+#define ULPD_LOW_PWR_EN 0x0001
+#define ULPD_DEEP_SLEEP_TRANSITION_EN 0x0010
+#define ULPD_SETUP_ANALOG_CELL_3_VAL 0
+#define ULPD_POWER_CTRL_REG_VAL 0x0219
+
+#define DSP_IDLE_DELAY 10
+#define DSP_IDLE 0x0040
+#define DSP_RST 0x0004
+#define DSP_ENABLE 0x0002
+#define SUFFICIENT_DSP_RESET_TIME 1000
+#define DEFAULT_MPUI_CONFIG 0x05cf
+#define ENABLE_XORCLK 0x2
+#define DSP_CLOCK_ENABLE 0x2000
+#define DSP_IDLE_MODE 0x2
+#define TC_IDLE_REQUEST (0x0000000c)
+
+#define IRQ_LEVEL2 (1<<0)
+#define IRQ_KEYBOARD (1<<1)
+#define IRQ_UART2 (1<<15)
+
+#define PDE_BIT 0x08
+#define PWD_EN_BIT 0x04
+#define EN_PERCK_BIT 0x04
+
+#define OMAP1510_DEEP_SLEEP_REQUEST 0x0ec7
+#define OMAP1510_BIG_SLEEP_REQUEST 0x0cc5
+#define OMAP1510_IDLE_LOOP_REQUEST 0x0c00
+#define OMAP1510_IDLE_CLOCK_DOMAINS 0x2
+
+/* Both big sleep and deep sleep use same values. Difference is in ULPD. */
+#define OMAP1610_IDLECT1_SLEEP_VAL 0x13c7
+#define OMAP1610_IDLECT2_SLEEP_VAL 0x09c7
+#define OMAP1610_IDLECT3_VAL 0x3f
+#define OMAP1610_IDLECT3_SLEEP_ORMASK 0x2c
+#define OMAP1610_IDLECT3 0xfffece24
+#define OMAP1610_IDLE_LOOP_REQUEST 0x0400
+
+#ifndef __ASSEMBLER__
+
+#include <linux/clk.h>
+
+extern struct kset power_subsys;
+
+extern void prevent_idle_sleep(void);
+extern void allow_idle_sleep(void);
+
+extern void omap1_pm_idle(void);
+extern void omap1_pm_suspend(void);
+
+extern void omap1510_cpu_suspend(unsigned long, unsigned long);
+extern void omap1610_cpu_suspend(unsigned long, unsigned long);
+extern void omap1510_idle_loop_suspend(void);
+extern void omap1610_idle_loop_suspend(void);
+
+extern unsigned int omap1510_cpu_suspend_sz;
+extern unsigned int omap1610_cpu_suspend_sz;
+extern unsigned int omap1510_idle_loop_suspend_sz;
+extern unsigned int omap1610_idle_loop_suspend_sz;
+
+#ifdef CONFIG_OMAP_SERIAL_WAKE
+extern void omap_serial_wake_trigger(int enable);
+#else
+#define omap_serial_wakeup_init() {}
+#define omap_serial_wake_trigger(x) {}
+#endif /* CONFIG_OMAP_SERIAL_WAKE */
+
+#define ARM_SAVE(x) arm_sleep_save[ARM_SLEEP_SAVE_##x] = omap_readl(x)
+#define ARM_RESTORE(x) omap_writel((arm_sleep_save[ARM_SLEEP_SAVE_##x]), (x))
+#define ARM_SHOW(x) arm_sleep_save[ARM_SLEEP_SAVE_##x]
+
+#define DSP_SAVE(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x] = __raw_readw(x)
+#define DSP_RESTORE(x) __raw_writew((dsp_sleep_save[DSP_SLEEP_SAVE_##x]), (x))
+#define DSP_SHOW(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x]
+
+#define ULPD_SAVE(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x] = omap_readw(x)
+#define ULPD_RESTORE(x) omap_writew((ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]), (x))
+#define ULPD_SHOW(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]
+
+#define MPUI1510_SAVE(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x] = omap_readl(x)
+#define MPUI1510_RESTORE(x) omap_writel((mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x]), (x))
+#define MPUI1510_SHOW(x) mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_##x]
+
+#define MPUI1610_SAVE(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x] = omap_readl(x)
+#define MPUI1610_RESTORE(x) omap_writel((mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]), (x))
+#define MPUI1610_SHOW(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]
+
+/*
+ * List of global OMAP registers to preserve.
+ * More ones like CP and general purpose register values are preserved
+ * with the stack pointer in sleep.S.
+ */
+
+enum arm_save_state {
+ ARM_SLEEP_SAVE_START = 0,
+ /*
+ * MPU control registers 32 bits
+ */
+ ARM_SLEEP_SAVE_ARM_CKCTL,
+ ARM_SLEEP_SAVE_ARM_IDLECT1,
+ ARM_SLEEP_SAVE_ARM_IDLECT2,
+ ARM_SLEEP_SAVE_ARM_IDLECT3,
+ ARM_SLEEP_SAVE_ARM_EWUPCT,
+ ARM_SLEEP_SAVE_ARM_RSTCT1,
+ ARM_SLEEP_SAVE_ARM_RSTCT2,
+ ARM_SLEEP_SAVE_ARM_SYSST,
+ ARM_SLEEP_SAVE_SIZE
+};
+
+enum dsp_save_state {
+ DSP_SLEEP_SAVE_START = 0,
+ /*
+ * DSP registers 16 bits
+ */
+ DSP_SLEEP_SAVE_DSP_IDLECT2,
+ DSP_SLEEP_SAVE_SIZE
+};
+
+enum ulpd_save_state {
+ ULPD_SLEEP_SAVE_START = 0,
+ /*
+ * ULPD registers 16 bits
+ */
+ ULPD_SLEEP_SAVE_ULPD_IT_STATUS,
+ ULPD_SLEEP_SAVE_ULPD_CLOCK_CTRL,
+ ULPD_SLEEP_SAVE_ULPD_SOFT_REQ,
+ ULPD_SLEEP_SAVE_ULPD_STATUS_REQ,
+ ULPD_SLEEP_SAVE_ULPD_DPLL_CTRL,
+ ULPD_SLEEP_SAVE_ULPD_POWER_CTRL,
+ ULPD_SLEEP_SAVE_SIZE
+};
+
+enum mpui1510_save_state {
+ MPUI1510_SLEEP_SAVE_START = 0,
+ /*
+ * MPUI registers 32 bits
+ */
+ MPUI1510_SLEEP_SAVE_MPUI_CTRL,
+ MPUI1510_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
+ MPUI1510_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
+ MPUI1510_SLEEP_SAVE_MPUI_DSP_STATUS,
+ MPUI1510_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
+ MPUI1510_SLEEP_SAVE_EMIFS_CONFIG,
+ MPUI1510_SLEEP_SAVE_OMAP_IH1_MIR,
+ MPUI1510_SLEEP_SAVE_OMAP_IH2_MIR,
+#if defined(CONFIG_ARCH_OMAP15XX)
+ MPUI1510_SLEEP_SAVE_SIZE
+#else
+ MPUI1510_SLEEP_SAVE_SIZE = 0
+#endif
+};
+
+enum mpui1610_save_state {
+ MPUI1610_SLEEP_SAVE_START = 0,
+ /*
+ * MPUI registers 32 bits
+ */
+ MPUI1610_SLEEP_SAVE_MPUI_CTRL,
+ MPUI1610_SLEEP_SAVE_MPUI_DSP_BOOT_CONFIG,
+ MPUI1610_SLEEP_SAVE_MPUI_DSP_API_CONFIG,
+ MPUI1610_SLEEP_SAVE_MPUI_DSP_STATUS,
+ MPUI1610_SLEEP_SAVE_EMIFF_SDRAM_CONFIG,
+ MPUI1610_SLEEP_SAVE_EMIFS_CONFIG,
+ MPUI1610_SLEEP_SAVE_OMAP_IH1_MIR,
+ MPUI1610_SLEEP_SAVE_OMAP_IH2_0_MIR,
+ MPUI1610_SLEEP_SAVE_OMAP_IH2_1_MIR,
+ MPUI1610_SLEEP_SAVE_OMAP_IH2_2_MIR,
+ MPUI1610_SLEEP_SAVE_OMAP_IH2_3_MIR,
+#if defined(CONFIG_ARCH_OMAP16XX)
+ MPUI1610_SLEEP_SAVE_SIZE
+#else
+ MPUI1610_SLEEP_SAVE_SIZE = 0
+#endif
+};
+
+#endif /* ASSEMBLER */
+#endif /* __ASM_ARCH_OMAP_PM_H */
diff --git a/arch/arm/mach-omap1/pm_bus.c b/arch/arm/mach-omap1/pm_bus.c
new file mode 100644
index 0000000000..c04619ac06
--- /dev/null
+++ b/arch/arm/mach-omap1/pm_bus.c
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Runtime PM support code for OMAP1
+ *
+ * Author: Kevin Hilman, Deep Root Systems, LLC
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_clock.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include "soc.h"
+
+static struct dev_pm_domain default_pm_domain = {
+ .ops = {
+ USE_PM_CLK_RUNTIME_OPS
+ USE_PLATFORM_PM_SLEEP_OPS
+ },
+};
+
+static struct pm_clk_notifier_block platform_bus_notifier = {
+ .pm_domain = &default_pm_domain,
+ .con_ids = { "ick", "fck", NULL, },
+};
+
+static int __init omap1_pm_runtime_init(void)
+{
+ if (!cpu_class_is_omap1())
+ return -ENODEV;
+
+ pm_clk_add_notifier(&platform_bus_type, &platform_bus_notifier);
+
+ return 0;
+}
+core_initcall(omap1_pm_runtime_init);
diff --git a/arch/arm/mach-omap1/reset.c b/arch/arm/mach-omap1/reset.c
new file mode 100644
index 0000000000..2eee6a6965
--- /dev/null
+++ b/arch/arm/mach-omap1/reset.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * OMAP1 reset support
+ */
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/reboot.h>
+
+#include "hardware.h"
+#include "iomap.h"
+#include "common.h"
+
+/* ARM_SYSST bit shifts related to SoC reset sources */
+#define ARM_SYSST_POR_SHIFT 5
+#define ARM_SYSST_EXT_RST_SHIFT 4
+#define ARM_SYSST_ARM_WDRST_SHIFT 2
+#define ARM_SYSST_GLOB_SWRST_SHIFT 1
+
+/* Standardized reset source bits (across all OMAP SoCs) */
+#define OMAP_GLOBAL_COLD_RST_SRC_ID_SHIFT 0
+#define OMAP_GLOBAL_WARM_RST_SRC_ID_SHIFT 1
+#define OMAP_MPU_WD_RST_SRC_ID_SHIFT 3
+#define OMAP_EXTWARM_RST_SRC_ID_SHIFT 5
+
+
+void omap1_restart(enum reboot_mode mode, const char *cmd)
+{
+ /*
+ * Workaround for 5912/1611b bug mentioned in sprz209d.pdf p. 28
+ * "Global Software Reset Affects Traffic Controller Frequency".
+ */
+ if (cpu_is_omap5912()) {
+ omap_writew(omap_readw(DPLL_CTL) & ~(1 << 4), DPLL_CTL);
+ omap_writew(0x8, ARM_RSTCT1);
+ }
+
+ omap_writew(1, ARM_RSTCT1);
+}
+
+/**
+ * omap1_get_reset_sources - return the source of the SoC's last reset
+ *
+ * Returns bits that represent the last reset source for the SoC. The
+ * format is standardized across OMAPs for use by the OMAP watchdog.
+ */
+u32 omap1_get_reset_sources(void)
+{
+ u32 ret = 0;
+ u16 rs;
+
+ rs = __raw_readw(OMAP1_IO_ADDRESS(ARM_SYSST));
+
+ if (rs & (1 << ARM_SYSST_POR_SHIFT))
+ ret |= 1 << OMAP_GLOBAL_COLD_RST_SRC_ID_SHIFT;
+ if (rs & (1 << ARM_SYSST_EXT_RST_SHIFT))
+ ret |= 1 << OMAP_EXTWARM_RST_SRC_ID_SHIFT;
+ if (rs & (1 << ARM_SYSST_ARM_WDRST_SHIFT))
+ ret |= 1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT;
+ if (rs & (1 << ARM_SYSST_GLOB_SWRST_SHIFT))
+ ret |= 1 << OMAP_GLOBAL_WARM_RST_SRC_ID_SHIFT;
+
+ return ret;
+}
diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c
new file mode 100644
index 0000000000..ffa4a9bece
--- /dev/null
+++ b/arch/arm/mach-omap1/serial.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * linux/arch/arm/mach-omap1/serial.c
+ *
+ * OMAP1 serial support.
+ */
+#include <linux/gpio/machine.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <asm/mach-types.h>
+
+#include "common.h"
+#include "serial.h"
+#include "mux.h"
+#include "pm.h"
+#include "soc.h"
+
+static struct clk * uart1_ck;
+static struct clk * uart2_ck;
+static struct clk * uart3_ck;
+
+static inline unsigned int omap_serial_in(struct plat_serial8250_port *up,
+ int offset)
+{
+ offset <<= up->regshift;
+ return (unsigned int)__raw_readb(up->membase + offset);
+}
+
+static inline void omap_serial_outp(struct plat_serial8250_port *p, int offset,
+ int value)
+{
+ offset <<= p->regshift;
+ __raw_writeb(value, p->membase + offset);
+}
+
+/*
+ * Internal UARTs need to be initialized for the 8250 autoconfig to work
+ * properly. Note that the TX watermark initialization may not be needed
+ * once the 8250.c watermark handling code is merged.
+ */
+static void __init omap_serial_reset(struct plat_serial8250_port *p)
+{
+ omap_serial_outp(p, UART_OMAP_MDR1,
+ UART_OMAP_MDR1_DISABLE); /* disable UART */
+ omap_serial_outp(p, UART_OMAP_SCR, 0x08); /* TX watermark */
+ omap_serial_outp(p, UART_OMAP_MDR1,
+ UART_OMAP_MDR1_16X_MODE); /* enable UART */
+
+ if (!cpu_is_omap15xx()) {
+ omap_serial_outp(p, UART_OMAP_SYSC, 0x01);
+ while (!(omap_serial_in(p, UART_OMAP_SYSC) & 0x01));
+ }
+}
+
+static struct plat_serial8250_port serial_platform_data[] = {
+ {
+ .mapbase = OMAP1_UART1_BASE,
+ .irq = INT_UART1,
+ .flags = UPF_BOOT_AUTOCONF,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ .uartclk = OMAP16XX_BASE_BAUD * 16,
+ },
+ {
+ .mapbase = OMAP1_UART2_BASE,
+ .irq = INT_UART2,
+ .flags = UPF_BOOT_AUTOCONF,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ .uartclk = OMAP16XX_BASE_BAUD * 16,
+ },
+ {
+ .mapbase = OMAP1_UART3_BASE,
+ .irq = INT_UART3,
+ .flags = UPF_BOOT_AUTOCONF,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ .uartclk = OMAP16XX_BASE_BAUD * 16,
+ },
+ { },
+};
+
+static struct platform_device serial_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = serial_platform_data,
+ },
+};
+
+/*
+ * Note that on Innovator-1510 UART2 pins conflict with USB2.
+ * By default UART2 does not work on Innovator-1510 if you have
+ * USB OHCI enabled. To use UART2, you must disable USB2 first.
+ */
+void __init omap_serial_init(void)
+{
+ int i;
+
+ if (cpu_is_omap15xx()) {
+ serial_platform_data[0].uartclk = OMAP1510_BASE_BAUD * 16;
+ serial_platform_data[1].uartclk = OMAP1510_BASE_BAUD * 16;
+ serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(serial_platform_data) - 1; i++) {
+ /* Static mapping, never released */
+ serial_platform_data[i].membase =
+ ioremap(serial_platform_data[i].mapbase, SZ_2K);
+ if (!serial_platform_data[i].membase) {
+ printk(KERN_ERR "Could not ioremap uart%i\n", i);
+ continue;
+ }
+ switch (i) {
+ case 0:
+ uart1_ck = clk_get(NULL, "uart1_ck");
+ if (IS_ERR(uart1_ck))
+ printk("Could not get uart1_ck\n");
+ else {
+ clk_prepare_enable(uart1_ck);
+ if (cpu_is_omap15xx())
+ clk_set_rate(uart1_ck, 12000000);
+ }
+ break;
+ case 1:
+ uart2_ck = clk_get(NULL, "uart2_ck");
+ if (IS_ERR(uart2_ck))
+ printk("Could not get uart2_ck\n");
+ else {
+ clk_prepare_enable(uart2_ck);
+ if (cpu_is_omap15xx())
+ clk_set_rate(uart2_ck, 12000000);
+ else
+ clk_set_rate(uart2_ck, 48000000);
+ }
+ break;
+ case 2:
+ uart3_ck = clk_get(NULL, "uart3_ck");
+ if (IS_ERR(uart3_ck))
+ printk("Could not get uart3_ck\n");
+ else {
+ clk_prepare_enable(uart3_ck);
+ if (cpu_is_omap15xx())
+ clk_set_rate(uart3_ck, 12000000);
+ }
+ break;
+ }
+ omap_serial_reset(&serial_platform_data[i]);
+ }
+}
+
+#ifdef CONFIG_OMAP_SERIAL_WAKE
+
+static irqreturn_t omap_serial_wake_interrupt(int irq, void *dev_id)
+{
+ /* Need to do something with serial port right after wake-up? */
+ return IRQ_HANDLED;
+}
+
+/*
+ * Reroutes serial RX lines to GPIO lines for the duration of
+ * sleep to allow waking up the device from serial port even
+ * in deep sleep.
+ */
+void omap_serial_wake_trigger(int enable)
+{
+ if (!cpu_is_omap16xx())
+ return;
+
+ if (uart1_ck != NULL) {
+ if (enable)
+ omap_cfg_reg(V14_16XX_GPIO37);
+ else
+ omap_cfg_reg(V14_16XX_UART1_RX);
+ }
+ if (uart2_ck != NULL) {
+ if (enable)
+ omap_cfg_reg(R9_16XX_GPIO18);
+ else
+ omap_cfg_reg(R9_16XX_UART2_RX);
+ }
+ if (uart3_ck != NULL) {
+ if (enable)
+ omap_cfg_reg(L14_16XX_GPIO49);
+ else
+ omap_cfg_reg(L14_16XX_UART3_RX);
+ }
+}
+
+static void __init omap_serial_set_port_wakeup(int idx)
+{
+ struct gpio_desc *d;
+ int ret;
+
+ d = gpiod_get_index(NULL, "wakeup", idx, GPIOD_IN);
+ if (IS_ERR(d)) {
+ pr_err("Unable to get UART wakeup GPIO descriptor\n");
+ return;
+ }
+ ret = request_irq(gpiod_to_irq(d), &omap_serial_wake_interrupt,
+ IRQF_TRIGGER_RISING, "serial wakeup", NULL);
+ if (ret) {
+ gpiod_put(d);
+ pr_err("No interrupt for UART%d wake GPIO\n", idx + 1);
+ return;
+ }
+ enable_irq_wake(gpiod_to_irq(d));
+}
+
+
+int __init omap_serial_wakeup_init(void)
+{
+ if (!cpu_is_omap16xx())
+ return 0;
+
+ if (uart1_ck != NULL)
+ omap_serial_set_port_wakeup(0);
+ if (uart2_ck != NULL)
+ omap_serial_set_port_wakeup(1);
+ if (uart3_ck != NULL)
+ omap_serial_set_port_wakeup(2);
+
+ return 0;
+}
+
+#endif /* CONFIG_OMAP_SERIAL_WAKE */
+
+static int __init omap_init(void)
+{
+ if (!cpu_class_is_omap1())
+ return -ENODEV;
+
+ return platform_device_register(&serial_device);
+}
+arch_initcall(omap_init);
diff --git a/arch/arm/mach-omap1/serial.h b/arch/arm/mach-omap1/serial.h
new file mode 100644
index 0000000000..4700e384c3
--- /dev/null
+++ b/arch/arm/mach-omap1/serial.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2009 Texas Instruments
+ * Added OMAP4 support- Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_SERIAL_H
+#define __ASM_ARCH_SERIAL_H
+
+#include <linux/init.h>
+
+/*
+ * Memory entry used for the DEBUG_LL UART configuration, relative to
+ * start of RAM. See also uncompress.h and debug-macro.S.
+ *
+ * Note that using a memory location for storing the UART configuration
+ * has at least two limitations:
+ *
+ * 1. Kernel uncompress code cannot overlap OMAP_UART_INFO as the
+ * uncompress code could then partially overwrite itself
+ * 2. We assume printascii is called at least once before paging_init,
+ * and addruart has a chance to read OMAP_UART_INFO
+ */
+#define OMAP_UART_INFO_OFS 0x3ffc
+
+#define OMAP_PORT_SHIFT 2
+#define OMAP7XX_PORT_SHIFT 0
+
+#define OMAP1510_BASE_BAUD (12000000/16)
+#define OMAP16XX_BASE_BAUD (48000000/16)
+
+/*
+ * DEBUG_LL port encoding stored into the UART1 scratchpad register by
+ * decomp_setup in uncompress.h
+ */
+#define OMAP1UART1 11
+#define OMAP1UART2 12
+#define OMAP1UART3 13
+
+#ifndef __ASSEMBLER__
+extern void omap_serial_init(void);
+#endif
+
+#endif
diff --git a/arch/arm/mach-omap1/sleep.S b/arch/arm/mach-omap1/sleep.S
new file mode 100644
index 0000000000..6192f52d53
--- /dev/null
+++ b/arch/arm/mach-omap1/sleep.S
@@ -0,0 +1,290 @@
+/*
+ * linux/arch/arm/mach-omap1/sleep.S
+ *
+ * Low-level OMAP7XX/1510/1610 sleep/wakeUp support
+ *
+ * Initial SA1110 code:
+ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
+ *
+ * Adapted for PXA by Nicolas Pitre:
+ * Copyright (c) 2002 Monta Vista Software, Inc.
+ *
+ * Support for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/assembler.h>
+
+#include "hardware.h"
+
+#include "iomap.h"
+#include "pm.h"
+
+ .text
+
+
+/*
+ * Forces OMAP into deep sleep state
+ *
+ * omapXXXX_cpu_suspend()
+ *
+ * The values of the registers ARM_IDLECT1 and ARM_IDLECT2 are passed
+ * as arg0 and arg1 from caller. arg0 is stored in register r0 and arg1
+ * in register r1.
+ *
+ * Note: This code get's copied to internal SRAM at boot. When the OMAP
+ * wakes up it continues execution at the point it went to sleep.
+ *
+ * Note: Because of errata work arounds we have processor specific functions
+ * here. They are mostly the same, but slightly different.
+ *
+ */
+
+#ifdef CONFIG_ARCH_OMAP15XX
+ .align 3
+ENTRY(omap1510_cpu_suspend)
+
+ @ save registers on stack
+ stmfd sp!, {r0 - r12, lr}
+
+ @ load base address of Traffic Controller
+ mov r4, #TCMIF_ASM_BASE & 0xff000000
+ orr r4, r4, #TCMIF_ASM_BASE & 0x00ff0000
+ orr r4, r4, #TCMIF_ASM_BASE & 0x0000ff00
+
+ @ work around errata of OMAP1510 PDE bit for TC shut down
+ @ clear PDE bit
+ ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+ bic r5, r5, #PDE_BIT & 0xff
+ str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+
+ @ set PWD_EN bit
+ and r5, r5, #PWD_EN_BIT & 0xff
+ str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+
+ @ prepare to put SDRAM into self-refresh manually
+ ldr r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+ orr r5, r5, #SELF_REFRESH_MODE & 0xff000000
+ orr r5, r5, #SELF_REFRESH_MODE & 0x000000ff
+ str r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+
+ @ prepare to put EMIFS to Sleep
+ ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+ orr r5, r5, #IDLE_EMIFS_REQUEST & 0xff
+ str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+
+ @ load base address of ARM_IDLECT1 and ARM_IDLECT2
+ mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
+ orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
+ orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
+
+ @ turn off clock domains
+ mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff
+ orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00
+ strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+
+ @ request ARM idle
+ mov r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff
+ orr r3, r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff00
+ strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+ mov r5, #IDLE_WAIT_CYCLES & 0xff
+ orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00
+l_1510_2:
+ subs r5, r5, #1
+ bne l_1510_2
+/*
+ * Let's wait for the next wake up event to wake us up. r0 can't be
+ * used here because r0 holds ARM_IDLECT1
+ */
+ mov r2, #0
+ mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt
+/*
+ * omap1510_cpu_suspend()'s resume point.
+ *
+ * It will just start executing here, so we'll restore stuff from the
+ * stack, reset the ARM_IDLECT1 and ARM_IDLECT2.
+ */
+ strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+ strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+ @ restore regs and return
+ ldmfd sp!, {r0 - r12, pc}
+
+ENTRY(omap1510_cpu_suspend_sz)
+ .word . - omap1510_cpu_suspend
+#endif /* CONFIG_ARCH_OMAP15XX */
+
+#if defined(CONFIG_ARCH_OMAP16XX)
+ .align 3
+ENTRY(omap1610_cpu_suspend)
+
+ @ save registers on stack
+ stmfd sp!, {r0 - r12, lr}
+
+ @ Drain write cache
+ mov r4, #0
+ mcr p15, 0, r0, c7, c10, 4
+ nop
+
+ @ Load base address of Traffic Controller
+ mov r6, #TCMIF_ASM_BASE & 0xff000000
+ orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000
+ orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00
+
+ @ Prepare to put SDRAM into self-refresh manually
+ ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+ orr r9, r7, #SELF_REFRESH_MODE & 0xff000000
+ orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff
+ str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+
+ @ Prepare to put EMIFS to Sleep
+ ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+ orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff
+ str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+
+ @ Load base address of ARM_IDLECT1 and ARM_IDLECT2
+ mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000
+ orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
+ orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
+
+ @ Turn off clock domains
+ @ Do not disable PERCK (0x04)
+ mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff
+ orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00
+ strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+
+ @ Request ARM idle
+ mov r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff
+ orr r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00
+ strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+/*
+ * Let's wait for the next wake up event to wake us up. r0 can't be
+ * used here because r0 holds ARM_IDLECT1
+ */
+ mov r2, #0
+ mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt
+
+ @ Errata (HEL3SU467, section 1.4.4) specifies nop-instructions
+ @ according to this formula:
+ @ 2 + (4*DPLL_MULT)/DPLL_DIV/ARMDIV
+ @ Max DPLL_MULT = 18
+ @ DPLL_DIV = 1
+ @ ARMDIV = 1
+ @ => 74 nop-instructions
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @10
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @20
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @30
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @40
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @50
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @60
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop @70
+ nop
+ nop
+ nop
+ nop @74
+/*
+ * omap1610_cpu_suspend()'s resume point.
+ *
+ * It will just start executing here, so we'll restore stuff from the
+ * stack.
+ */
+ @ Restore the ARM_IDLECT1 and ARM_IDLECT2.
+ strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
+ strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
+
+ @ Restore EMIFF controls
+ str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
+ str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
+
+ @ Restore regs and return
+ ldmfd sp!, {r0 - r12, pc}
+
+ENTRY(omap1610_cpu_suspend_sz)
+ .word . - omap1610_cpu_suspend
+#endif /* CONFIG_ARCH_OMAP16XX */
diff --git a/arch/arm/mach-omap1/soc.h b/arch/arm/mach-omap1/soc.h
new file mode 100644
index 0000000000..5fb57fdd9c
--- /dev/null
+++ b/arch/arm/mach-omap1/soc.h
@@ -0,0 +1,6 @@
+/*
+ * We can move linux/soc/ti/omap1-soc.h here once the drivers are fixed
+ */
+#include "hardware.h"
+#include "irqs.h"
+#include <asm/irq.h>
diff --git a/arch/arm/mach-omap1/sram-init.c b/arch/arm/mach-omap1/sram-init.c
new file mode 100644
index 0000000000..736a72a2b1
--- /dev/null
+++ b/arch/arm/mach-omap1/sram-init.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * OMAP SRAM detection and management
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Written by Tony Lindgren <tony@atomide.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/set_memory.h>
+
+#include <asm/fncpy.h>
+#include <asm/tlb.h>
+#include <asm/cacheflush.h>
+
+#include <asm/mach/map.h>
+
+#include "soc.h"
+#include "sram.h"
+
+#define OMAP1_SRAM_PA 0x20000000
+#define SRAM_BOOTLOADER_SZ 0x80
+#define ROUND_DOWN(value, boundary) ((value) & (~((boundary) - 1)))
+
+static void __iomem *omap_sram_base;
+static unsigned long omap_sram_start;
+static unsigned long omap_sram_skip;
+static unsigned long omap_sram_size;
+static void __iomem *omap_sram_ceil;
+
+/*
+ * Memory allocator for SRAM: calculates the new ceiling address
+ * for pushing a function using the fncpy API.
+ *
+ * Note that fncpy requires the returned address to be aligned
+ * to an 8-byte boundary.
+ */
+static void *omap_sram_push_address(unsigned long size)
+{
+ unsigned long available, new_ceil = (unsigned long)omap_sram_ceil;
+
+ available = omap_sram_ceil - (omap_sram_base + omap_sram_skip);
+
+ if (size > available) {
+ pr_err("Not enough space in SRAM\n");
+ return NULL;
+ }
+
+ new_ceil -= size;
+ new_ceil = ROUND_DOWN(new_ceil, FNCPY_ALIGN);
+ omap_sram_ceil = IOMEM(new_ceil);
+
+ return (void __force *)omap_sram_ceil;
+}
+
+void *omap_sram_push(void *funcp, unsigned long size)
+{
+ void *sram;
+ unsigned long base;
+ int pages;
+ void *dst = NULL;
+
+ sram = omap_sram_push_address(size);
+ if (!sram)
+ return NULL;
+
+ base = (unsigned long)sram & PAGE_MASK;
+ pages = PAGE_ALIGN(size) / PAGE_SIZE;
+
+ set_memory_rw(base, pages);
+
+ dst = fncpy(sram, funcp, size);
+
+ set_memory_rox(base, pages);
+
+ return dst;
+}
+
+/*
+ * The amount of SRAM depends on the core type.
+ * Note that we cannot try to test for SRAM here because writes
+ * to secure SRAM will hang the system. Also the SRAM is not
+ * yet mapped at this point.
+ * Note that we cannot use ioremap for SRAM, as clock init needs SRAM early.
+ */
+static void __init omap_detect_and_map_sram(void)
+{
+ unsigned long base;
+ int pages;
+
+ omap_sram_skip = SRAM_BOOTLOADER_SZ;
+ omap_sram_start = OMAP1_SRAM_PA;
+
+ if (cpu_is_omap15xx())
+ omap_sram_size = 0x30000; /* 192K */
+ else if (cpu_is_omap1610() || cpu_is_omap1611() ||
+ cpu_is_omap1621() || cpu_is_omap1710())
+ omap_sram_size = 0x4000; /* 16K */
+ else {
+ pr_err("Could not detect SRAM size\n");
+ omap_sram_size = 0x4000;
+ }
+
+ omap_sram_start = ROUND_DOWN(omap_sram_start, PAGE_SIZE);
+ omap_sram_base = __arm_ioremap_exec(omap_sram_start, omap_sram_size, 1);
+ if (!omap_sram_base) {
+ pr_err("SRAM: Could not map\n");
+ return;
+ }
+
+ omap_sram_ceil = omap_sram_base + omap_sram_size;
+
+ /*
+ * Looks like we need to preserve some bootloader code at the
+ * beginning of SRAM for jumping to flash for reboot to work...
+ */
+ memset_io(omap_sram_base + omap_sram_skip, 0,
+ omap_sram_size - omap_sram_skip);
+
+ base = (unsigned long)omap_sram_base;
+ pages = PAGE_ALIGN(omap_sram_size) / PAGE_SIZE;
+
+ set_memory_rox(base, pages);
+}
+
+static void (*_omap_sram_reprogram_clock)(u32 dpllctl, u32 ckctl);
+
+void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl)
+{
+ BUG_ON(!_omap_sram_reprogram_clock);
+ _omap_sram_reprogram_clock(dpllctl, ckctl);
+}
+
+int __init omap1_sram_init(void)
+{
+ omap_detect_and_map_sram();
+ _omap_sram_reprogram_clock =
+ omap_sram_push(omap1_sram_reprogram_clock,
+ omap1_sram_reprogram_clock_sz);
+
+ return 0;
+}
diff --git a/arch/arm/mach-omap1/sram.S b/arch/arm/mach-omap1/sram.S
new file mode 100644
index 0000000000..89f4dc1b70
--- /dev/null
+++ b/arch/arm/mach-omap1/sram.S
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * linux/arch/arm/plat-omap/sram-fn.S
+ *
+ * Functions that need to be run in internal SRAM
+ */
+
+#include <linux/linkage.h>
+#include <linux/soc/ti/omap1-io.h>
+
+#include <asm/assembler.h>
+
+#include "hardware.h"
+#include "iomap.h"
+
+ .text
+
+/*
+ * Reprograms ULPD and CKCTL.
+ */
+ .align 3
+ENTRY(omap1_sram_reprogram_clock)
+ stmfd sp!, {r0 - r12, lr} @ save registers on stack
+
+ mov r2, #OMAP1_IO_ADDRESS(DPLL_CTL) & 0xff000000
+ orr r2, r2, #OMAP1_IO_ADDRESS(DPLL_CTL) & 0x00ff0000
+ orr r2, r2, #OMAP1_IO_ADDRESS(DPLL_CTL) & 0x0000ff00
+
+ mov r3, #OMAP1_IO_ADDRESS(ARM_CKCTL) & 0xff000000
+ orr r3, r3, #OMAP1_IO_ADDRESS(ARM_CKCTL) & 0x00ff0000
+ orr r3, r3, #OMAP1_IO_ADDRESS(ARM_CKCTL) & 0x0000ff00
+
+ tst r0, #1 << 4 @ want lock mode?
+ beq newck @ nope
+ bic r0, r0, #1 << 4 @ else clear lock bit
+ strh r0, [r2] @ set dpll into bypass mode
+ orr r0, r0, #1 << 4 @ set lock bit again
+
+newck:
+ strh r1, [r3] @ write new ckctl value
+ strh r0, [r2] @ write new dpll value
+
+ mov r4, #0x0700 @ let the clocks settle
+ orr r4, r4, #0x00ff
+delay: sub r4, r4, #1
+ cmp r4, #0
+ bne delay
+
+lock: ldrh r4, [r2], #0 @ read back dpll value
+ tst r0, #1 << 4 @ want lock mode?
+ beq out @ nope
+ tst r4, #1 << 0 @ dpll rate locked?
+ beq lock @ try again
+
+out:
+ ldmfd sp!, {r0 - r12, pc} @ restore regs and return
+ENTRY(omap1_sram_reprogram_clock_sz)
+ .word . - omap1_sram_reprogram_clock
diff --git a/arch/arm/mach-omap1/sram.h b/arch/arm/mach-omap1/sram.h
new file mode 100644
index 0000000000..f45e6dd6d7
--- /dev/null
+++ b/arch/arm/mach-omap1/sram.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+extern void omap_sram_reprogram_clock(u32 dpllctl, u32 ckctl);
+
+int omap1_sram_init(void);
+void *omap_sram_push(void *funcp, unsigned long size);
+
+/* Do not use these */
+extern void omap1_sram_reprogram_clock(u32 ckctl, u32 dpllctl);
+extern unsigned long omap1_sram_reprogram_clock_sz;
diff --git a/arch/arm/mach-omap1/tc.h b/arch/arm/mach-omap1/tc.h
new file mode 100644
index 0000000000..243454bc06
--- /dev/null
+++ b/arch/arm/mach-omap1/tc.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * OMAP Traffic Controller
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ */
+
+#ifndef __ASM_ARCH_TC_H
+#define __ASM_ARCH_TC_H
+
+#define TCMIF_BASE 0xfffecc00
+#define OMAP_TC_OCPT1_PRIOR (TCMIF_BASE + 0x00)
+#define OMAP_TC_EMIFS_PRIOR (TCMIF_BASE + 0x04)
+#define OMAP_TC_EMIFF_PRIOR (TCMIF_BASE + 0x08)
+#define EMIFS_CONFIG (TCMIF_BASE + 0x0c)
+#define EMIFS_CS0_CONFIG (TCMIF_BASE + 0x10)
+#define EMIFS_CS1_CONFIG (TCMIF_BASE + 0x14)
+#define EMIFS_CS2_CONFIG (TCMIF_BASE + 0x18)
+#define EMIFS_CS3_CONFIG (TCMIF_BASE + 0x1c)
+#define EMIFF_SDRAM_CONFIG (TCMIF_BASE + 0x20)
+#define EMIFF_MRS (TCMIF_BASE + 0x24)
+#define TC_TIMEOUT1 (TCMIF_BASE + 0x28)
+#define TC_TIMEOUT2 (TCMIF_BASE + 0x2c)
+#define TC_TIMEOUT3 (TCMIF_BASE + 0x30)
+#define TC_ENDIANISM (TCMIF_BASE + 0x34)
+#define EMIFF_SDRAM_CONFIG_2 (TCMIF_BASE + 0x3c)
+#define EMIF_CFG_DYNAMIC_WS (TCMIF_BASE + 0x40)
+#define EMIFS_ACS0 (TCMIF_BASE + 0x50)
+#define EMIFS_ACS1 (TCMIF_BASE + 0x54)
+#define EMIFS_ACS2 (TCMIF_BASE + 0x58)
+#define EMIFS_ACS3 (TCMIF_BASE + 0x5c)
+#define OMAP_TC_OCPT2_PRIOR (TCMIF_BASE + 0xd0)
+
+/* external EMIFS chipselect regions */
+#define OMAP_CS0_PHYS 0x00000000
+#define OMAP_CS0_SIZE SZ_64M
+
+#define OMAP_CS1_PHYS 0x04000000
+#define OMAP_CS1_SIZE SZ_64M
+
+#define OMAP_CS1A_PHYS OMAP_CS1_PHYS
+#define OMAP_CS1A_SIZE SZ_32M
+
+#define OMAP_CS1B_PHYS (OMAP_CS1A_PHYS + OMAP_CS1A_SIZE)
+#define OMAP_CS1B_SIZE SZ_32M
+
+#define OMAP_CS2_PHYS 0x08000000
+#define OMAP_CS2_SIZE SZ_64M
+
+#define OMAP_CS2A_PHYS OMAP_CS2_PHYS
+#define OMAP_CS2A_SIZE SZ_32M
+
+#define OMAP_CS2B_PHYS (OMAP_CS2A_PHYS + OMAP_CS2A_SIZE)
+#define OMAP_CS2B_SIZE SZ_32M
+
+#define OMAP_CS3_PHYS 0x0c000000
+#define OMAP_CS3_SIZE SZ_64M
+
+#ifndef __ASSEMBLER__
+
+/* EMIF Slow Interface Configuration Register */
+#define OMAP_EMIFS_CONFIG_FR (1 << 4)
+#define OMAP_EMIFS_CONFIG_PDE (1 << 3)
+#define OMAP_EMIFS_CONFIG_PWD_EN (1 << 2)
+#define OMAP_EMIFS_CONFIG_BM (1 << 1)
+#define OMAP_EMIFS_CONFIG_WP (1 << 0)
+
+#define EMIFS_CCS(n) (EMIFS_CS0_CONFIG + (4 * (n)))
+#define EMIFS_ACS(n) (EMIFS_ACS0 + (4 * (n)))
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* __ASM_ARCH_TC_H */
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
new file mode 100644
index 0000000000..d5e127851d
--- /dev/null
+++ b/arch/arm/mach-omap1/time.c
@@ -0,0 +1,234 @@
+/*
+ * linux/arch/arm/mach-omap1/time.c
+ *
+ * OMAP Timers
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Partial timer rewrite and additional dynamic tick timer support by
+ * Tony Lindgen <tony@atomide.com> and
+ * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ *
+ * MPU timer code based on the older MPU timer code for OMAP
+ * Copyright (C) 2000 RidgeRun, Inc.
+ * Author: Greg Lonnon <glonnon@ridgerun.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/io.h>
+#include <linux/sched_clock.h>
+
+#include <asm/irq.h>
+
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+
+#include "hardware.h"
+#include "mux.h"
+#include "iomap.h"
+#include "common.h"
+#include "clock.h"
+
+#ifdef CONFIG_OMAP_MPU_TIMER
+
+#define OMAP_MPU_TIMER_BASE OMAP_MPU_TIMER1_BASE
+#define OMAP_MPU_TIMER_OFFSET 0x100
+
+typedef struct {
+ u32 cntl; /* CNTL_TIMER, R/W */
+ u32 load_tim; /* LOAD_TIM, W */
+ u32 read_tim; /* READ_TIM, R */
+} omap_mpu_timer_regs_t;
+
+#define omap_mpu_timer_base(n) \
+((omap_mpu_timer_regs_t __iomem *)OMAP1_IO_ADDRESS(OMAP_MPU_TIMER_BASE + \
+ (n)*OMAP_MPU_TIMER_OFFSET))
+
+static inline unsigned long notrace omap_mpu_timer_read(int nr)
+{
+ omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
+ return readl(&timer->read_tim);
+}
+
+static inline void omap_mpu_set_autoreset(int nr)
+{
+ omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
+
+ writel(readl(&timer->cntl) | MPU_TIMER_AR, &timer->cntl);
+}
+
+static inline void omap_mpu_remove_autoreset(int nr)
+{
+ omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
+
+ writel(readl(&timer->cntl) & ~MPU_TIMER_AR, &timer->cntl);
+}
+
+static inline void omap_mpu_timer_start(int nr, unsigned long load_val,
+ int autoreset)
+{
+ omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
+ unsigned int timerflags = MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_ST;
+
+ if (autoreset)
+ timerflags |= MPU_TIMER_AR;
+
+ writel(MPU_TIMER_CLOCK_ENABLE, &timer->cntl);
+ udelay(1);
+ writel(load_val, &timer->load_tim);
+ udelay(1);
+ writel(timerflags, &timer->cntl);
+}
+
+static inline void omap_mpu_timer_stop(int nr)
+{
+ omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
+
+ writel(readl(&timer->cntl) & ~MPU_TIMER_ST, &timer->cntl);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * MPU timer 1 ... count down to zero, interrupt, reload
+ * ---------------------------------------------------------------------------
+ */
+static int omap_mpu_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ omap_mpu_timer_start(0, cycles, 0);
+ return 0;
+}
+
+static int omap_mpu_set_oneshot(struct clock_event_device *evt)
+{
+ omap_mpu_timer_stop(0);
+ omap_mpu_remove_autoreset(0);
+ return 0;
+}
+
+static int omap_mpu_set_periodic(struct clock_event_device *evt)
+{
+ omap_mpu_set_autoreset(0);
+ return 0;
+}
+
+static struct clock_event_device clockevent_mpu_timer1 = {
+ .name = "mpu_timer1",
+ .features = CLOCK_EVT_FEAT_PERIODIC |
+ CLOCK_EVT_FEAT_ONESHOT,
+ .set_next_event = omap_mpu_set_next_event,
+ .set_state_periodic = omap_mpu_set_periodic,
+ .set_state_oneshot = omap_mpu_set_oneshot,
+};
+
+static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = &clockevent_mpu_timer1;
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static __init void omap_init_mpu_timer(unsigned long rate)
+{
+ if (request_irq(INT_TIMER1, omap_mpu_timer1_interrupt,
+ IRQF_TIMER | IRQF_IRQPOLL, "mpu_timer1", NULL))
+ pr_err("Failed to request irq %d (mpu_timer1)\n", INT_TIMER1);
+ omap_mpu_timer_start(0, (rate / HZ) - 1, 1);
+
+ clockevent_mpu_timer1.cpumask = cpumask_of(0);
+ clockevents_config_and_register(&clockevent_mpu_timer1, rate,
+ 1, -1);
+}
+
+
+/*
+ * ---------------------------------------------------------------------------
+ * MPU timer 2 ... free running 32-bit clock source and scheduler clock
+ * ---------------------------------------------------------------------------
+ */
+
+static u64 notrace omap_mpu_read_sched_clock(void)
+{
+ return ~omap_mpu_timer_read(1);
+}
+
+static void __init omap_init_clocksource(unsigned long rate)
+{
+ omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(1);
+ static char err[] __initdata = KERN_ERR
+ "%s: can't register clocksource!\n";
+
+ omap_mpu_timer_start(1, ~0, 1);
+ sched_clock_register(omap_mpu_read_sched_clock, 32, rate);
+
+ if (clocksource_mmio_init(&timer->read_tim, "mpu_timer2", rate,
+ 300, 32, clocksource_mmio_readl_down))
+ printk(err, "mpu_timer2");
+}
+
+static void __init omap_mpu_timer_init(void)
+{
+ struct clk *ck_ref = clk_get(NULL, "ck_ref");
+ unsigned long rate;
+
+ BUG_ON(IS_ERR(ck_ref));
+
+ rate = clk_get_rate(ck_ref);
+ clk_put(ck_ref);
+
+ /* PTV = 0 */
+ rate /= 2;
+
+ omap_init_mpu_timer(rate);
+ omap_init_clocksource(rate);
+}
+
+#else
+static inline void omap_mpu_timer_init(void)
+{
+ pr_err("Bogus timer, should not happen\n");
+}
+#endif /* CONFIG_OMAP_MPU_TIMER */
+
+/*
+ * ---------------------------------------------------------------------------
+ * Timer initialization
+ * ---------------------------------------------------------------------------
+ */
+void __init omap1_timer_init(void)
+{
+ omap1_clk_init();
+ omap1_mux_init();
+
+ if (omap_32k_timer_init() != 0)
+ omap_mpu_timer_init();
+}
diff --git a/arch/arm/mach-omap1/timer.c b/arch/arm/mach-omap1/timer.c
new file mode 100644
index 0000000000..81a912c114
--- /dev/null
+++ b/arch/arm/mach-omap1/timer.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * OMAP1 Dual-Mode Timers - platform device registration
+ *
+ * Contains first level initialization routines which internally
+ * generates timer device information and registers with linux
+ * device model. It also has a low level function to change the timer
+ * input clock source.
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/
+ * Tarun Kanti DebBarma <tarun.kanti@ti.com>
+ * Thara Gopinath <thara@ti.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/dmtimer-omap.h>
+#include <linux/soc/ti/omap1-io.h>
+
+#include <clocksource/timer-ti-dm.h>
+
+#include "soc.h"
+
+#define OMAP1610_GPTIMER1_BASE 0xfffb1400
+#define OMAP1610_GPTIMER2_BASE 0xfffb1c00
+#define OMAP1610_GPTIMER3_BASE 0xfffb2400
+#define OMAP1610_GPTIMER4_BASE 0xfffb2c00
+#define OMAP1610_GPTIMER5_BASE 0xfffb3400
+#define OMAP1610_GPTIMER6_BASE 0xfffb3c00
+#define OMAP1610_GPTIMER7_BASE 0xfffb7400
+#define OMAP1610_GPTIMER8_BASE 0xfffbd400
+
+#define OMAP1_DM_TIMER_COUNT 8
+
+static int omap1_dm_timer_set_src(struct platform_device *pdev,
+ int source)
+{
+ int n = (pdev->id - 1) << 1;
+ u32 l;
+
+ l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
+ l |= source << n;
+ omap_writel(l, MOD_CONF_CTRL_1);
+
+ return 0;
+}
+
+static int __init omap1_dm_timer_init(void)
+{
+ int i;
+ int ret;
+ struct dmtimer_platform_data *pdata;
+ struct platform_device *pdev;
+
+ if (!cpu_is_omap16xx())
+ return 0;
+
+ for (i = 1; i <= OMAP1_DM_TIMER_COUNT; i++) {
+ struct resource res[2];
+ u32 base, irq;
+
+ switch (i) {
+ case 1:
+ base = OMAP1610_GPTIMER1_BASE;
+ irq = INT_1610_GPTIMER1;
+ break;
+ case 2:
+ base = OMAP1610_GPTIMER2_BASE;
+ irq = INT_1610_GPTIMER2;
+ break;
+ case 3:
+ base = OMAP1610_GPTIMER3_BASE;
+ irq = INT_1610_GPTIMER3;
+ break;
+ case 4:
+ base = OMAP1610_GPTIMER4_BASE;
+ irq = INT_1610_GPTIMER4;
+ break;
+ case 5:
+ base = OMAP1610_GPTIMER5_BASE;
+ irq = INT_1610_GPTIMER5;
+ break;
+ case 6:
+ base = OMAP1610_GPTIMER6_BASE;
+ irq = INT_1610_GPTIMER6;
+ break;
+ case 7:
+ base = OMAP1610_GPTIMER7_BASE;
+ irq = INT_1610_GPTIMER7;
+ break;
+ case 8:
+ base = OMAP1610_GPTIMER8_BASE;
+ irq = INT_1610_GPTIMER8;
+ break;
+ default:
+ /*
+ * not supposed to reach here.
+ * this is to remove warning.
+ */
+ return -EINVAL;
+ }
+
+ pdev = platform_device_alloc("omap_timer", i);
+ if (!pdev) {
+ pr_err("%s: Failed to device alloc for dmtimer%d\n",
+ __func__, i);
+ return -ENOMEM;
+ }
+
+ memset(res, 0, 2 * sizeof(struct resource));
+ res[0].start = base;
+ res[0].end = base + 0x46;
+ res[0].flags = IORESOURCE_MEM;
+ res[1].start = irq;
+ res[1].end = irq;
+ res[1].flags = IORESOURCE_IRQ;
+ ret = platform_device_add_resources(pdev, res,
+ ARRAY_SIZE(res));
+ if (ret) {
+ dev_err(&pdev->dev, "%s: Failed to add resources.\n",
+ __func__);
+ goto err_free_pdev;
+ }
+
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ ret = -ENOMEM;
+ goto err_free_pdata;
+ }
+
+ pdata->set_timer_src = omap1_dm_timer_set_src;
+ pdata->timer_capability = OMAP_TIMER_ALWON |
+ OMAP_TIMER_NEEDS_RESET | OMAP_TIMER_HAS_DSP_IRQ;
+
+ ret = platform_device_add_data(pdev, pdata, sizeof(*pdata));
+ if (ret) {
+ dev_err(&pdev->dev, "%s: Failed to add platform data.\n",
+ __func__);
+ goto err_free_pdata;
+ }
+
+ ret = platform_device_add(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: Failed to add platform device.\n",
+ __func__);
+ goto err_free_pdata;
+ }
+
+ dev_dbg(&pdev->dev, " Registered.\n");
+ }
+
+ return 0;
+
+err_free_pdata:
+ kfree(pdata);
+
+err_free_pdev:
+ platform_device_put(pdev);
+
+ return ret;
+}
+arch_initcall(omap1_dm_timer_init);
diff --git a/arch/arm/mach-omap1/timer32k.c b/arch/arm/mach-omap1/timer32k.c
new file mode 100644
index 0000000000..f618a6df29
--- /dev/null
+++ b/arch/arm/mach-omap1/timer32k.c
@@ -0,0 +1,282 @@
+/*
+ * linux/arch/arm/mach-omap1/timer32k.c
+ *
+ * OMAP 32K Timer
+ *
+ * Copyright (C) 2004 - 2005 Nokia Corporation
+ * Partial timer rewrite and additional dynamic tick timer support by
+ * Tony Lindgen <tony@atomide.com> and
+ * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ * OMAP Dual-mode timer framework support by Timo Teras
+ *
+ * MPU timer code based on the older MPU timer code for OMAP
+ * Copyright (C) 2000 RidgeRun, Inc.
+ * Author: Greg Lonnon <glonnon@ridgerun.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/io.h>
+#include <linux/sched_clock.h>
+
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+
+#include "hardware.h"
+#include "common.h"
+
+/*
+ * ---------------------------------------------------------------------------
+ * 32KHz OS timer
+ *
+ * This currently works only on 16xx, as 1510 does not have the continuous
+ * 32KHz synchronous timer. The 32KHz synchronous timer is used to keep track
+ * of time in addition to the 32KHz OS timer. Using only the 32KHz OS timer
+ * on 1510 would be possible, but the timer would not be as accurate as
+ * with the 32KHz synchronized timer.
+ * ---------------------------------------------------------------------------
+ */
+
+/* 16xx specific defines */
+#define OMAP1_32K_TIMER_BASE 0xfffb9000
+#define OMAP1_32KSYNC_TIMER_BASE 0xfffbc400
+#define OMAP1_32K_TIMER_CR 0x08
+#define OMAP1_32K_TIMER_TVR 0x00
+#define OMAP1_32K_TIMER_TCR 0x04
+
+#define OMAP_32K_TICKS_PER_SEC (32768)
+
+/*
+ * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1
+ * so with HZ = 128, TVR = 255.
+ */
+#define OMAP_32K_TIMER_TICK_PERIOD ((OMAP_32K_TICKS_PER_SEC / HZ) - 1)
+
+#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \
+ (((nr_jiffies) * (clock_rate)) / HZ)
+
+static inline void omap_32k_timer_write(int val, int reg)
+{
+ omap_writew(val, OMAP1_32K_TIMER_BASE + reg);
+}
+
+static inline void omap_32k_timer_start(unsigned long load_val)
+{
+ if (!load_val)
+ load_val = 1;
+ omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR);
+ omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR);
+}
+
+static inline void omap_32k_timer_stop(void)
+{
+ omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR);
+}
+
+#define omap_32k_timer_ack_irq()
+
+static int omap_32k_timer_set_next_event(unsigned long delta,
+ struct clock_event_device *dev)
+{
+ omap_32k_timer_start(delta);
+
+ return 0;
+}
+
+static int omap_32k_timer_shutdown(struct clock_event_device *evt)
+{
+ omap_32k_timer_stop();
+ return 0;
+}
+
+static int omap_32k_timer_set_periodic(struct clock_event_device *evt)
+{
+ omap_32k_timer_stop();
+ omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
+ return 0;
+}
+
+static struct clock_event_device clockevent_32k_timer = {
+ .name = "32k-timer",
+ .features = CLOCK_EVT_FEAT_PERIODIC |
+ CLOCK_EVT_FEAT_ONESHOT,
+ .set_next_event = omap_32k_timer_set_next_event,
+ .set_state_shutdown = omap_32k_timer_shutdown,
+ .set_state_periodic = omap_32k_timer_set_periodic,
+ .set_state_oneshot = omap_32k_timer_shutdown,
+ .tick_resume = omap_32k_timer_shutdown,
+};
+
+static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = &clockevent_32k_timer;
+ omap_32k_timer_ack_irq();
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static __init void omap_init_32k_timer(void)
+{
+ if (request_irq(INT_OS_TIMER, omap_32k_timer_interrupt,
+ IRQF_TIMER | IRQF_IRQPOLL, "32KHz timer", NULL))
+ pr_err("Failed to request irq %d(32KHz timer)\n", INT_OS_TIMER);
+
+ clockevent_32k_timer.cpumask = cpumask_of(0);
+ clockevents_config_and_register(&clockevent_32k_timer,
+ OMAP_32K_TICKS_PER_SEC, 1, 0xfffffffe);
+}
+
+/* OMAP2_32KSYNCNT_CR_OFF: offset of 32ksync counter register */
+#define OMAP2_32KSYNCNT_REV_OFF 0x0
+#define OMAP2_32KSYNCNT_REV_SCHEME (0x3 << 30)
+#define OMAP2_32KSYNCNT_CR_OFF_LOW 0x10
+#define OMAP2_32KSYNCNT_CR_OFF_HIGH 0x30
+
+/*
+ * 32KHz clocksource ... always available, on pretty most chips except
+ * OMAP 730 and 1510. Other timers could be used as clocksources, with
+ * higher resolution in free-running counter modes (e.g. 12 MHz xtal),
+ * but systems won't necessarily want to spend resources that way.
+ */
+static void __iomem *sync32k_cnt_reg;
+
+static u64 notrace omap_32k_read_sched_clock(void)
+{
+ return sync32k_cnt_reg ? readl_relaxed(sync32k_cnt_reg) : 0;
+}
+
+static struct timespec64 persistent_ts;
+static cycles_t cycles;
+static unsigned int persistent_mult, persistent_shift;
+
+/**
+ * omap_read_persistent_clock64 - Return time from a persistent clock.
+ * @ts: &struct timespec64 for the returned time
+ *
+ * Reads the time from a source which isn't disabled during PM, the
+ * 32k sync timer. Convert the cycles elapsed since last read into
+ * nsecs and adds to a monotonically increasing timespec64.
+ */
+static void omap_read_persistent_clock64(struct timespec64 *ts)
+{
+ unsigned long long nsecs;
+ cycles_t last_cycles;
+
+ last_cycles = cycles;
+ cycles = sync32k_cnt_reg ? readl_relaxed(sync32k_cnt_reg) : 0;
+
+ nsecs = clocksource_cyc2ns(cycles - last_cycles,
+ persistent_mult, persistent_shift);
+
+ timespec64_add_ns(&persistent_ts, nsecs);
+
+ *ts = persistent_ts;
+}
+
+/**
+ * omap_init_clocksource_32k - setup and register counter 32k as a
+ * kernel clocksource
+ * @vbase: base addr of counter_32k module
+ *
+ * Returns: %0 upon success or negative error code upon failure.
+ *
+ */
+static int __init omap_init_clocksource_32k(void __iomem *vbase)
+{
+ int ret;
+
+ /*
+ * 32k sync Counter IP register offsets vary between the
+ * highlander version and the legacy ones.
+ * The 'SCHEME' bits(30-31) of the revision register is used
+ * to identify the version.
+ */
+ if (readl_relaxed(vbase + OMAP2_32KSYNCNT_REV_OFF) &
+ OMAP2_32KSYNCNT_REV_SCHEME)
+ sync32k_cnt_reg = vbase + OMAP2_32KSYNCNT_CR_OFF_HIGH;
+ else
+ sync32k_cnt_reg = vbase + OMAP2_32KSYNCNT_CR_OFF_LOW;
+
+ /*
+ * 120000 rough estimate from the calculations in
+ * __clocksource_update_freq_scale.
+ */
+ clocks_calc_mult_shift(&persistent_mult, &persistent_shift,
+ 32768, NSEC_PER_SEC, 120000);
+
+ ret = clocksource_mmio_init(sync32k_cnt_reg, "32k_counter", 32768,
+ 250, 32, clocksource_mmio_readl_up);
+ if (ret) {
+ pr_err("32k_counter: can't register clocksource\n");
+ return ret;
+ }
+
+ sched_clock_register(omap_32k_read_sched_clock, 32, 32768);
+ register_persistent_clock(omap_read_persistent_clock64);
+ pr_info("OMAP clocksource: 32k_counter at 32768 Hz\n");
+
+ return 0;
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * Timer initialization
+ * ---------------------------------------------------------------------------
+ */
+int __init omap_32k_timer_init(void)
+{
+ int ret = -ENODEV;
+
+ if (cpu_is_omap16xx()) {
+ void __iomem *base;
+ struct clk *sync32k_ick;
+
+ base = ioremap(OMAP1_32KSYNC_TIMER_BASE, SZ_1K);
+ if (!base) {
+ pr_err("32k_counter: failed to map base addr\n");
+ return -ENODEV;
+ }
+
+ sync32k_ick = clk_get(NULL, "omap_32ksync_ick");
+ if (!IS_ERR(sync32k_ick))
+ clk_prepare_enable(sync32k_ick);
+
+ ret = omap_init_clocksource_32k(base);
+ }
+
+ if (!ret)
+ omap_init_32k_timer();
+
+ return ret;
+}
diff --git a/arch/arm/mach-omap1/usb.c b/arch/arm/mach-omap1/usb.c
new file mode 100644
index 0000000000..08d42abc4a
--- /dev/null
+++ b/arch/arm/mach-omap1/usb.c
@@ -0,0 +1,687 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Platform level USB initialization for FS USB OTG controller on omap1
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-map-ops.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/soc/ti/omap1-io.h>
+
+#include <asm/irq.h>
+
+#include "hardware.h"
+#include "mux.h"
+#include "usb.h"
+#include "common.h"
+
+/* These routines should handle the standard chip-specific modes
+ * for usb0/1/2 ports, covering basic mux and transceiver setup.
+ *
+ * Some board-*.c files will need to set up additional mux options,
+ * like for suspend handling, vbus sensing, GPIOs, and the D+ pullup.
+ */
+
+/* TESTED ON:
+ * - 1611B H2 (with usb1 mini-AB) using standard Mini-B or OTG cables
+ * - 5912 OSK OHCI (with usb0 standard-A), standard A-to-B cables
+ * - 5912 OSK UDC, with *nonstandard* A-to-A cable
+ * - 1510 Innovator UDC with bundled usb0 cable
+ * - 1510 Innovator OHCI with bundled usb1/usb2 cable
+ * - 1510 Innovator OHCI with custom usb0 cable, feeding 5V VBUS
+ * - 1710 custom development board using alternate pin group
+ * - 1710 H3 (with usb1 mini-AB) using standard Mini-B or OTG cables
+ */
+
+#define INT_USB_IRQ_GEN IH2_BASE + 20
+#define INT_USB_IRQ_NISO IH2_BASE + 30
+#define INT_USB_IRQ_ISO IH2_BASE + 29
+#define INT_USB_IRQ_HGEN INT_USB_HHC_1
+#define INT_USB_IRQ_OTG IH2_BASE + 8
+
+#ifdef CONFIG_ARCH_OMAP_OTG
+
+static void __init
+omap_otg_init(struct omap_usb_config *config)
+{
+ u32 syscon;
+ int alt_pingroup = 0;
+ u16 w;
+
+ /* NOTE: no bus or clock setup (yet?) */
+
+ syscon = omap_readl(OTG_SYSCON_1) & 0xffff;
+ if (!(syscon & OTG_RESET_DONE))
+ pr_debug("USB resets not complete?\n");
+
+ //omap_writew(0, OTG_IRQ_EN);
+
+ /* pin muxing and transceiver pinouts */
+ if (config->pins[0] > 2) /* alt pingroup 2 */
+ alt_pingroup = 1;
+ syscon |= config->usb0_init(config->pins[0], is_usb0_device(config));
+ syscon |= config->usb1_init(config->pins[1]);
+ syscon |= config->usb2_init(config->pins[2], alt_pingroup);
+ pr_debug("OTG_SYSCON_1 = %08x\n", omap_readl(OTG_SYSCON_1));
+ omap_writel(syscon, OTG_SYSCON_1);
+
+ syscon = config->hmc_mode;
+ syscon |= USBX_SYNCHRO | (4 << 16) /* B_ASE0_BRST */;
+#ifdef CONFIG_USB_OTG
+ if (config->otg)
+ syscon |= OTG_EN;
+#endif
+ pr_debug("USB_TRANSCEIVER_CTRL = %03x\n",
+ omap_readl(USB_TRANSCEIVER_CTRL));
+ pr_debug("OTG_SYSCON_2 = %08x\n", omap_readl(OTG_SYSCON_2));
+ omap_writel(syscon, OTG_SYSCON_2);
+
+ printk("USB: hmc %d", config->hmc_mode);
+ if (!alt_pingroup)
+ pr_cont(", usb2 alt %d wires", config->pins[2]);
+ else if (config->pins[0])
+ pr_cont(", usb0 %d wires%s", config->pins[0],
+ is_usb0_device(config) ? " (dev)" : "");
+ if (config->pins[1])
+ pr_cont(", usb1 %d wires", config->pins[1]);
+ if (!alt_pingroup && config->pins[2])
+ pr_cont(", usb2 %d wires", config->pins[2]);
+ if (config->otg)
+ pr_cont(", Mini-AB on usb%d", config->otg - 1);
+ pr_cont("\n");
+
+ /* leave USB clocks/controllers off until needed */
+ w = omap_readw(ULPD_SOFT_REQ);
+ w &= ~SOFT_USB_CLK_REQ;
+ omap_writew(w, ULPD_SOFT_REQ);
+
+ w = omap_readw(ULPD_CLOCK_CTRL);
+ w &= ~USB_MCLK_EN;
+ w |= DIS_USB_PVCI_CLK;
+ omap_writew(w, ULPD_CLOCK_CTRL);
+
+ syscon = omap_readl(OTG_SYSCON_1);
+ syscon |= HST_IDLE_EN|DEV_IDLE_EN|OTG_IDLE_EN;
+
+#if IS_ENABLED(CONFIG_USB_OMAP)
+ if (config->otg || config->register_dev) {
+ struct platform_device *udc_device = config->udc_device;
+ int status;
+
+ syscon &= ~DEV_IDLE_EN;
+ udc_device->dev.platform_data = config;
+ status = platform_device_register(udc_device);
+ if (status)
+ pr_debug("can't register UDC device, %d\n", status);
+ }
+#endif
+
+#if IS_ENABLED(CONFIG_USB_OHCI_HCD)
+ if (config->otg || config->register_host) {
+ struct platform_device *ohci_device = config->ohci_device;
+ int status;
+
+ syscon &= ~HST_IDLE_EN;
+ ohci_device->dev.platform_data = config;
+ status = platform_device_register(ohci_device);
+ if (status)
+ pr_debug("can't register OHCI device, %d\n", status);
+ }
+#endif
+
+#ifdef CONFIG_USB_OTG
+ if (config->otg) {
+ struct platform_device *otg_device = config->otg_device;
+ int status;
+
+ syscon &= ~OTG_IDLE_EN;
+ otg_device->dev.platform_data = config;
+ status = platform_device_register(otg_device);
+ if (status)
+ pr_debug("can't register OTG device, %d\n", status);
+ }
+#endif
+ pr_debug("OTG_SYSCON_1 = %08x\n", omap_readl(OTG_SYSCON_1));
+ omap_writel(syscon, OTG_SYSCON_1);
+}
+
+#else
+static void omap_otg_init(struct omap_usb_config *config) {}
+#endif
+
+#if IS_ENABLED(CONFIG_USB_OMAP)
+
+static struct resource udc_resources[] = {
+ /* order is significant! */
+ { /* registers */
+ .start = UDC_BASE,
+ .end = UDC_BASE + 0xff,
+ .flags = IORESOURCE_MEM,
+ }, { /* general IRQ */
+ .start = INT_USB_IRQ_GEN,
+ .flags = IORESOURCE_IRQ,
+ }, { /* PIO IRQ */
+ .start = INT_USB_IRQ_NISO,
+ .flags = IORESOURCE_IRQ,
+ }, { /* SOF IRQ */
+ .start = INT_USB_IRQ_ISO,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 udc_dmamask = ~(u32)0;
+
+static struct platform_device udc_device = {
+ .name = "omap_udc",
+ .id = -1,
+ .dev = {
+ .dma_mask = &udc_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(udc_resources),
+ .resource = udc_resources,
+};
+
+static inline void udc_device_init(struct omap_usb_config *pdata)
+{
+ pdata->udc_device = &udc_device;
+}
+
+#else
+
+static inline void udc_device_init(struct omap_usb_config *pdata)
+{
+}
+
+#endif
+
+/* The dmamask must be set for OHCI to work */
+static u64 ohci_dmamask = ~(u32)0;
+
+static struct resource ohci_resources[] = {
+ {
+ .start = OMAP_OHCI_BASE,
+ .end = OMAP_OHCI_BASE + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_USB_IRQ_HGEN,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device ohci_device = {
+ .name = "ohci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &ohci_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(ohci_resources),
+ .resource = ohci_resources,
+};
+
+static inline void ohci_device_init(struct omap_usb_config *pdata)
+{
+ if (!IS_ENABLED(CONFIG_USB_OHCI_HCD))
+ return;
+
+ pdata->ohci_device = &ohci_device;
+ pdata->ocpi_enable = &ocpi_enable;
+}
+
+#if defined(CONFIG_USB_OTG) && defined(CONFIG_ARCH_OMAP_OTG)
+
+static struct resource otg_resources[] = {
+ /* order is significant! */
+ {
+ .start = OTG_BASE,
+ .end = OTG_BASE + 0xff,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = INT_USB_IRQ_OTG,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device otg_device = {
+ .name = "omap_otg",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(otg_resources),
+ .resource = otg_resources,
+};
+
+static inline void otg_device_init(struct omap_usb_config *pdata)
+{
+ pdata->otg_device = &otg_device;
+}
+
+#else
+
+static inline void otg_device_init(struct omap_usb_config *pdata)
+{
+}
+
+#endif
+
+static u32 __init omap1_usb0_init(unsigned nwires, unsigned is_device)
+{
+ u32 syscon1 = 0;
+
+ if (nwires == 0) {
+ if (!cpu_is_omap15xx()) {
+ u32 l;
+
+ /* pulldown D+/D- */
+ l = omap_readl(USB_TRANSCEIVER_CTRL);
+ l &= ~(3 << 1);
+ omap_writel(l, USB_TRANSCEIVER_CTRL);
+ }
+ return 0;
+ }
+
+ if (is_device) {
+ omap_cfg_reg(W4_USB_PUEN);
+ }
+
+ if (nwires == 2) {
+ u32 l;
+
+ // omap_cfg_reg(P9_USB_DP);
+ // omap_cfg_reg(R8_USB_DM);
+
+ if (cpu_is_omap15xx()) {
+ /* This works on 1510-Innovator */
+ return 0;
+ }
+
+ /* NOTES:
+ * - peripheral should configure VBUS detection!
+ * - only peripherals may use the internal D+/D- pulldowns
+ * - OTG support on this port not yet written
+ */
+
+ l = omap_readl(USB_TRANSCEIVER_CTRL);
+ l &= ~(7 << 4);
+ if (!is_device)
+ l |= (3 << 1);
+ omap_writel(l, USB_TRANSCEIVER_CTRL);
+
+ return 3 << 16;
+ }
+
+ /* alternate pin config, external transceiver */
+ if (cpu_is_omap15xx()) {
+ printk(KERN_ERR "no usb0 alt pin config on 15xx\n");
+ return 0;
+ }
+
+ omap_cfg_reg(V6_USB0_TXD);
+ omap_cfg_reg(W9_USB0_TXEN);
+ omap_cfg_reg(W5_USB0_SE0);
+ if (nwires != 3)
+ omap_cfg_reg(Y5_USB0_RCV);
+
+ /* NOTE: SPEED and SUSP aren't configured here. OTG hosts
+ * may be able to use I2C requests to set those bits along
+ * with VBUS switching and overcurrent detection.
+ */
+
+ if (nwires != 6) {
+ u32 l;
+
+ l = omap_readl(USB_TRANSCEIVER_CTRL);
+ l &= ~CONF_USB2_UNI_R;
+ omap_writel(l, USB_TRANSCEIVER_CTRL);
+ }
+
+ switch (nwires) {
+ case 3:
+ syscon1 = 2;
+ break;
+ case 4:
+ syscon1 = 1;
+ break;
+ case 6:
+ syscon1 = 3;
+ {
+ u32 l;
+
+ omap_cfg_reg(AA9_USB0_VP);
+ omap_cfg_reg(R9_USB0_VM);
+ l = omap_readl(USB_TRANSCEIVER_CTRL);
+ l |= CONF_USB2_UNI_R;
+ omap_writel(l, USB_TRANSCEIVER_CTRL);
+ }
+ break;
+ default:
+ printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
+ 0, nwires);
+ }
+
+ return syscon1 << 16;
+}
+
+static u32 __init omap1_usb1_init(unsigned nwires)
+{
+ u32 syscon1 = 0;
+
+ if (!cpu_is_omap15xx() && nwires != 6) {
+ u32 l;
+
+ l = omap_readl(USB_TRANSCEIVER_CTRL);
+ l &= ~CONF_USB1_UNI_R;
+ omap_writel(l, USB_TRANSCEIVER_CTRL);
+ }
+ if (nwires == 0)
+ return 0;
+
+ /* external transceiver */
+ omap_cfg_reg(USB1_TXD);
+ omap_cfg_reg(USB1_TXEN);
+ if (nwires != 3)
+ omap_cfg_reg(USB1_RCV);
+
+ if (cpu_is_omap15xx()) {
+ omap_cfg_reg(USB1_SEO);
+ omap_cfg_reg(USB1_SPEED);
+ // SUSP
+ } else if (cpu_is_omap1610() || cpu_is_omap5912()) {
+ omap_cfg_reg(W13_1610_USB1_SE0);
+ omap_cfg_reg(R13_1610_USB1_SPEED);
+ // SUSP
+ } else if (cpu_is_omap1710()) {
+ omap_cfg_reg(R13_1710_USB1_SE0);
+ // SUSP
+ } else {
+ pr_debug("usb%d cpu unrecognized\n", 1);
+ return 0;
+ }
+
+ switch (nwires) {
+ case 2:
+ goto bad;
+ case 3:
+ syscon1 = 2;
+ break;
+ case 4:
+ syscon1 = 1;
+ break;
+ case 6:
+ syscon1 = 3;
+ omap_cfg_reg(USB1_VP);
+ omap_cfg_reg(USB1_VM);
+ if (!cpu_is_omap15xx()) {
+ u32 l;
+
+ l = omap_readl(USB_TRANSCEIVER_CTRL);
+ l |= CONF_USB1_UNI_R;
+ omap_writel(l, USB_TRANSCEIVER_CTRL);
+ }
+ break;
+ default:
+bad:
+ printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
+ 1, nwires);
+ }
+
+ return syscon1 << 20;
+}
+
+static u32 __init omap1_usb2_init(unsigned nwires, unsigned alt_pingroup)
+{
+ u32 syscon1 = 0;
+
+ /* NOTE omap1 erratum: must leave USB2_UNI_R set if usb0 in use */
+ if (alt_pingroup || nwires == 0)
+ return 0;
+
+ if (!cpu_is_omap15xx() && nwires != 6) {
+ u32 l;
+
+ l = omap_readl(USB_TRANSCEIVER_CTRL);
+ l &= ~CONF_USB2_UNI_R;
+ omap_writel(l, USB_TRANSCEIVER_CTRL);
+ }
+
+ /* external transceiver */
+ if (cpu_is_omap15xx()) {
+ omap_cfg_reg(USB2_TXD);
+ omap_cfg_reg(USB2_TXEN);
+ omap_cfg_reg(USB2_SEO);
+ if (nwires != 3)
+ omap_cfg_reg(USB2_RCV);
+ /* there is no USB2_SPEED */
+ } else if (cpu_is_omap16xx()) {
+ omap_cfg_reg(V6_USB2_TXD);
+ omap_cfg_reg(W9_USB2_TXEN);
+ omap_cfg_reg(W5_USB2_SE0);
+ if (nwires != 3)
+ omap_cfg_reg(Y5_USB2_RCV);
+ // FIXME omap_cfg_reg(USB2_SPEED);
+ } else {
+ pr_debug("usb%d cpu unrecognized\n", 1);
+ return 0;
+ }
+
+ // omap_cfg_reg(USB2_SUSP);
+
+ switch (nwires) {
+ case 2:
+ goto bad;
+ case 3:
+ syscon1 = 2;
+ break;
+ case 4:
+ syscon1 = 1;
+ break;
+ case 5:
+ goto bad;
+ case 6:
+ syscon1 = 3;
+ if (cpu_is_omap15xx()) {
+ omap_cfg_reg(USB2_VP);
+ omap_cfg_reg(USB2_VM);
+ } else {
+ u32 l;
+
+ omap_cfg_reg(AA9_USB2_VP);
+ omap_cfg_reg(R9_USB2_VM);
+ l = omap_readl(USB_TRANSCEIVER_CTRL);
+ l |= CONF_USB2_UNI_R;
+ omap_writel(l, USB_TRANSCEIVER_CTRL);
+ }
+ break;
+ default:
+bad:
+ printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
+ 2, nwires);
+ }
+
+ return syscon1 << 24;
+}
+
+#ifdef CONFIG_ARCH_OMAP15XX
+/* OMAP-1510 OHCI has its own MMU for DMA */
+#define OMAP1510_LB_MEMSIZE 32 /* Should be same as SDRAM size */
+#define OMAP1510_LB_CLOCK_DIV 0xfffec10c
+#define OMAP1510_LB_MMU_CTL 0xfffec208
+#define OMAP1510_LB_MMU_LCK 0xfffec224
+#define OMAP1510_LB_MMU_LD_TLB 0xfffec228
+#define OMAP1510_LB_MMU_CAM_H 0xfffec22c
+#define OMAP1510_LB_MMU_CAM_L 0xfffec230
+#define OMAP1510_LB_MMU_RAM_H 0xfffec234
+#define OMAP1510_LB_MMU_RAM_L 0xfffec238
+
+/*
+ * Bus address is physical address, except for OMAP-1510 Local Bus.
+ * OMAP-1510 bus address is translated into a Local Bus address if the
+ * OMAP bus type is lbus.
+ */
+#define OMAP1510_LB_OFFSET UL(0x30000000)
+
+/*
+ * OMAP-1510 specific Local Bus clock on/off
+ */
+static int omap_1510_local_bus_power(int on)
+{
+ if (on) {
+ omap_writel((1 << 1) | (1 << 0), OMAP1510_LB_MMU_CTL);
+ udelay(200);
+ } else {
+ omap_writel(0, OMAP1510_LB_MMU_CTL);
+ }
+
+ return 0;
+}
+
+/*
+ * OMAP-1510 specific Local Bus initialization
+ * NOTE: This assumes 32MB memory size in OMAP1510LB_MEMSIZE.
+ * See also arch/mach-omap/memory.h for __virt_to_dma() and
+ * __dma_to_virt() which need to match with the physical
+ * Local Bus address below.
+ */
+static int omap_1510_local_bus_init(void)
+{
+ unsigned int tlb;
+ unsigned long lbaddr, physaddr;
+
+ omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4,
+ OMAP1510_LB_CLOCK_DIV);
+
+ /* Configure the Local Bus MMU table */
+ for (tlb = 0; tlb < OMAP1510_LB_MEMSIZE; tlb++) {
+ lbaddr = tlb * 0x00100000 + OMAP1510_LB_OFFSET;
+ physaddr = tlb * 0x00100000 + PHYS_OFFSET;
+ omap_writel((lbaddr & 0x0fffffff) >> 22, OMAP1510_LB_MMU_CAM_H);
+ omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc,
+ OMAP1510_LB_MMU_CAM_L);
+ omap_writel(physaddr >> 16, OMAP1510_LB_MMU_RAM_H);
+ omap_writel((physaddr & 0x0000fc00) | 0x300, OMAP1510_LB_MMU_RAM_L);
+ omap_writel(tlb << 4, OMAP1510_LB_MMU_LCK);
+ omap_writel(0x1, OMAP1510_LB_MMU_LD_TLB);
+ }
+
+ /* Enable the walking table */
+ omap_writel(omap_readl(OMAP1510_LB_MMU_CTL) | (1 << 3), OMAP1510_LB_MMU_CTL);
+ udelay(200);
+
+ return 0;
+}
+
+static void omap_1510_local_bus_reset(void)
+{
+ omap_1510_local_bus_power(1);
+ omap_1510_local_bus_init();
+}
+
+/* ULPD_DPLL_CTRL */
+#define DPLL_IOB (1 << 13)
+#define DPLL_PLL_ENABLE (1 << 4)
+#define DPLL_LOCK (1 << 0)
+
+/* ULPD_APLL_CTRL */
+#define APLL_NDPLL_SWITCH (1 << 0)
+
+static void __init omap_1510_usb_init(struct omap_usb_config *config)
+{
+ unsigned int val;
+ u16 w;
+
+ config->usb0_init(config->pins[0], is_usb0_device(config));
+ config->usb1_init(config->pins[1]);
+ config->usb2_init(config->pins[2], 0);
+
+ val = omap_readl(MOD_CONF_CTRL_0) & ~(0x3f << 1);
+ val |= (config->hmc_mode << 1);
+ omap_writel(val, MOD_CONF_CTRL_0);
+
+ printk("USB: hmc %d", config->hmc_mode);
+ if (config->pins[0])
+ pr_cont(", usb0 %d wires%s", config->pins[0],
+ is_usb0_device(config) ? " (dev)" : "");
+ if (config->pins[1])
+ pr_cont(", usb1 %d wires", config->pins[1]);
+ if (config->pins[2])
+ pr_cont(", usb2 %d wires", config->pins[2]);
+ pr_cont("\n");
+
+ /* use DPLL for 48 MHz function clock */
+ pr_debug("APLL %04x DPLL %04x REQ %04x\n", omap_readw(ULPD_APLL_CTRL),
+ omap_readw(ULPD_DPLL_CTRL), omap_readw(ULPD_SOFT_REQ));
+
+ w = omap_readw(ULPD_APLL_CTRL);
+ w &= ~APLL_NDPLL_SWITCH;
+ omap_writew(w, ULPD_APLL_CTRL);
+
+ w = omap_readw(ULPD_DPLL_CTRL);
+ w |= DPLL_IOB | DPLL_PLL_ENABLE;
+ omap_writew(w, ULPD_DPLL_CTRL);
+
+ w = omap_readw(ULPD_SOFT_REQ);
+ w |= SOFT_UDC_REQ | SOFT_DPLL_REQ;
+ omap_writew(w, ULPD_SOFT_REQ);
+
+ while (!(omap_readw(ULPD_DPLL_CTRL) & DPLL_LOCK))
+ cpu_relax();
+
+#if IS_ENABLED(CONFIG_USB_OMAP)
+ if (config->register_dev) {
+ int status;
+
+ udc_device.dev.platform_data = config;
+ status = platform_device_register(&udc_device);
+ if (status)
+ pr_debug("can't register UDC device, %d\n", status);
+ /* udc driver gates 48MHz by D+ pullup */
+ }
+#endif
+
+ if (IS_ENABLED(CONFIG_USB_OHCI_HCD) && config->register_host) {
+ int status;
+
+ ohci_device.dev.platform_data = config;
+ dma_direct_set_offset(&ohci_device.dev, PHYS_OFFSET,
+ OMAP1510_LB_OFFSET, (u64)-1);
+ status = platform_device_register(&ohci_device);
+ if (status)
+ pr_debug("can't register OHCI device, %d\n", status);
+ /* hcd explicitly gates 48MHz */
+
+ config->lb_reset = omap_1510_local_bus_reset;
+ }
+}
+
+#else
+static inline void omap_1510_usb_init(struct omap_usb_config *config) {}
+#endif
+
+void __init omap1_usb_init(struct omap_usb_config *_pdata)
+{
+ struct omap_usb_config *pdata;
+
+ pdata = kmemdup(_pdata, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return;
+
+ pdata->usb0_init = omap1_usb0_init;
+ pdata->usb1_init = omap1_usb1_init;
+ pdata->usb2_init = omap1_usb2_init;
+ udc_device_init(pdata);
+ ohci_device_init(pdata);
+ otg_device_init(pdata);
+
+ if (cpu_is_omap16xx())
+ omap_otg_init(pdata);
+ else if (cpu_is_omap15xx())
+ omap_1510_usb_init(pdata);
+ else
+ printk(KERN_ERR "USB: No init for your chip yet\n");
+}
diff --git a/arch/arm/mach-omap1/usb.h b/arch/arm/mach-omap1/usb.h
new file mode 100644
index 0000000000..08c9344c46
--- /dev/null
+++ b/arch/arm/mach-omap1/usb.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * fixme correct answer depends on hmc_mode,
+ * as does (on omap1) any nonzero value for config->otg port number
+ */
+#include <linux/platform_data/usb-omap1.h>
+#include <linux/soc/ti/omap1-usb.h>
+
+#if IS_ENABLED(CONFIG_USB_OMAP)
+#define is_usb0_device(config) 1
+#else
+#define is_usb0_device(config) 0
+#endif
+
+#if IS_ENABLED(CONFIG_USB_SUPPORT)
+void omap1_usb_init(struct omap_usb_config *pdata);
+#else
+static inline void omap1_usb_init(struct omap_usb_config *pdata)
+{
+}
+#endif
+
+#define OMAP1_OHCI_BASE 0xfffba000
+#define OMAP2_OHCI_BASE 0x4805e000
+#define OMAP_OHCI_BASE OMAP1_OHCI_BASE