OMAP2+: UART: runtime conversion + cleanup.
Subsystems (7)
cover OMAP2+: UART: runtime conversion + cleanup.
Converting uart driver to adapt to pm runtime api's.
Changes involves:
================
1.) Cleaning up certain uart calls from sram_idle func but still
retaining the prepare_idle/resume_idle func calls because as of today uart module level wakeup doesn't seem to work.
We have informed the hardware folks about this and discussion is in progress. So until we have a workaround for this we have to depend on prepare/resume calls to cut uart clock and wakeup based on io-daisy chain mechanism using uart_rx padconf.
2.) Removed all types of uart clock handling code from serial.c
file and now onwards serial.c file is used only for device registration and to probe early uart and pass some uart board data which can be passed as pdata to driver. Also cleaned up direct padconf usage.
3.) Using hwmod_mux api enable wakeup capability for uart pad during
hwmod_idle state i.e., when uart clocks are disabled we can enable io-pad wakeup capability for uart if mux_data is available for given uart. Also during during resume from idle call to uart we need to enable clocks back conditionally and this can be done only when io-pad wakeup event bit is set for uart_rx pad. So we need a hwmod api which can probe the uart pad and let us know whether a uart wakeup happened. So omap_hmwod_pad_wakeup_status api is added to meet this requirement.
3.) Adapted omap-serial driver to use runtime api's.
4.) Modify serial_init calls to accept certain dma based uart parameters 5.) Minor cleanups and rename uart_rx_dma api.
Patch series is based on LO Kernel omap_for_linus branch.
Commit-id: 7cab8713b1ed0dab08ad6458f92a40b7ff4be619
Dependency patches needed to test system wide suspend on omap_for_linus branch.
https://patchwork.kernel.org/patch/550551/
https://patchwork.kernel.org/patch/513481/
https://patchwork.kernel.org/patch/501211/
Testing updates:
----------------
3430SDP, ZOOM2: retention, off_mode, system_wide suspend is tested. OMAP3630 - Zoom3: pm-retention checked, off mode for per domain checked.
[uart3/uart4 in per domain on omap3630].
OMAP4430[Blaze]: Boot tested.
OMAP2420/2430SDP: Boot tested
Govindraj.R (5):
OMAP2+ : hwmod_data: update uart hwmod data. OMAP2+: mux: Enable wakeup for wakeup enable requested pads. OMAP2+: UART: Remove certain uart calls from sram_idle. OMAP2+: UART: Remove uart clock handling code serial.c
Serial: OMAP: add runtime pm support for omap-serial driver
Jon Hunter (2):
OMAP: Serial: Allow UART parameters to be configured from board file
Serial: OMAP2+: Make the RX_TIMEOUT for DMA configurable for each
UART
arch/arm/mach-omap2/board-2430sdp.c | 3 +- arch/arm/mach-omap2/board-3430sdp.c | 4 +- arch/arm/mach-omap2/board-4430sdp.c | 3 +- arch/arm/mach-omap2/board-am3517evm.c | 3 +- arch/arm/mach-omap2/board-apollon.c | 3 +- arch/arm/mach-omap2/board-cm-t35.c | 3 +- arch/arm/mach-omap2/board-cm-t3517.c | 3 +- arch/arm/mach-omap2/board-devkit8000.c | 3 +- arch/arm/mach-omap2/board-generic.c | 3 +- arch/arm/mach-omap2/board-h4.c | 3 +- arch/arm/mach-omap2/board-igep0020.c | 3 +- arch/arm/mach-omap2/board-igep0030.c | 3 +- arch/arm/mach-omap2/board-ldp.c | 3 +- arch/arm/mach-omap2/board-n8x0.c | 9 +- arch/arm/mach-omap2/board-omap3beagle.c | 3 +- arch/arm/mach-omap2/board-omap3evm.c | 3 +- arch/arm/mach-omap2/board-omap3logic.c | 3 +- arch/arm/mach-omap2/board-omap3pandora.c | 3 +- arch/arm/mach-omap2/board-omap3stalker.c | 3 +- arch/arm/mach-omap2/board-omap3touchbook.c | 3 +- arch/arm/mach-omap2/board-omap4panda.c | 3 +- arch/arm/mach-omap2/board-overo.c | 3 +- arch/arm/mach-omap2/board-rm680.c | 3 +- arch/arm/mach-omap2/board-rx51.c | 3 +- arch/arm/mach-omap2/board-ti8168evm.c | 2 +- arch/arm/mach-omap2/board-zoom-peripherals.c | 3 +- arch/arm/mach-omap2/mux.c | 23 + arch/arm/mach-omap2/mux.h | 13 + arch/arm/mach-omap2/omap_hwmod.c | 13 + arch/arm/mach-omap2/omap_hwmod_2420_data.c | 3 + arch/arm/mach-omap2/omap_hwmod_2430_data.c | 3 + arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 4 + arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 4 + arch/arm/mach-omap2/pm24xx.c | 11 - arch/arm/mach-omap2/pm34xx.c | 16 - arch/arm/mach-omap2/serial.c | 845 +++++-------------------- arch/arm/plat-omap/include/plat/omap-serial.h | 37 +- arch/arm/plat-omap/include/plat/omap_hwmod.h | 1 + arch/arm/plat-omap/include/plat/serial.h | 10 +- drivers/tty/serial/omap-serial.c | 323 +++++++++- 40 files changed, 601 insertions(+), 789 deletions(-)
PATCH 1/7 OMAP2+ : hwmod_data: update uart hwmod data.
Add HWMOD_SWSUP_SIDLE flag to uart*_hwmod data. With addition of this flag the hwmod framework will take care of updating sysc reg with no_idle mode while enabling clocks and to force_idle mode while disabling clocks.
--- arch/arm/mach-omap2/omap_hwmod_2420_data.c | 3 +++ arch/arm/mach-omap2/omap_hwmod_2430_data.c | 3 +++ arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 4 ++++ arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 4 ++++ 4 files changed, 14 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/omap_hwmod_2420_data.c +3 -0
@@ -434,6 +434,7 @@ static struct omap_hwmod_ocp_if *omap2420_uart1_slaves[] = {static struct omap_hwmod omap2420_uart1_hwmod = { .name ="uart1" , + .flags =HWMOD_SWSUP_SIDLE , .mpu_irqs = uart1_mpu_irqs, .mpu_irqs_cnt =ARRAY_SIZE (uart1_mpu_irqs), .sdma_reqs = uart1_sdma_reqs,
@@ -471,6 +472,7 @@ static struct omap_hwmod_ocp_if *omap2420_uart2_slaves[] = {static struct omap_hwmod omap2420_uart2_hwmod = { .name ="uart2" , + .flags =HWMOD_SWSUP_SIDLE , .mpu_irqs = uart2_mpu_irqs, .mpu_irqs_cnt =ARRAY_SIZE (uart2_mpu_irqs), .sdma_reqs = uart2_sdma_reqs,
@@ -508,6 +510,7 @@ static struct omap_hwmod_ocp_if *omap2420_uart3_slaves[] = {static struct omap_hwmod omap2420_uart3_hwmod = { .name ="uart3" , + .flags =HWMOD_SWSUP_SIDLE , .mpu_irqs = uart3_mpu_irqs, .mpu_irqs_cnt =ARRAY_SIZE (uart3_mpu_irqs), .sdma_reqs = uart3_sdma_reqs,
arch/arm/mach-omap2/omap_hwmod_2430_data.c +3 -0
@@ -490,6 +490,7 @@ static struct omap_hwmod_ocp_if *omap2430_uart1_slaves[] = {static struct omap_hwmod omap2430_uart1_hwmod = { .name ="uart1" , + .flags =HWMOD_SWSUP_SIDLE , .mpu_irqs = uart1_mpu_irqs, .mpu_irqs_cnt =ARRAY_SIZE (uart1_mpu_irqs), .sdma_reqs = uart1_sdma_reqs,
@@ -527,6 +528,7 @@ static struct omap_hwmod_ocp_if *omap2430_uart2_slaves[] = {static struct omap_hwmod omap2430_uart2_hwmod = { .name ="uart2" , + .flags =HWMOD_SWSUP_SIDLE , .mpu_irqs = uart2_mpu_irqs, .mpu_irqs_cnt =ARRAY_SIZE (uart2_mpu_irqs), .sdma_reqs = uart2_sdma_reqs,
@@ -564,6 +566,7 @@ static struct omap_hwmod_ocp_if *omap2430_uart3_slaves[] = {static struct omap_hwmod omap2430_uart3_hwmod = { .name ="uart3" , + .flags =HWMOD_SWSUP_SIDLE , .mpu_irqs = uart3_mpu_irqs, .mpu_irqs_cnt =ARRAY_SIZE (uart3_mpu_irqs), .sdma_reqs = uart3_sdma_reqs,
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +4 -0
@@ -626,6 +626,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_uart1_slaves[] = {static struct omap_hwmod omap3xxx_uart1_hwmod = { .name ="uart1" , + .flags =HWMOD_SWSUP_SIDLE , .mpu_irqs = uart1_mpu_irqs, .mpu_irqs_cnt =ARRAY_SIZE (uart1_mpu_irqs), .sdma_reqs = uart1_sdma_reqs,
@@ -663,6 +664,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_uart2_slaves[] = {static struct omap_hwmod omap3xxx_uart2_hwmod = { .name ="uart2" , + .flags =HWMOD_SWSUP_SIDLE , .mpu_irqs = uart2_mpu_irqs, .mpu_irqs_cnt =ARRAY_SIZE (uart2_mpu_irqs), .sdma_reqs = uart2_sdma_reqs,
@@ -700,6 +702,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_uart3_slaves[] = {static struct omap_hwmod omap3xxx_uart3_hwmod = { .name ="uart3" , + .flags =HWMOD_SWSUP_SIDLE , .mpu_irqs = uart3_mpu_irqs, .mpu_irqs_cnt =ARRAY_SIZE (uart3_mpu_irqs), .sdma_reqs = uart3_sdma_reqs,
@@ -737,6 +740,7 @@ static struct omap_hwmod_ocp_if *omap3xxx_uart4_slaves[] = {static struct omap_hwmod omap3xxx_uart4_hwmod = { .name ="uart4" , + .flags =HWMOD_SWSUP_SIDLE , .mpu_irqs = uart4_mpu_irqs, .mpu_irqs_cnt =ARRAY_SIZE (uart4_mpu_irqs), .sdma_reqs = uart4_sdma_reqs,
arch/arm/mach-omap2/omap_hwmod_44xx_data.c +4 -0
@@ -4587,6 +4587,7 @@ static struct omap_hwmod_ocp_if *omap44xx_uart1_slaves[] = {static struct omap_hwmod omap44xx_uart1_hwmod = { .name ="uart1" , + .flags =HWMOD_SWSUP_SIDLE , .class = &omap44xx_uart_hwmod_class, .mpu_irqs = omap44xx_uart1_irqs, .mpu_irqs_cnt =ARRAY_SIZE (omap44xx_uart1_irqs),
@@ -4639,6 +4640,7 @@ static struct omap_hwmod_ocp_if *omap44xx_uart2_slaves[] = {static struct omap_hwmod omap44xx_uart2_hwmod = { .name ="uart2" , + .flags =HWMOD_SWSUP_SIDLE , .class = &omap44xx_uart_hwmod_class, .mpu_irqs = omap44xx_uart2_irqs, .mpu_irqs_cnt =ARRAY_SIZE (omap44xx_uart2_irqs),
@@ -4691,6 +4693,7 @@ static struct omap_hwmod_ocp_if *omap44xx_uart3_slaves[] = {static struct omap_hwmod omap44xx_uart3_hwmod = { .name ="uart3" , + .flags =HWMOD_SWSUP_SIDLE , .class = &omap44xx_uart_hwmod_class, .flags = (HWMOD_INIT_NO_IDLE |HWMOD_INIT_NO_RESET ), .mpu_irqs = omap44xx_uart3_irqs,
@@ -4744,6 +4747,7 @@ static struct omap_hwmod_ocp_if *omap44xx_uart4_slaves[] = {static struct omap_hwmod omap44xx_uart4_hwmod = { .name ="uart4" , + .flags =HWMOD_SWSUP_SIDLE , .class = &omap44xx_uart_hwmod_class, .mpu_irqs = omap44xx_uart4_irqs, .mpu_irqs_cnt =ARRAY_SIZE (omap44xx_uart4_irqs),
Signature · 1 line
1.7.1
PATCH 2/7 OMAP2+: mux: Enable wakeup for wakeup enable requested pads
In reply to Govindraj.RFor device pads which have OMAP_DEVICE_PAD_WAKEUP set (which means they are wakeup capable) enable the IO-daisy wakeup capability. During re-muxing avoid direct write with val as this can disturb if any mux done at bootloader level so read the pad then write back.
Also add a api to fetch the wake-up status bit is set for given omap-hwmod device using available mux info which is added during omap_hwmod_mux_init. Wakeup status bit is needed for uart_resume_idle call from sram_idle path based on wake-up event has occurred for given uart we can enable clocks back.
--- arch/arm/mach-omap2/mux.c | 23 +++++++++++++++++++++++ arch/arm/mach-omap2/mux.h | 13 +++++++++++++ arch/arm/mach-omap2/omap_hwmod.c | 13 +++++++++++++ arch/arm/plat-omap/include/plat/omap_hwmod.h | 1 + 4 files changed, 50 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/mux.c +23 -0
@@ -317,6 +317,24 @@ err1:return NULL ; } +/* Gets the wakeup status of given pad from omap-hwmod */ +int omap_hwmod_mux_wakeup (struct omap_hwmod_mux_info *hmux) +{ +int i; +unsigned int val = -EINVAL ; + +for (i =0 ; i < hmux->nr_pads; i++) { +struct omap_device_pad *pad = &hmux->pads[i]; + + val =omap_mux_read (pad->partition, pad->mux->reg_offset); + } + +if (val >0 && val &OMAP_WAKEUP_EVENT ) +return 1 ; +else +return 0 ; +} +/* Assumes the calling function takes care of locking */ void omap_hwmod_mux (struct omap_hwmod_mux_info *hmux,u8 state) {
@@ -342,6 +360,9 @@ void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state)break ; flags &= ~OMAP_DEVICE_PAD_ENABLED ; val = pad->idle; +if (flags &OMAP_DEVICE_PAD_WAKEUP ) + val |=OMAP_WAKEUP_EN ; +pr_debug ("%s: Idling %s %x\n" , __func__, pad->name, val);break ;
@@ -358,6 +379,8 @@ void omap_hwmod_mux(struct omap_hwmod_mux_info *hmux, u8 state) };if (val >=0 ) { + val |=omap_mux_read (pad->partition, + pad->mux->reg_offset);omap_mux_write (pad->partition, val, pad->mux->reg_offset); pad->flags = flags;
arch/arm/mach-omap2/mux.h +13 -0
@@ -220,8 +220,21 @@ omap_hwmod_mux_init(struct omap_device_pad *bpads, int nr_pads);*/ void omap_hwmod_mux (struct omap_hwmod_mux_info *hmux,u8 state); + +/** +* omap_hwmod_mux_wakeup - omap hwmod check given pad had wakeup event +* @hmux: Pads for a hwmod +* +* Called only from omap_hwmod.c, do not use. +*/ +int omap_hwmod_mux_wakeup (struct omap_hwmod_mux_info *hmux);#else +static inline int omap_hwmod_mux_wakeup (struct omap_hwmod_mux_info *hmux) +{ +return 0 ; +} +static inline int omap_mux_init_gpio (int gpio,int val) {return 0 ;
arch/arm/mach-omap2/omap_hwmod.c +13 -0
@@ -2239,3 +2239,16 @@ u32 omap_hwmod_get_context_loss_count(struct omap_hwmod *oh)return ret; } + +/** +* omap_hwmod_pad_wakeup_status - get pad wakeup status if mux is available. +* @oh: struct omap_hwmod * +* +* Returns the wake_up status bit of available pad mux pin. +*/ +int omap_hmwod_pad_wakeup_status (struct omap_hwmod *oh) +{ +if (oh->mux) +return omap_hwmod_mux_wakeup (oh->mux); +return -EINVAL ; +}
arch/arm/plat-omap/include/plat/omap_hwmod.h +1 -0
@@ -588,6 +588,7 @@ int omap_hwmod_for_each_by_class(const char *classname,int omap_hwmod_set_postsetup_state (struct omap_hwmod *oh,u8 state);u32 omap_hwmod_get_context_loss_count (struct omap_hwmod *oh); +int omap_hmwod_pad_wakeup_status (struct omap_hwmod *oh);/* * Chip variant-specific hwmod init routines - XXX should be converted * to use initcalls once the initial boot ordering is straightened out
Signature · 1 line
1.7.1
PATCH 2/7 OMAP2+: mux: Enable wakeup for wakeup enable requested pads
Govind,
Couple of minor comments.
Quoted 6 lines · Govindraj.R
For device pads which have
OMAP_DEVICE_PAD_WAKEUPset (which means they are wakeup capable) enable the IO-daisy wakeup capability. During re-muxing avoid direct write with val as this can disturb if any mux done at bootloader level so read the pad then write back.Also add a api to fetch the wake-up status bit is set for given omap-hwmod
%s/a api/an API/
Quoted 26 lines
device using available mux info which is added during
omap_hwmod_mux_init. Wakeup status bit is needed foruart_resume_idlecall fromsram_idlepath based on wake-up event has occurred for given uart we can enable clocks back.Signed-off-by Rajendra Nayak <[email protected]>Signed-off-by Govindraj.R <[email protected]>---
?arch/arm/mach-omap2/mux.c ? ? ? ? ? ? ? ? ? ?| ? 23 +++++++++++++++++++++++ ?arch/arm/mach-omap2/mux.h ? ? ? ? ? ? ? ? ? ?| ? 13 +++++++++++++ ?arch/arm/mach-omap2/omap_hwmod.c ? ? ? ? ? ? | ? 13 +++++++++++++ ?arch/arm/plat-omap/include/plat/omap_hwmod.h | ? ?1 +?4 files changed, 50 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/mux.c +5
-0@@ -317,6 +317,24 @@ err1: ? ? ? ?return NULL; ?} +/* Gets the wakeup status of given pad from omap-hwmod */ +int omap_hwmod_mux_wakeup (struct omap_hwmod_mux_info *hmux) +{ + ? ? ? int i; + ? ? ? unsigned int val = -EINVAL;
arch/arm/mach-omap2/mux.c err1: · line 334
Quoted 10 lines
arch/arm/mach-omap2/mux.c +10
-0+ + ? ? ? for (i = 0; i < hmux->nr_pads; i++) { + ? ? ? ? ? ? ? struct omap_device_pad *pad = &hmux->pads[i]; + + ? ? ? ? ? ? ? val = omap_mux_read(pad->partition, pad->mux->reg_offset); + ? ? ? } + + ? ? ? if (val > 0 && val & OMAP_WAKEUP_EVENT) + ? ? ? ? ? ? ? return 1; + ? ? ? else
No need of else here.
arch/arm/mach-omap2/mux.c err1: · line 331
Quoted 3 lines
arch/arm/mach-omap2/mux.c +3
-0+ ? ? ? ? ? ? ? return 0; +} +
- V Charulatha
PATCH 2/7 OMAP2+: mux: Enable wakeup for wakeup enable requested pads
Quoted 44 lines · Charulatha
Govind,
Couple of minor comments.
Quoted 6 lines · Govindraj.R
For device pads which have
OMAP_DEVICE_PAD_WAKEUPset (which means they are wakeup capable) enable the IO-daisy wakeup capability. During re-muxing avoid direct write with val as this can disturb if any mux done at bootloader level so read the pad then write back.Also add a api to fetch the wake-up status bit is set for given omap-hwmod
%s/a api/an API/
Quoted 30 lines
device using available mux info which is added during
omap_hwmod_mux_init. Wakeup status bit is needed foruart_resume_idlecall fromsram_idlepath based on wake-up event has occurred for given uart we can enable clocks back.Signed-off-by Rajendra Nayak <[email protected]>Signed-off-by Govindraj.R <[email protected]>---
?arch/arm/mach-omap2/mux.c ? ? ? ? ? ? ? ? ? ?| ? 23 +++++++++++++++++++++++ ?arch/arm/mach-omap2/mux.h ? ? ? ? ? ? ? ? ? ?| ? 13 +++++++++++++ ?arch/arm/mach-omap2/omap_hwmod.c ? ? ? ? ? ? | ? 13 +++++++++++++ ?arch/arm/plat-omap/include/plat/omap_hwmod.h | ? ?1 +?4 files changed, 50 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/mux.c +9
-0@@ -317,6 +317,24 @@ err1: ? ? ? ?return NULL; ?} +/* Gets the wakeup status of given pad from omap-hwmod */ +int omap_hwmod_mux_wakeup (struct omap_hwmod_mux_info *hmux) +{ + ? ? ? int i; + ? ? ? unsigned int val = -EINVAL; + + ? ? ? for (i = 0; i < hmux->nr_pads; i++) { + ? ? ? ? ? ? ? struct omap_device_pad *pad = &hmux->pads[i]; +
Quoted 8 lines
arch/arm/mach-omap2/mux.c err1: · line 334
Quoted 6 lines
arch/arm/mach-omap2/mux.c +6
-0+ ? ? ? ? ? ? ? val = omap_mux_read(pad->partition, pad->mux->reg_offset); + ? ? ? } + + ? ? ? if (val > 0 && val & OMAP_WAKEUP_EVENT) + ? ? ? ? ? ? ? return 1; + ? ? ? elseNo need of else here.
Yes correct.
I am resending this patch with some more modifications to fix one more issue in the above loop.
--
Thanks,
Govindraj.R
<<SNIP>>
PATCH 3/7 OMAP2+: UART: Remove certain uart calls from sram_idle
In reply to Govindraj.RIn preparation to UART runtime conversion. Remove certain uart specific calls from sram_idle path in pm24xx/34xx files.
These func calls will no more be used with upcoming uart runtime design.
1.) Removing console lock holding :- Now can be handled with omap-serial file
itself with appropraite console_enable/disable calls for clk_enable/disable cases.
2.) omap_uart_can_sleep :- not needed driver can decide based on inactivity. 3.) omap_uart_prepare_suspend :- omap-serial can take care with driver
suspend/resume hooks.
--- arch/arm/mach-omap2/pm24xx.c | 11 ----------- arch/arm/mach-omap2/pm34xx.c | 16 ---------------- arch/arm/plat-omap/include/plat/serial.h | 4 ---- 3 files changed, 0 insertions(+), 31 deletions(-)
arch/arm/mach-omap2/pm24xx.c +0 -11
@@ -132,11 +132,6 @@ static void omap2_enter_full_retention(void)if (omap_irq_pending ()) goto no_sleep; -/* Block console output in case it is on one of the OMAP UARTs */ -if (!is_suspending ()) -if (!console_trylock ()) - goto no_sleep; -omap_uart_prepare_idle (0 );omap_uart_prepare_idle (1 );omap_uart_prepare_idle (2 );
@@ -150,9 +145,6 @@ static void omap2_enter_full_retention(void)omap_uart_resume_idle (1 );omap_uart_resume_idle (0 ); -if (!is_suspending ()) -console_unlock (); - no_sleep:if (omap2_pm_debug) {unsigned long long tmp;
@@ -267,8 +259,6 @@ static int omap2_can_sleep(void) {if (omap2_fclks_active ())return 0 ; -if (!omap_uart_can_sleep ()) -return 0 ;if (osc_ck->usecount >1 )return 0 ;if (omap_dma_running ())
@@ -319,7 +309,6 @@ static int omap2_pm_suspend(void) mir1 =omap_readl (0x480fe0a4 );omap_writel (1 <<5 ,0x480fe0ac ); -omap_uart_prepare_suspend ();omap2_enter_full_retention ();omap_writel (mir1,0x480fe0a4 );
arch/arm/mach-omap2/pm34xx.c +0 -16
@@ -395,13 +395,6 @@ void omap_sram_idle(void)omap3_enable_io_chain (); } -/* Block console output in case it is on one of the OMAP UARTs */ -if (!is_suspending ()) -if (per_next_state <PWRDM_POWER_ON || - core_next_state <PWRDM_POWER_ON ) -if (!console_trylock ()) - goto console_still_active; -/* PER */ if (per_next_state <PWRDM_POWER_ON ) { per_going_off = (per_next_state ==PWRDM_POWER_OFF ) ?1 :0 ;
@@ -481,10 +474,6 @@ void omap_sram_idle(void)omap_uart_resume_idle (3 ); } -if (!is_suspending ()) -console_unlock (); - -console_still_active:/* Disable IO-PAD and IO-CHAIN wakeup */ if (omap3_has_io_wakeup() && (per_next_state < PWRDM_POWER_ON ||
@@ -503,8 +492,6 @@ int omap3_can_sleep(void) {if (!sleep_while_idle)return 0 ; -if (!omap_uart_can_sleep ()) -return 0 ;return 1 ; }
@@ -547,7 +534,6 @@ static int omap3_pm_suspend(void) goto restore; } -omap_uart_prepare_suspend ();omap3_intc_suspend ();omap_sram_idle ();
@@ -594,14 +580,12 @@ static int omap3_pm_begin(suspend_state_t state) {disable_hlt (); suspend_state = state; -omap_uart_enable_irqs (0 );return 0 ; }static void omap3_pm_end (void ) { suspend_state =PM_SUSPEND_ON ; -omap_uart_enable_irqs (1 );enable_hlt ();return ; }
arch/arm/plat-omap/include/plat/serial.h +0 -4
@@ -106,12 +106,8 @@ struct omap_board_data;extern void omap_serial_init (void );extern void omap_serial_init_port (struct omap_board_data *bdata); -extern int omap_uart_can_sleep (void ); -extern void omap_uart_check_wakeup (void ); -extern void omap_uart_prepare_suspend (void );extern void omap_uart_prepare_idle (int num);extern void omap_uart_resume_idle (int num); -extern void omap_uart_enable_irqs (int enable);#endif #endif
Signature · 1 line
1.7.1
PATCH 4/7 OMAP2+: UART: Remove uart clock handling code serial.c
In reply to Govindraj.RCleanup serial.c file in preparation to addition of runtime api's in omap-serial file. Cleanup serial.c file and remove all clock handling mechanism as this will be taken care with pm runtime apis in omap-serial.c file itself.
1.) remove omap-device enable and disable. We can can use get_sync/put_sync api's 2.) remove context save/restore can be done with runtime_resume callback for
get_sync call. No need to save context as all reg details available in uart_port structure can be used for restore, so add missing regs in uart port struct.
3.) Add api to identify console uart.
4.) Erratum handling informed as flag to driver and func to handle erratum
can be moved to omap-serial driver itself.
--- arch/arm/mach-omap2/serial.c | 749 ++----------------------- arch/arm/plat-omap/include/plat/omap-serial.h | 21 +- 2 files changed, 75 insertions(+), 695 deletions(-)
arch/arm/mach-omap2/serial.c +57 -692
@@ -19,25 +19,18 @@*/ #include <linux/kernel.h> #include <linux/init.h> -#include <linux/serial_reg.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/slab.h> -#include <linux/serial_8250.h> #include <linux/pm_runtime.h> -#include <linux/console.h> -#ifdef CONFIG_SERIAL_OMAP #include <plat/omap-serial.h> -#endif -#include <plat/common.h> #include <plat/board.h> #include <plat/clock.h> #include <plat/dma.h> -#include <plat/omap_hwmod.h> #include <plat/omap_device.h> #include "prm2xxx_3xxx.h"
@@ -47,65 +40,9 @@#include "control.h" #include "mux.h" -#define UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV 0x52 -#define UART_OMAP_WER 0x17/* Wake-up enable register */ - -#define UART_ERRATA_FIFO_FULL_ABORT (0x1 << 0) -#define UART_ERRATA_i202_MDR1_ACCESS (0x1 << 1) - -/* -* NOTE: By default the serial timeout is disabled as it causes lost characters -* over the serial ports. This means that the UART clocks will stay on until -* disabled via sysfs. This also causes that any deeper omap sleep states are -* blocked. -*/ -#define DEFAULT_TIMEOUT 0 - -#define MAX_UART_HWMOD_NAME_LEN 16 - -struct omap_uart_state { -int num; -int can_sleep; -struct timer_list timer; -u32 timeout; - -void __iomem *wk_st; -void __iomem *wk_en; -u32 wk_mask; -u32 padconf; -u32 dma_enabled; - -struct clk *ick; -struct clk *fck; -int clocked; - -int irq; -int regshift; -int irqflags; -void __iomem *membase; -resource_size_t mapbase; - -struct list_head node; -struct omap_hwmod *oh; -struct platform_device *pdev; - -u32 errata; -#if defined(CONFIG_ARCH_OMAP3 ) && defined(CONFIG_PM ) -int context_valid; +#define MAX_UART_HWMOD_NAME_LEN 16 -/* Registers to be saved/restored for OFF-mode */ -u16 dll; -u16 dlh; -u16 ier; -u16 sysc; -u16 scr; -u16 wer; -u16 mcr; -#endif -}; - -static LIST_HEAD (uart_list); -static u8 num_uarts; +static int omap_uart_con_id__initdata =-1 ;static int uart_idle_hwmod (struct omap_device *od) {
@@ -129,396 +66,35 @@ static struct omap_device_pm_latency omap_uart_latency[] = { }, }; -static inline unsigned int __serial_read_reg (struct uart_port *up, -int offset) -{ - offset <<= up->regshift; -return (unsigned int )__raw_readb (up->membase + offset); -} - -static inline unsigned int serial_read_reg (struct omap_uart_state *uart, -int offset) -{ - offset <<= uart->regshift; -return (unsigned int )__raw_readb (uart->membase + offset); -} - -static inline void __serial_write_reg (struct uart_port *up,int offset, -int value) -{ - offset <<= up->regshift; -__raw_writeb (value, up->membase + offset); -} - -static inline void serial_write_reg (struct omap_uart_state *uart,int offset, -int value) -{ - offset <<= uart->regshift; -__raw_writeb (value, uart->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 inline void __init omap_uart_reset (struct omap_uart_state *uart) -{ -serial_write_reg (uart,UART_OMAP_MDR1 ,UART_OMAP_MDR1_DISABLE ); -serial_write_reg (uart,UART_OMAP_SCR ,0x08 ); -serial_write_reg (uart,UART_OMAP_MDR1 ,UART_OMAP_MDR1_16X_MODE ); -} - -#if defined(CONFIG_PM ) && defined(CONFIG_ARCH_OMAP3 ) - -/* -* Work Around for Errata i202 (3430 - 1.12, 3630 - 1.6) -* The access to uart register after MDR1 Access -* causes UART to corrupt data. -* -* Need a delay = -* 5 L4 clock cycles + 5 UART functional clock cycle (@48MHz = ~0.2uS) -* give 10 times as much -*/ -static void omap_uart_mdr1_errataset (struct omap_uart_state *uart,u8 mdr1_val, -u8 fcr_val) -{ -u8 timeout =255 ; - -serial_write_reg (uart,UART_OMAP_MDR1 , mdr1_val); -udelay (2 ); -serial_write_reg (uart,UART_FCR , fcr_val |UART_FCR_CLEAR_XMIT | -UART_FCR_CLEAR_RCVR ); -/* -* Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and -* TX_FIFO_E bit is 1. -*/ -while (UART_LSR_THRE != (serial_read_reg (uart,UART_LSR ) & - (UART_LSR_THRE |UART_LSR_DR ))) { - timeout--; -if (!timeout) { -/* Should *never* happen. we warn and carry on */ -dev_crit (&uart->pdev->dev,"Errata i202: timedout %x\n" , -serial_read_reg (uart,UART_LSR )); -break ; - } -udelay (1 ); - } -} - -static void omap_uart_save_context (struct omap_uart_state *uart) -{ -u16 lcr =0 ; - -if (!enable_off_mode) -return ; - - lcr =serial_read_reg (uart,UART_LCR ); -serial_write_reg (uart,UART_LCR ,UART_LCR_CONF_MODE_B ); - uart->dll =serial_read_reg (uart,UART_DLL ); - uart->dlh =serial_read_reg (uart,UART_DLM ); -serial_write_reg (uart,UART_LCR , lcr); - uart->ier =serial_read_reg (uart,UART_IER ); - uart->sysc =serial_read_reg (uart,UART_OMAP_SYSC ); - uart->scr =serial_read_reg (uart,UART_OMAP_SCR ); - uart->wer =serial_read_reg (uart,UART_OMAP_WER ); -serial_write_reg (uart,UART_LCR ,UART_LCR_CONF_MODE_A ); - uart->mcr =serial_read_reg (uart,UART_MCR ); -serial_write_reg (uart,UART_LCR , lcr); - - uart->context_valid =1 ; -} - -static void omap_uart_restore_context (struct omap_uart_state *uart) -{ -u16 efr =0 ; - -if (!enable_off_mode) -return ; - -if (!uart->context_valid) -return ; - - uart->context_valid =0 ; - -if (uart->errata & UART_ERRATA_i202_MDR1_ACCESS) -omap_uart_mdr1_errataset (uart,UART_OMAP_MDR1_DISABLE ,0xA0 ); -else -serial_write_reg (uart,UART_OMAP_MDR1 ,UART_OMAP_MDR1_DISABLE ); - -serial_write_reg (uart,UART_LCR ,UART_LCR_CONF_MODE_B ); - efr =serial_read_reg (uart,UART_EFR ); -serial_write_reg (uart,UART_EFR ,UART_EFR_ECB ); -serial_write_reg (uart,UART_LCR ,0x0 );/* Operational mode */ -serial_write_reg (uart,UART_IER ,0x0 ); -serial_write_reg (uart,UART_LCR ,UART_LCR_CONF_MODE_B ); -serial_write_reg (uart,UART_DLL , uart->dll); -serial_write_reg (uart,UART_DLM , uart->dlh); -serial_write_reg (uart,UART_LCR ,0x0 );/* Operational mode */ -serial_write_reg (uart,UART_IER , uart->ier); -serial_write_reg (uart,UART_LCR ,UART_LCR_CONF_MODE_A ); -serial_write_reg (uart,UART_MCR , uart->mcr); -serial_write_reg (uart,UART_LCR ,UART_LCR_CONF_MODE_B ); -serial_write_reg (uart,UART_EFR , efr); -serial_write_reg (uart,UART_LCR ,UART_LCR_WLEN8 ); -serial_write_reg (uart,UART_OMAP_SCR , uart->scr); -serial_write_reg (uart,UART_OMAP_WER , uart->wer); -serial_write_reg (uart,UART_OMAP_SYSC , uart->sysc); - -if (uart->errata & UART_ERRATA_i202_MDR1_ACCESS) -omap_uart_mdr1_errataset (uart,UART_OMAP_MDR1_16X_MODE ,0xA1 ); -else -/* UART 16x mode */ -serial_write_reg (uart,UART_OMAP_MDR1 , -UART_OMAP_MDR1_16X_MODE ); -} -#else -static inline void omap_uart_save_context (struct omap_uart_state *uart) {} -static inline void omap_uart_restore_context (struct omap_uart_state *uart) {} -#endif /* CONFIG_PM && CONFIG_ARCH_OMAP3 */ - -static inline void omap_uart_enable_clocks (struct omap_uart_state *uart) -{ -if (uart->clocked) -return ; - -omap_device_enable (uart->pdev); - uart->clocked =1 ; -omap_uart_restore_context (uart); -} - -#ifdef CONFIG_PM - -static inline void omap_uart_disable_clocks (struct omap_uart_state *uart) -{ -if (!uart->clocked) -return ; - -omap_uart_save_context (uart); - uart->clocked =0 ; -omap_device_idle (uart->pdev); -} - -static void omap_uart_enable_wakeup (struct omap_uart_state *uart) -{ -/* Set wake-enable bit */ -if (uart->wk_en && uart->wk_mask) { -u32 v =__raw_readl (uart->wk_en); - v |= uart->wk_mask; -__raw_writel (v, uart->wk_en); - } - -/* Ensure IOPAD wake-enables are set */ -if (cpu_is_omap34xx () && uart->padconf) { -u16 v =omap_ctrl_readw (uart->padconf); - v |=OMAP3_PADCONF_WAKEUPENABLE0 ; -omap_ctrl_writew (v, uart->padconf); - } -} - -static void omap_uart_disable_wakeup (struct omap_uart_state *uart) -{ -/* Clear wake-enable bit */ -if (uart->wk_en && uart->wk_mask) { -u32 v =__raw_readl (uart->wk_en); - v &= ~uart->wk_mask; -__raw_writel (v, uart->wk_en); - } - -/* Ensure IOPAD wake-enables are cleared */ -if (cpu_is_omap34xx () && uart->padconf) { -u16 v =omap_ctrl_readw (uart->padconf); - v &= ~OMAP3_PADCONF_WAKEUPENABLE0 ; -omap_ctrl_writew (v, uart->padconf); - } -} - -static void omap_uart_smart_idle_enable (struct omap_uart_state *uart, -int enable) -{ -u8 idlemode; - -if (enable) { -/** -* Errata 2.15: [UART]:Cannot Acknowledge Idle Requests -* in Smartidle Mode When Configured for DMA Operations. -*/ -if (uart->dma_enabled) - idlemode =HWMOD_IDLEMODE_FORCE ; -else - idlemode =HWMOD_IDLEMODE_SMART ; - }else { - idlemode =HWMOD_IDLEMODE_NO ; - } - -omap_hwmod_set_slave_idlemode (uart->oh, idlemode); -} - -static void omap_uart_block_sleep (struct omap_uart_state *uart) -{ -omap_uart_enable_clocks (uart); - -omap_uart_smart_idle_enable (uart,0 ); - uart->can_sleep =0 ; -if (uart->timeout) -mod_timer (&uart->timer, jiffies + uart->timeout); -else -del_timer (&uart->timer); -} - -static void omap_uart_allow_sleep (struct omap_uart_state *uart) -{ -if (device_may_wakeup (&uart->pdev->dev)) -omap_uart_enable_wakeup (uart); -else -omap_uart_disable_wakeup (uart); - -if (!uart->clocked) -return ; - -omap_uart_smart_idle_enable (uart,1 ); - uart->can_sleep =1 ; -del_timer (&uart->timer); -} - -static void omap_uart_idle_timer (unsigned long data) +static void omap_uart_idle_init (struct omap_uart_port_info *uart, +unsigned short num) { -struct omap_uart_state *uart = (struct omap_uart_state *)data; - -omap_uart_allow_sleep (uart); -} - -void omap_uart_prepare_idle (int num) -{ -struct omap_uart_state *uart; - -list_for_each_entry (uart, &uart_list, node) { -if (num == uart->num && uart->can_sleep) { -omap_uart_disable_clocks (uart); -return ; - } - } -} - -void omap_uart_resume_idle (int num) -{ -struct omap_uart_state *uart; - -list_for_each_entry (uart, &uart_list, node) { -if (num == uart->num && uart->can_sleep) { -omap_uart_enable_clocks (uart); - -/* Check for IO pad wakeup */ -if (cpu_is_omap34xx () && uart->padconf) { -u16 p =omap_ctrl_readw (uart->padconf); - -if (p &OMAP3_PADCONF_WAKEUPEVENT0 ) -omap_uart_block_sleep (uart); - } - -/* Check for normal UART wakeup */ -if (__raw_readl (uart->wk_st) & uart->wk_mask) -omap_uart_block_sleep (uart); -return ; - } - } -} - -void omap_uart_prepare_suspend (void ) -{ -struct omap_uart_state *uart; - -list_for_each_entry (uart, &uart_list, node) { -omap_uart_allow_sleep (uart); - } -} - -int omap_uart_can_sleep (void ) -{ -struct omap_uart_state *uart; -int can_sleep =1 ; - -list_for_each_entry (uart, &uart_list, node) { -if (!uart->clocked) -continue ; - -if (!uart->can_sleep) { - can_sleep =0 ; -continue ; - } - -/* This UART can now safely sleep. */ -omap_uart_allow_sleep (uart); - } - -return can_sleep; -} - -/** -* omap_uart_interrupt() -* -* This handler is used only to detect that *any* UART interrupt has -* occurred. It does _nothing_ to handle the interrupt. Rather, -* any UART interrupt will trigger the inactivity timer so the -* UART will not idle or sleep for its timeout period. -* -**/ -/* static int first_interrupt; */ -static irqreturn_t omap_uart_interrupt (int irq,void *dev_id) -{ -struct omap_uart_state *uart = dev_id; - -omap_uart_block_sleep (uart); - -return IRQ_NONE ; -} - -static void omap_uart_idle_init (struct omap_uart_state *uart) -{ -int ret; - - uart->can_sleep =0 ; - uart->timeout =DEFAULT_TIMEOUT ; -setup_timer (&uart->timer, omap_uart_idle_timer, - (unsigned long ) uart); -if (uart->timeout) -mod_timer (&uart->timer, jiffies + uart->timeout); -omap_uart_smart_idle_enable (uart,0 ); - -if (cpu_is_omap34xx () && !cpu_is_ti816x ()) { -u32 mod = (uart->num >1 ) ?OMAP3430_PER_MOD :CORE_MOD ; +if (cpu_is_omap34xx ()) { +u32 mod = num >1 ?OMAP3430_PER_MOD :CORE_MOD ;u32 wk_mask =0 ; -u32 padconf =0 ; -/* XXX These PRM accesses do not belong here */ uart->wk_en =OMAP34XX_PRM_REGADDR (mod,PM_WKEN1 ); uart->wk_st =OMAP34XX_PRM_REGADDR (mod,PM_WKST1 ); -switch (uart->num) { +switch (num) {case 0 : wk_mask =OMAP3430_ST_UART1_MASK ; - padconf =0x182 ;break ;case 1 : wk_mask =OMAP3430_ST_UART2_MASK ; - padconf =0x17a ;break ;case 2 : wk_mask =OMAP3430_ST_UART3_MASK ; - padconf =0x19e ;break ;case 3 : wk_mask =OMAP3630_ST_UART4_MASK ; - padconf =0x0d2 ;break ; } uart->wk_mask = wk_mask; - uart->padconf = padconf; }else if (cpu_is_omap24xx ()) {u32 wk_mask =0 ;u32 wk_en =PM_WKEN1 , wk_st =PM_WKST1 ; -switch (uart->num) { +switch (num) {case 0 : wk_mask =OMAP24XX_ST_UART1_MASK ;break ;
@@ -543,155 +119,44 @@ static void omap_uart_idle_init(struct omap_uart_state *uart) uart->wk_en =NULL ; uart->wk_st =NULL ; uart->wk_mask =0 ; - uart->padconf = 0; - } - - uart->irqflags |=IRQF_SHARED ; - ret =request_threaded_irq (uart->irq,NULL , omap_uart_interrupt, -IRQF_SHARED ,"serial idle" , (void *)uart); -WARN_ON (ret); -} - -void omap_uart_enable_irqs (int enable) -{ -int ret; -struct omap_uart_state *uart; - -list_for_each_entry (uart, &uart_list, node) { -if (enable) { -pm_runtime_put_sync (&uart->pdev->dev); - ret =request_threaded_irq (uart->irq,NULL , - omap_uart_interrupt, -IRQF_SHARED , -"serial idle" , - (void *)uart); - }else { -pm_runtime_get_noresume (&uart->pdev->dev); -free_irq (uart->irq, (void *)uart); - } } } -static ssize_t sleep_timeout_show (struct device *dev, -struct device_attribute *attr, -char *buf) +char *cmdline_find_option (char *str) { -struct platform_device *pdev =to_platform_device (dev); -struct omap_device *odev =to_omap_device (pdev); -struct omap_uart_state *uart = odev->hwmods[0 ]->dev_attr; +extern char *saved_command_line; -return sprintf (buf,"%u\n" , uart->timeout /HZ ); +return strstr (saved_command_line, str); } -static ssize_t sleep_timeout_store (struct device *dev, -struct device_attribute *attr, -const char *buf,size_t n) +struct omap_hwmod *omap_uart_hwmod_lookup (int num) { -struct platform_device *pdev =to_platform_device (dev); -struct omap_device *odev =to_omap_device (pdev); -struct omap_uart_state *uart = odev->hwmods[0 ]->dev_attr; -unsigned int value; - -if (sscanf (buf,"%u" , &value) !=1 ) { -dev_err (dev,"sleep_timeout_store: Invalid value\n" ); -return -EINVAL ; - } - - uart->timeout = value *HZ ; -if (uart->timeout) -mod_timer (&uart->timer, jiffies + uart->timeout); -else -/* A zero value means disable timeout feature */ -omap_uart_block_sleep (uart); - -return n; -} - -static DEVICE_ATTR(sleep_timeout, 0644, sleep_timeout_show, - sleep_timeout_store); -#define DEV_CREATE_FILE (dev, attr) WARN_ON(device_create_file(dev, attr)) -#else -static inline void omap_uart_idle_init (struct omap_uart_state *uart) {} -static void omap_uart_block_sleep (struct omap_uart_state *uart) -{ -/* Needed to enable UART clocks when built without CONFIG_PM */ -omap_uart_enable_clocks (uart); -} -#define DEV_CREATE_FILE (dev, attr) -#endif /* CONFIG_PM */ - -#ifndef CONFIG_SERIAL_OMAP -/* -* Override the default 8250 read handler: mem_serial_in() -* Empty RX fifo read causes an abort on omap3630 and omap4 -* This function makes sure that an empty rx fifo is not read on these silicons -* (OMAP1/2/3430 are not affected) -*/ -static unsigned int serial_in_override (struct uart_port *up,int offset) -{ -if (UART_RX == offset) { -unsigned int lsr; - lsr =__serial_read_reg (up,UART_LSR ); -if (!(lsr &UART_LSR_DR )) -return -EPERM ; - } - -return __serial_read_reg (up, offset); -} - -static void serial_out_override (struct uart_port *up,int offset,int value) -{ -unsigned int status, tmout =10000 ; +struct omap_hwmod *oh; +char oh_name[MAX_UART_HWMOD_NAME_LEN ]; - status =__serial_read_reg (up,UART_LSR ); -while (!(status &UART_LSR_THRE )) { -/* Wait up to 10ms for the character(s) to be sent. */ -if (--tmout ==0 ) -break ; -udelay (1 ); - status =__serial_read_reg (up,UART_LSR ); - } -__serial_write_reg (up, offset, value); +snprintf (oh_name,MAX_UART_HWMOD_NAME_LEN ,"uart%d" , num +1 ); + oh =omap_hwmod_lookup (oh_name); +WARN (IS_ERR (oh),"Could not lookup hmwod info for %s\n" , + oh_name); +return oh; } -#endif static int __init omap_serial_early_init (void ) {int i =0 ; +char omap_tty_name[MAX_UART_HWMOD_NAME_LEN ]; +struct omap_hwmod *oh; -do { -char oh_name[MAX_UART_HWMOD_NAME_LEN ]; -struct omap_hwmod *oh; -struct omap_uart_state *uart; - -snprintf (oh_name,MAX_UART_HWMOD_NAME_LEN , -"uart%d" , i +1 ); - oh =omap_hwmod_lookup (oh_name); -if (!oh) -break ; - - uart =kzalloc (sizeof (struct omap_uart_state ),GFP_KERNEL ); -if (WARN_ON (!uart)) -return -ENODEV ; - - uart->oh = oh; - uart->num = i++; -list_add_tail (&uart->node, &uart_list); - num_uarts++; - -/* -* NOTE: omap_hwmod_init() has not yet been called, -* so no hwmod functions will work yet. -*/ - -/* -* During UART early init, device need to be probed -* to determine SoC specific init before omap_device -* is ready. Therefore, don't allow idle here -*/ - uart->oh->flags |=HWMOD_INIT_NO_IDLE |HWMOD_INIT_NO_RESET ; - }while (1 ); - +for (i =0 ; i <OMAP_MAX_HSUART_PORTS ; i++) { +snprintf (omap_tty_name,MAX_UART_HWMOD_NAME_LEN , +"%s%d" ,OMAP_SERIAL_NAME , i); +if (cmdline_find_option (omap_tty_name)) { + omap_uart_con_id = i; + oh =omap_uart_hwmod_lookup (i); + oh->flags |=HWMOD_INIT_NO_IDLE |HWMOD_INIT_NO_RESET ; +return 0 ; + } + }return 0 ; }core_initcall (omap_serial_early_init);
@@ -709,149 +174,50 @@ core_initcall(omap_serial_early_init);*/ void __init omap_serial_init_port (struct omap_board_data *bdata) { -struct omap_uart_state *uart;struct omap_hwmod *oh;struct omap_device *od; -void *pdata =NULL ; -u32 pdata_size =0 ; -char *name; -#ifndef CONFIG_SERIAL_OMAP -struct plat_serial8250_port ports[2 ] = { - {}, - {.flags =0 }, - }; -struct plat_serial8250_port *p = &ports[0 ]; -#else -struct omap_uart_port_info omap_up; -#endif +struct omap_uart_port_info *pdata; +char *name =DRIVER_NAME ;if (WARN_ON (!bdata))return ;if (WARN_ON (bdata->id <0 ))return ; -if (WARN_ON (bdata->id >= num_uarts)) +if (WARN_ON (bdata->id >=OMAP_MAX_HSUART_PORTS ))return ; -list_for_each_entry (uart, &uart_list, node) -if (bdata->id == uart->num) -break ; - - oh = uart->oh; - uart->dma_enabled =0 ; -#ifndef CONFIG_SERIAL_OMAP - name ="serial8250" ; - -/* -* !! 8250 driver does not use standard IORESOURCE* It -* has it's own custom pdata that can be taken from -* the hwmod resource data. But, this needs to be -* done after the build. -* -* ?? does it have to be done before the register ?? -* YES, because platform_device_data_add() copies -* pdata, it does not use a pointer. -*/ - p->flags =UPF_BOOT_AUTOCONF ; - p->iotype =UPIO_MEM ; - p->regshift =2 ; - p->uartclk =OMAP24XX_BASE_BAUD *16 ; - p->irq = oh->mpu_irqs[0 ].irq; - p->mapbase = oh->slaves[0 ]->addr->pa_start; - p->membase =omap_hwmod_get_mpu_rt_va (oh); - p->irqflags =IRQF_SHARED ; - p->private_data = uart; - -/* -* omap44xx, ti816x: Never read empty UART fifo -* omap3xxx: Never read empty UART fifo on UARTs -* with IP rev >=0x52 -*/ - uart->regshift = p->regshift; - uart->membase = p->membase; -if (cpu_is_omap44xx () ||cpu_is_ti816x ()) - uart->errata |=UART_ERRATA_FIFO_FULL_ABORT ; -else if ((serial_read_reg (uart,UART_OMAP_MVER ) &0xFF ) - >=UART_OMAP_NO_EMPTY_FIFO_READ_IP_REV ) - uart->errata |=UART_ERRATA_FIFO_FULL_ABORT ; + oh =omap_uart_hwmod_lookup (bdata->id); +if (!oh) +return ; -if (uart->errata &UART_ERRATA_FIFO_FULL_ABORT ) { - p->serial_in = serial_in_override; - p->serial_out = serial_out_override; + pdata =kzalloc (sizeof (*pdata),GFP_KERNEL ); +if (!pdata) { +pr_err ("Memory allocation for UART pdata failed\n" ); +return ; } - pdata = &ports[0 ]; - pdata_size =2 *sizeof (struct plat_serial8250_port ); -#else - - name =DRIVER_NAME ; +/* Enable the MDR1 errata for OMAP3 */ +if (cpu_is_omap34xx ()) + pdata->errata |= UART_ERRATA_i202_MDR1_ACCESS; - omap_up.dma_enabled = uart->dma_enabled; - omap_up.uartclk =OMAP24XX_BASE_BAUD *16 ; - omap_up.mapbase = oh->slaves[0 ]->addr->pa_start; - omap_up.membase =omap_hwmod_get_mpu_rt_va (oh); - omap_up.irqflags =IRQF_SHARED ; - omap_up.flags =UPF_BOOT_AUTOCONF |UPF_SHARE_IRQ ; +omap_uart_idle_init (pdata, bdata->id); - pdata = &omap_up; - pdata_size =sizeof (struct omap_uart_port_info ); -#endif + pdata->uartclk =OMAP24XX_BASE_BAUD *16 ; + pdata->flags =UPF_BOOT_AUTOCONF ; +if (bdata->id == omap_uart_con_id) + pdata->console_uart = true; -if (WARN_ON (!oh)) -return ; - - od =omap_device_build (name, uart->num, oh, pdata, pdata_size, - omap_uart_latency, -ARRAY_SIZE (omap_uart_latency), false); + od =omap_device_build (name, bdata->id, oh, pdata, +sizeof (*pdata), omap_uart_latency, +ARRAY_SIZE (omap_uart_latency), false);WARN (IS_ERR (od),"Could not build omap_device for %s: %s.\n" , name, oh->name); oh->mux =omap_hwmod_mux_init (bdata->pads, bdata->pads_cnt); - - uart->irq = oh->mpu_irqs[0 ].irq; - uart->regshift =2 ; - uart->mapbase = oh->slaves[0 ]->addr->pa_start; - uart->membase =omap_hwmod_get_mpu_rt_va (oh); - uart->pdev = &od->pdev; - - oh->dev_attr = uart; - -console_lock ();/* in case the earlycon is on the UART */ - -/* -* Because of early UART probing, UART did not get idled -* on init. Now that omap_device is ready, ensure full idle -* before doing omap_device_enable(). -*/ -omap_hwmod_idle (uart->oh); - -omap_device_enable (uart->pdev); -omap_uart_idle_init (uart); -omap_uart_reset (uart); -omap_hwmod_enable_wakeup (uart->oh); -omap_device_idle (uart->pdev); - -/* -* Need to block sleep long enough for interrupt driven -* driver to start. Console driver is in polling mode -* so device needs to be kept enabled while polling driver -* is in use. -*/ -if (uart->timeout) - uart->timeout = (30 *HZ ); -omap_uart_block_sleep (uart); - uart->timeout =DEFAULT_TIMEOUT ; - -console_unlock (); - -if ((cpu_is_omap34xx () && uart->padconf) || - (uart->wk_en && uart->wk_mask)) { +if (((cpu_is_omap34xx () ||cpu_is_omap44xx ()) && bdata->pads) || + (pdata->wk_en && pdata->wk_mask)) {device_init_wakeup (&od->pdev.dev, true); -DEV_CREATE_FILE (&od->pdev.dev, &dev_attr_sleep_timeout); } - -/* Enable the MDR1 errata for OMAP3 */ -if (cpu_is_omap34xx () && !cpu_is_ti816x ()) - uart->errata |= UART_ERRATA_i202_MDR1_ACCESS; }/**
@@ -863,15 +229,14 @@ void __init omap_serial_init_port(struct omap_board_data *bdata)*/ void __init omap_serial_init (void ) { -struct omap_uart_state *uart;struct omap_board_data bdata; +u8 i; -list_for_each_entry (uart, &uart_list, node) { - bdata.id = uart->num; +for (i =0 ; i <OMAP_MAX_HSUART_PORTS ; i++) { + bdata.id = i; bdata.flags =0 ; bdata.pads =NULL ; bdata.pads_cnt =0 ;omap_serial_init_port (&bdata); - } }
arch/arm/plat-omap/include/plat/omap-serial.h +18 -3
@@ -56,13 +56,18 @@#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA +#define UART_ERRATA_i202_MDR1_ACCESS BIT(0) +struct omap_uart_port_info {bool dma_enabled;/* To specify DMA Mode */ unsigned int uartclk;/* UART clock rate */ -void __iomem *membase;/* ioremap cookie or NULL */ -resource_size_t mapbase;/* resource base */ -unsigned long irqflags;/* request_irq flags */ upf_t flags;/* UPF_* flags */ +unsigned int errata; +unsigned int console_uart; + +void __iomem *wk_st; +void __iomem *wk_en; +u32 wk_mask; };struct uart_omap_dma {
@@ -100,6 +105,9 @@ struct uart_omap_port {unsigned char mcr;unsigned char fcr;unsigned char efr; +unsigned char dll; +unsigned char dlh; +unsigned char mdr1;int use_dma;/*
@@ -111,6 +119,13 @@ struct uart_omap_port {unsigned char msr_saved_flags;char name[20 ];unsigned long port_activity; +struct timer_list inactivity_timer; +unsigned int errata; +int can_sleep; + +void __iomem *wk_st; +void __iomem *wk_en; + u32 wk_mask; };#endif /* __OMAP_SERIAL_H__ */
Signature · 1 line
1.7.1
PATCH 5/7 Serial: OMAP: add runtime pm support for omap-serial driver
In reply to Govindraj.RAdapts omap-serial driver to use pm_runtime api's.
1.) Populate reg values to uart port which can be used for context restore. 2.) Moved Erratum handling func to driver from serial.c
3.) adding port_enable/disable func to enable/disable given uart port. 4.) using prepare/resume api's to cut and enable back uart func_clks. 5.) using timer to set flag to cut uart clocks based on this flag in
sram_idle path.
--- drivers/tty/serial/omap-serial.c | 304 +++++++++++++++++++++++++++++++++++--- 1 files changed, 283 insertions(+), 21 deletions(-)
drivers/tty/serial/omap-serial.c +283 -21
@@ -33,10 +33,21 @@#include <linux/clk.h> #include <linux/serial_core.h> #include <linux/irq.h> +#include <linux/pm_runtime.h> #include <plat/dma.h> #include <plat/dmtimer.h> #include <plat/omap-serial.h> +#include <plat/serial.h> +#include <plat/omap_device.h> + +#ifdef CONFIG_SERIAL_OMAP_CONSOLE +#define omap_uart_console (port) ((port)->cons && (port)->cons->index == (port)->line) +#else +#define omap_uart_console (port) NULL +#endif + +#define OMAP_UART_CLK_PUT_DELAY (5 * HZ)static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS ];
@@ -44,6 +55,7 @@ static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];static void uart_tx_dma_callback (int lch,u16 ch_status,void *data);static void serial_omap_rx_timeout (unsigned long uart_no);static int serial_omap_start_rxdma (struct uart_omap_port *up); +static void omap_uart_mdr1_errataset (struct uart_omap_port *up);static inline unsigned int serial_in (struct uart_omap_port *up,int offset) {
@@ -90,6 +102,73 @@ serial_omap_get_divisor(struct uart_port *port, unsigned int baud)return port->uartclk/(baud * divisor); } +static void omap_uart_smart_idle (struct uart_omap_port *up) +{ +struct platform_device *pdev = up->pdev; + struct omap_device *od = container_of(pdev, struct omap_device, pdev); + +omap_hwmod_set_slave_idlemode (od->hwmods[0 ],HWMOD_IDLEMODE_SMART ); +} + +static void serial_omap_port_disable (struct uart_omap_port *up) +{ +if (!pm_runtime_suspended (&up->pdev->dev)) { +del_timer (&up->inactivity_timer); +if (omap_uart_console (&up->port)) +console_stop (up->port.cons); + +pm_runtime_put_sync (&up->pdev->dev); + } +} + +static void serial_omap_inactivity_timer (unsigned long uart_no) +{ +struct uart_omap_port *up = ui[uart_no]; + + up->can_sleep =1 ; +omap_uart_smart_idle (up); +} + +static void serial_omap_port_enable (struct uart_omap_port *up) +{ +if (pm_runtime_suspended (&up->pdev->dev)) { +if (omap_uart_console (&up->port)) +console_start (up->port.cons); + +pm_runtime_get_sync (&up->pdev->dev); + } + + up->can_sleep =0 ; +mod_timer (&up->inactivity_timer, jiffies +OMAP_UART_CLK_PUT_DELAY ); +} + +void omap_uart_prepare_idle (int num) +{ +struct uart_omap_port *up = ui[num]; + +if (up && up->can_sleep) +serial_omap_port_disable (up); +} + +void omap_uart_resume_idle (int num) +{ +struct uart_omap_port *up = ui[num]; +struct omap_device *od; +struct platform_device *pdev; + +if (!up) +return ; + + pdev = up->pdev; + od = container_of(pdev, struct omap_device, pdev); + +if (omap_hmwod_pad_wakeup_status (od->hwmods[0 ]) == true) +serial_omap_port_enable (up); + +if (up->wk_st && (__raw_readl (up->wk_st) & up->wk_mask)) +serial_omap_port_enable (up); +} +static void serial_omap_stop_rxdma (struct uart_omap_port *up) {if (up->uart_dma.rx_dma_used) {
@@ -105,6 +184,7 @@ static void serial_omap_enable_ms(struct uart_port *port) {struct uart_omap_port *up = (struct uart_omap_port *)port; +serial_omap_port_enable (up);dev_dbg (up->port.dev,"serial_omap_enable_ms+%d\n" , up->pdev->id); up->ier |=UART_IER_MSI ;serial_out (up,UART_IER , up->ier);
@@ -114,6 +194,7 @@ static void serial_omap_stop_tx(struct uart_port *port) {struct uart_omap_port *up = (struct uart_omap_port *)port; +serial_omap_port_enable (up);if (up->use_dma && up->uart_dma.tx_dma_channel !=OMAP_UART_DMA_CH_FREE ) {/*
@@ -137,6 +218,7 @@ static void serial_omap_stop_rx(struct uart_port *port) {struct uart_omap_port *up = (struct uart_omap_port *)port; +serial_omap_port_enable (up);if (up->use_dma)serial_omap_stop_rxdma (up); up->ier &= ~UART_IER_RLSI ;
@@ -258,6 +340,7 @@ static void serial_omap_start_tx(struct uart_port *port)unsigned int start;int ret =0 ; +serial_omap_port_enable (up);if (!up->use_dma) {serial_omap_enable_ier_thri (up);return ;
@@ -351,6 +434,7 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)unsigned int iir, lsr;unsigned long flags; +serial_omap_port_enable (up); iir =serial_in (up,UART_IIR );if (iir &UART_IIR_NO_INT )return IRQ_NONE ;
@@ -385,6 +469,7 @@ static unsigned int serial_omap_tx_empty(struct uart_port *port)unsigned long flags =0 ;unsigned int ret =0 ; +serial_omap_port_enable (up);dev_dbg (up->port.dev,"serial_omap_tx_empty+%d\n" , up->pdev->id);spin_lock_irqsave (&up->port.lock, flags); ret =serial_in (up,UART_LSR ) &UART_LSR_TEMT ?TIOCSER_TEMT :0 ;
@@ -399,6 +484,7 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port)unsigned char status;unsigned int ret =0 ; +serial_omap_port_enable (up); status =check_modem_status (up);dev_dbg (up->port.dev,"serial_omap_get_mctrl+%d\n" , up->pdev->id);
@@ -419,6 +505,7 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)unsigned char mcr =0 ;dev_dbg (up->port.dev,"serial_omap_set_mctrl+%d\n" , up->pdev->id); +serial_omap_port_enable (up);if (mctrl &TIOCM_RTS ) mcr |=UART_MCR_RTS ;if (mctrl &TIOCM_DTR )
@@ -440,6 +527,7 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state)unsigned long flags =0 ;dev_dbg (up->port.dev,"serial_omap_break_ctl+%d\n" , up->pdev->id); +serial_omap_port_enable (up);spin_lock_irqsave (&up->port.lock, flags);if (break_state ==-1 ) up->lcr |=UART_LCR_SBC ;
@@ -465,6 +553,7 @@ static int serial_omap_startup(struct uart_port *port)dev_dbg (up->port.dev,"serial_omap_startup+%d\n" , up->pdev->id); +serial_omap_port_enable (up);/* * Clear the FIFO buffers and disable them. * (they will be reenabled in set_termios())
@@ -530,6 +619,8 @@ static void serial_omap_shutdown(struct uart_port *port)unsigned long flags =0 ;dev_dbg (up->port.dev,"serial_omap_shutdown+%d\n" , up->pdev->id); + +serial_omap_port_enable (up);/* * Disable interrupts from this port */
@@ -668,6 +759,10 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, baud =uart_get_baud_rate (port, termios, old,0 , port->uartclk/13 ); quot =serial_omap_get_divisor (port, baud); + up->dll = quot &0xff ; + up->dlh = quot >>8 ; + up->mdr1 =UART_OMAP_MDR1_DISABLE ; + up->fcr =UART_FCR_R_TRIG_01 |UART_FCR_T_TRIG_01 |UART_FCR_ENABLE_FIFO ;if (up->use_dma)
@@ -677,6 +772,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,* Ok, we're now changing the port state. Do it with * interrupts disabled. */ +serial_omap_port_enable (up);spin_lock_irqsave (&up->port.lock, flags);/*
@@ -755,8 +851,11 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,serial_out (up,UART_MCR , up->mcr);/* Protocol, Baud Rate, and Interrupt Settings */ +if (up->errata & UART_ERRATA_i202_MDR1_ACCESS) +omap_uart_mdr1_errataset (up); +else +serial_out (up,UART_OMAP_MDR1 , up->mdr1); -serial_out (up,UART_OMAP_MDR1 ,UART_OMAP_MDR1_DISABLE );serial_out (up,UART_LCR ,UART_LCR_CONF_MODE_B ); up->efr =serial_in (up,UART_EFR );
@@ -766,8 +865,8 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,serial_out (up,UART_IER ,0 );serial_out (up,UART_LCR ,UART_LCR_CONF_MODE_B ); -serial_out (up,UART_DLL , quot &0xff );/* LS of divisor */ -serial_out (up,UART_DLM , quot >>8 );/* MS of divisor */ +serial_out (up,UART_DLL , up->dll);/* LS of divisor */ +serial_out (up,UART_DLM , up->dlh);/* MS of divisor */ serial_out (up,UART_LCR ,0 );serial_out (up,UART_IER , up->ier);
@@ -777,9 +876,14 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,serial_out (up,UART_LCR , cval);if (baud >230400 && baud !=3000000 ) -serial_out (up,UART_OMAP_MDR1 ,UART_OMAP_MDR1_13X_MODE ); + up->mdr1 =UART_OMAP_MDR1_13X_MODE ; +else + up->mdr1 =UART_OMAP_MDR1_16X_MODE ; + +if (up->errata & UART_ERRATA_i202_MDR1_ACCESS) +omap_uart_mdr1_errataset (up);else -serial_out (up,UART_OMAP_MDR1 ,UART_OMAP_MDR1_16X_MODE ); +serial_out (up,UART_OMAP_MDR1 , up->mdr1);/* Hardware Flow Control Configuration */
@@ -818,6 +922,8 @@ serial_omap_pm(struct uart_port *port, unsigned int state,unsigned char efr;dev_dbg (up->port.dev,"serial_omap_pm+%d\n" , up->pdev->id); + +serial_omap_port_enable (up);serial_out (up,UART_LCR ,UART_LCR_CONF_MODE_B ); efr =serial_in (up,UART_EFR );serial_out (up,UART_EFR , efr |UART_EFR_ECB );
@@ -827,6 +933,8 @@ serial_omap_pm(struct uart_port *port, unsigned int state,serial_out (up,UART_LCR ,UART_LCR_CONF_MODE_B );serial_out (up,UART_EFR , efr);serial_out (up,UART_LCR ,0 ); +if (state) +serial_omap_port_disable (up); }static void serial_omap_release_port (struct uart_port *port)
@@ -904,6 +1012,8 @@ static inline void wait_for_xmitr(struct uart_omap_port *up)static void serial_omap_poll_put_char (struct uart_port *port,unsigned char ch) {struct uart_omap_port *up = (struct uart_omap_port *)port; + +serial_omap_port_enable (up);wait_for_xmitr (up);serial_out (up,UART_TX , ch); }
@@ -911,8 +1021,10 @@ static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch)static int serial_omap_poll_get_char (struct uart_port *port) {struct uart_omap_port *up = (struct uart_omap_port *)port; -unsigned int status =serial_in (up,UART_LSR ); +unsigned int status; +serial_omap_port_enable (up); + status =serial_in (up,UART_LSR );if (!(status &UART_LSR_DR ))return NO_POLL_CHAR ;
@@ -922,7 +1034,6 @@ static int serial_omap_poll_get_char(struct uart_port *port)#endif /* CONFIG_CONSOLE_POLL */ #ifdef CONFIG_SERIAL_OMAP_CONSOLE -static struct uart_omap_port *serial_omap_console_ports[4 ];static struct uart_driver serial_omap_reg;
@@ -931,6 +1042,7 @@ static void serial_omap_console_putchar(struct uart_port *port, int ch) {struct uart_omap_port *up = (struct uart_omap_port *)port; +serial_omap_port_enable (up);wait_for_xmitr (up);serial_out (up,UART_TX , ch); }
@@ -944,6 +1056,7 @@ serial_omap_console_write(struct console *co, const char *s,unsigned int ier;int locked =1 ; +serial_omap_port_enable (up);local_irq_save (flags);if (up->port.sysrq) locked =0 ;
@@ -1058,22 +1171,25 @@ static struct uart_driver serial_omap_reg = { .cons = OMAP_CONSOLE, }; -static int -serial_omap_suspend (struct platform_device *pdev,pm_message_t state) +static int serial_omap_suspend (struct device *dev) { -struct uart_omap_port *up =platform_get_drvdata (pdev); +struct uart_omap_port *up =dev_get_drvdata (dev); -if (up) +if (up) {uart_suspend_port (&serial_omap_reg, &up->port); +serial_omap_port_disable (up); + } +return 0 ; } -static int serial_omap_resume (struct platform_device *dev) +static int serial_omap_resume (struct device *dev) { -struct uart_omap_port *up =platform_get_drvdata (dev); +struct uart_omap_port *up =dev_get_drvdata (dev);if (up)uart_resume_port (&serial_omap_reg, &up->port); +return 0 ; }
@@ -1221,9 +1337,10 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)static int serial_omap_probe (struct platform_device *pdev) { -struct uart_omap_port *up; +struct uart_omap_port *up =NULL ;struct resource *mem, *irq, *dma_tx, *dma_rx;struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data; +struct omap_device *od;int ret = -ENOSPC ; mem =platform_get_resource (pdev,IORESOURCE_MEM ,0 );
@@ -1273,12 +1390,23 @@ static int serial_omap_probe(struct platform_device *pdev) up->port.ops = &serial_omap_pops; up->port.line = pdev->id; - up->port.membase = omap_up_info->membase; - up->port.mapbase = omap_up_info->mapbase; + up->port.mapbase = mem->start; + up->port.membase =ioremap (mem->start, mem->end - mem->start); + +if (!up->port.membase) { +dev_err (&pdev->dev,"can't ioremap UART\n" ); + ret = -ENOMEM ; + goto err1; + } + up->port.flags = omap_up_info->flags; - up->port.irqflags = omap_up_info->irqflags; up->port.uartclk = omap_up_info->uartclk; up->uart_dma.uart_base = mem->start; + up->errata = omap_up_info->errata; + + up->wk_st = omap_up_info->wk_st; + up->wk_en = omap_up_info->wk_en; + up->wk_mask = omap_up_info->wk_mask;if (omap_up_info->dma_enabled) { up->uart_dma.uart_dma_tx = dma_tx->start;
@@ -1291,19 +1419,35 @@ static int serial_omap_probe(struct platform_device *pdev) up->uart_dma.tx_dma_channel =OMAP_UART_DMA_CH_FREE ; up->uart_dma.rx_dma_channel =OMAP_UART_DMA_CH_FREE ; } +init_timer (&(up->inactivity_timer)); + up->inactivity_timer.function = serial_omap_inactivity_timer; + up->inactivity_timer.data = up->pdev->id; + +pm_runtime_enable (&pdev->dev); +pm_runtime_irq_safe (&pdev->dev); + +if (omap_up_info->console_uart) { + od = container_of(pdev, struct omap_device, pdev); +omap_hwmod_idle (od->hwmods[0 ]); +serial_omap_port_enable (up); + } ui[pdev->id] = up;serial_omap_add_console_port (up); ret =uart_add_one_port (&serial_omap_reg, &up->port);if (ret !=0 ) - goto do_release_region; + goto err1; +dev_set_drvdata (&pdev->dev, up);platform_set_drvdata (pdev, up); +return 0 ; err:dev_err (&pdev->dev,"[UART%d]: failure [%s]: %d\n" , pdev->id, __func__, ret); +err1: +kfree (up); do_release_region:release_mem_region (mem->start, (mem->end - mem->start) +1 );return ret;
@@ -1315,20 +1459,138 @@ static int serial_omap_remove(struct platform_device *dev)platform_set_drvdata (dev,NULL );if (up) { +pm_runtime_disable (&up->pdev->dev);uart_remove_one_port (&serial_omap_reg, &up->port);kfree (up); }return 0 ; } +/* +* Work Around for Errata i202 (3430 - 1.12, 3630 - 1.6) +* The access to uart register after MDR1 Access +* causes UART to corrupt data. +* +* Need a delay = +* 5 L4 clock cycles + 5 UART functional clock cycle (@48MHz = ~0.2uS) +* give 10 times as much +*/ +static void omap_uart_mdr1_errataset (struct uart_omap_port *up) +{ +u8 timeout =255 ; + +serial_out (up,UART_OMAP_MDR1 , up->mdr1); +udelay (2 ); +serial_out (up,UART_FCR , up->fcr |UART_FCR_CLEAR_XMIT | +UART_FCR_CLEAR_RCVR ); +/* +* Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and +* TX_FIFO_E bit is 1. +*/ +while (UART_LSR_THRE != (serial_in (up,UART_LSR ) & + (UART_LSR_THRE |UART_LSR_DR ))) { + timeout--; +if (!timeout) { +/* Should *never* happen. we warn and carry on */ +dev_crit (&up->pdev->dev,"Errata i202: timedout %x\n" , +serial_in (up,UART_LSR )); +break ; + } +udelay (1 ); + } +} + +static void omap_uart_restore_context (struct uart_omap_port *up) +{ +u16 efr =0 ; + +if (up->errata & UART_ERRATA_i202_MDR1_ACCESS) +omap_uart_mdr1_errataset (up); +else +serial_out (up,UART_OMAP_MDR1 , up->mdr1); +serial_out (up,UART_LCR ,0xBF );/* Config B mode */ + efr =serial_in (up,UART_EFR ); +serial_out (up,UART_EFR ,UART_EFR_ECB ); +serial_out (up,UART_LCR ,0x0 );/* Operational mode */ +serial_out (up,UART_IER ,0x0 ); +serial_out (up,UART_LCR ,0xBF );/* Config B mode */ +serial_out (up,UART_DLL , up->dll); +serial_out (up,UART_DLM , up->dlh); +serial_out (up,UART_LCR ,0x0 );/* Operational mode */ +serial_out (up,UART_IER , up->ier); +serial_out (up,UART_FCR , up->fcr); +serial_out (up,UART_LCR ,0x80 ); +serial_out (up,UART_MCR , up->mcr); +serial_out (up,UART_LCR ,0xBF );/* Config B mode */ +serial_out (up,UART_EFR , efr); +serial_out (up,UART_LCR ,UART_LCR_WLEN8 ); +if (up->errata & UART_ERRATA_i202_MDR1_ACCESS) +omap_uart_mdr1_errataset (up); +else +/* UART 16x mode */ +serial_out (up,UART_OMAP_MDR1 , up->mdr1); +} + +static void omap_uart_enable_wakeup (struct uart_omap_port *up) +{ +/* Set wake-enable bit */ +if (up->wk_en && up->wk_mask) { +u32 v =__raw_readl (up->wk_en); + v |= up->wk_mask; +__raw_writel (v, up->wk_en); + } +} + +static void omap_uart_disable_wakeup (struct uart_omap_port *up) +{ +/* Clear wake-enable bit */ +if (up->wk_en && up->wk_mask) { +u32 v =__raw_readl (up->wk_en); + v &= ~up->wk_mask; +__raw_writel (v, up->wk_en); + } +} + +static int omap_serial_runtime_suspend (struct device *dev) +{ +struct uart_omap_port *up =dev_get_drvdata (dev); + +if (!up) + goto done; + +if (device_may_wakeup (&up->pdev->dev)) +omap_uart_enable_wakeup (up); +else +omap_uart_disable_wakeup (up); +done: +return 0 ; +} + +static int omap_serial_runtime_resume (struct device *dev) +{ +struct uart_omap_port *up =dev_get_drvdata (dev); + +if (!up) + goto done; + +omap_uart_restore_context (up); +done: +return 0 ; +} + +static const struct dev_pm_ops omap_serial_dev_pm_ops = { + .suspend = serial_omap_suspend, + .resume = serial_omap_resume, + .runtime_suspend = omap_serial_runtime_suspend, + .runtime_resume = omap_serial_runtime_resume, +}; +static struct platform_driver serial_omap_driver = { .probe = serial_omap_probe, .remove = serial_omap_remove, - - .suspend = serial_omap_suspend, - .resume = serial_omap_resume, .driver = { .name =DRIVER_NAME , + .pm = &omap_serial_dev_pm_ops, }, };
Signature · 1 line
1.7.1
PATCH 5/7 Serial: OMAP: add runtime pm support for omap-serial driver
Quoted 8 lines · Govindraj.R
Adapts omap-serial driver to use
pm_runtimeapi's.1.) Populate reg values to uart port which can be used for context restore. 2.) Moved Erratum handling func to driver from
serial.c
3.) adding port_enable/disable func to enable/disable given uart port. 4.) using prepare/resume api's to cut and enable back uartfunc_clks. 5.) using timer to set flag to cut uart clocks based on this flag in
sram_idlepath.
At least the errata handling should be in a separate patch as it's not related to runtime PM.
Also, please be sure to test building this driver as a module. Because of direct access to hwmod in this patch, it will currently build as a module.
Quoted 51 lines
Signed-off-by Govindraj.R <[email protected]>--- drivers/tty/serial/omap-serial.c | 304 +++++++++++++++++++++++++++++++++++--- 1 files changed, 283 insertions(+), 21 deletions(-)drivers/tty/serial/omap-serial.c +20
-0@@ -33,10 +33,21 @@#include <linux/clk.h> #include <linux/serial_core.h> #include <linux/irq.h> +#include <linux/pm_runtime.h> #include <plat/dma.h> #include <plat/dmtimer.h> #include <plat/omap-serial.h> +#include <plat/serial.h> +#include <plat/omap_device.h> + +#ifdef CONFIG_SERIAL_OMAP_CONSOLE +#define omap_uart_console (port) ((port)->cons && (port)->cons->index == (port)->line) +#else +#define omap_uart_console (port) NULL +#endif + +#define OMAP_UART_CLK_PUT_DELAY (5 * HZ)static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS ];@@ -44,6 +55,7 @@ static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];static void uart_tx_dma_callback (int lch,u16 ch_status,void *data);static void serial_omap_rx_timeout (unsigned long uart_no);static int serial_omap_start_rxdma (struct uart_omap_port *up); +static void omap_uart_mdr1_errataset (struct uart_omap_port *up);static inline unsigned int serial_in (struct uart_omap_port *up,int offset) {@@ -90,6 +102,73 @@ serial_omap_get_divisor(struct uart_port *port, unsigned int baud)return port->uartclk/(baud * divisor); } +static void omap_uart_smart_idle (struct uart_omap_port *up) +{ +struct platform_device *pdev = up->pdev; + struct omap_device *od = container_of(pdev, struct omap_device, pdev); + +omap_hwmod_set_slave_idlemode (od->hwmods[0 ],HWMOD_IDLEMODE_SMART ); +} +
drivers/tty/serial/omap-serial.c serial_omap_get_divisor(struct uart_port *port, unsigned int baud) · line 122
Quoted 10 lines
drivers/tty/serial/omap-serial.c +10
-0+static void serial_omap_port_disable (struct uart_omap_port *up) +{ +if (!pm_runtime_suspended (&up->pdev->dev)) { +del_timer (&up->inactivity_timer); +if (omap_uart_console (&up->port)) +console_stop (up->port.cons); + +pm_runtime_put_sync (&up->pdev->dev); + } +}
This function should not be needed.
The timer should be replaced by the auto-suspend feature of runtime PM.
Instead of calling omap_port_disable() callers should call pm_runtime_put_autosuspend(), and the console_stop() should be part of the ->runtime_suspend() callback.
Also, why do you check for pm_runtime_suspended()? Just call it for every time and we get runtime PM use-counting and statistics for free and the ->runtime_suspend() callback will be called when the usecount goes to zero.
drivers/tty/serial/omap-serial.c serial_omap_get_divisor(struct uart_port *port, unsigned int baud) · line 130
Quoted 7 lines
drivers/tty/serial/omap-serial.c +7
-0+static void serial_omap_inactivity_timer (unsigned long uart_no) +{ +struct uart_omap_port *up = ui[uart_no]; + + up->can_sleep =1 ; +omap_uart_smart_idle (up); +}
This will not be needed if using the autosuspend feature.
drivers/tty/serial/omap-serial.c serial_omap_get_divisor(struct uart_port *port, unsigned int baud) · line 143
Quoted 12 lines
drivers/tty/serial/omap-serial.c +12
-0+static void serial_omap_port_enable (struct uart_omap_port *up) +{ +if (pm_runtime_suspended (&up->pdev->dev)) { +if (omap_uart_console (&up->port)) +console_start (up->port.cons); + +pm_runtime_get_sync (&up->pdev->dev); + } + + up->can_sleep =0 ; +mod_timer (&up->inactivity_timer, jiffies +OMAP_UART_CLK_PUT_DELAY ); +}
Similarily to the disable side, callers of this function should call pm_runtime_get_sync() and the console_start() should be in the ->runtime_resume method.
Again, no need to check pm_runtime_suspended() since the runtime PM core does usecounting already.
drivers/tty/serial/omap-serial.c serial_omap_get_divisor(struct uart_port *port, unsigned int baud) · line 150
Quoted 6 lines
drivers/tty/serial/omap-serial.c +6
-0+void omap_uart_prepare_idle (int num) +{ +struct uart_omap_port *up = ui[num]; + +if (up && up->can_sleep) +serial_omap_port_disable (up);
pm_runtime_put_autosuspend()
drivers/tty/serial/omap-serial.c serial_omap_get_divisor(struct uart_port *port, unsigned int baud) · line 163
Quoted 13 lines
drivers/tty/serial/omap-serial.c +13
-0+} + +void omap_uart_resume_idle (int num) +{ +struct uart_omap_port *up = ui[num]; +struct omap_device *od; +struct platform_device *pdev; + +if (!up) +return ; + + pdev = up->pdev; + od = container_of(pdev, struct omap_device, pdev);
od = to_omap_device(pdev);
drivers/tty/serial/omap-serial.c serial_omap_get_divisor(struct uart_port *port, unsigned int baud) · line 170
Quoted 6 lines
drivers/tty/serial/omap-serial.c +6
-0+if (omap_hmwod_pad_wakeup_status (od->hwmods[0 ]) == true) +serial_omap_port_enable (up); + +if (up->wk_st && (__raw_readl (up->wk_st) & up->wk_mask)) +serial_omap_port_enable (up); +}
c.f. comments from PATCH 2/7
Also, direct hwmod access and PRCM accesses do not belong in drivers.
Until it is understood why wakeups are not working, these hacks should stay in mach-omap2/serial.c
drivers/tty/serial/omap-serial.c static void serial_omap_enable_ms(struct uart_port *port) · line 187
Quoted 8 lines
drivers/tty/serial/omap-serial.c +1
-0static void serial_omap_stop_rxdma (struct uart_omap_port *up) {if (up->uart_dma.rx_dma_used) {@@ -105,6 +184,7 @@ static void serial_omap_enable_ms(struct uart_port *port) {struct uart_omap_port *up = (struct uart_omap_port *)port; +serial_omap_port_enable (up);
pm_runtime_put_autosuspend()
similarily for all calls to omap_port_enable()
Quoted 154 lines
drivers/tty/serial/omap-serial.c +31
-5dev_dbg (up->port.dev,"serial_omap_enable_ms+%d\n" , up->pdev->id); up->ier |=UART_IER_MSI ;serial_out (up,UART_IER , up->ier);@@ -114,6 +194,7 @@ static void serial_omap_stop_tx(struct uart_port *port) {struct uart_omap_port *up = (struct uart_omap_port *)port; +serial_omap_port_enable (up);if (up->use_dma && up->uart_dma.tx_dma_channel !=OMAP_UART_DMA_CH_FREE ) {/* @@ -137,6 +218,7 @@ static void serial_omap_stop_rx(struct uart_port *port) {struct uart_omap_port *up = (struct uart_omap_port *)port; +serial_omap_port_enable (up);if (up->use_dma)serial_omap_stop_rxdma (up); up->ier &= ~UART_IER_RLSI ;@@ -258,6 +340,7 @@ static void serial_omap_start_tx(struct uart_port *port)unsigned int start;int ret =0 ; +serial_omap_port_enable (up);if (!up->use_dma) {serial_omap_enable_ier_thri (up);return ;@@ -351,6 +434,7 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)unsigned int iir, lsr;unsigned long flags; +serial_omap_port_enable (up); iir =serial_in (up,UART_IIR );if (iir &UART_IIR_NO_INT )return IRQ_NONE ;@@ -385,6 +469,7 @@ static unsigned int serial_omap_tx_empty(struct uart_port *port)unsigned long flags =0 ;unsigned int ret =0 ; +serial_omap_port_enable (up);dev_dbg (up->port.dev,"serial_omap_tx_empty+%d\n" , up->pdev->id);spin_lock_irqsave (&up->port.lock, flags); ret =serial_in (up,UART_LSR ) &UART_LSR_TEMT ?TIOCSER_TEMT :0 ;@@ -399,6 +484,7 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port)unsigned char status;unsigned int ret =0 ; +serial_omap_port_enable (up); status =check_modem_status (up);dev_dbg (up->port.dev,"serial_omap_get_mctrl+%d\n" , up->pdev->id);@@ -419,6 +505,7 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)unsigned char mcr =0 ;dev_dbg (up->port.dev,"serial_omap_set_mctrl+%d\n" , up->pdev->id); +serial_omap_port_enable (up);if (mctrl &TIOCM_RTS ) mcr |=UART_MCR_RTS ;if (mctrl &TIOCM_DTR )@@ -440,6 +527,7 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state)unsigned long flags =0 ;dev_dbg (up->port.dev,"serial_omap_break_ctl+%d\n" , up->pdev->id); +serial_omap_port_enable (up);spin_lock_irqsave (&up->port.lock, flags);if (break_state ==-1 ) up->lcr |=UART_LCR_SBC ;@@ -465,6 +553,7 @@ static int serial_omap_startup(struct uart_port *port)dev_dbg (up->port.dev,"serial_omap_startup+%d\n" , up->pdev->id); +serial_omap_port_enable (up);/* * Clear the FIFO buffers and disable them. * (they will be reenabled in set_termios()) @@ -530,6 +619,8 @@ static void serial_omap_shutdown(struct uart_port *port)unsigned long flags =0 ;dev_dbg (up->port.dev,"serial_omap_shutdown+%d\n" , up->pdev->id); + +serial_omap_port_enable (up);/* * Disable interrupts from this port */ @@ -668,6 +759,10 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, baud =uart_get_baud_rate (port, termios, old,0 , port->uartclk/13 ); quot =serial_omap_get_divisor (port, baud); + up->dll = quot &0xff ; + up->dlh = quot >>8 ; + up->mdr1 =UART_OMAP_MDR1_DISABLE ; + up->fcr =UART_FCR_R_TRIG_01 |UART_FCR_T_TRIG_01 |UART_FCR_ENABLE_FIFO ;if (up->use_dma)@@ -677,6 +772,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,* Ok, we're now changing the port state. Do it with * interrupts disabled. */ +serial_omap_port_enable (up);spin_lock_irqsave (&up->port.lock, flags);/* @@ -755,8 +851,11 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,serial_out (up,UART_MCR , up->mcr);/* Protocol, Baud Rate, and Interrupt Settings */ +if (up->errata & UART_ERRATA_i202_MDR1_ACCESS) +omap_uart_mdr1_errataset (up); +else +serial_out (up,UART_OMAP_MDR1 , up->mdr1); -serial_out (up,UART_OMAP_MDR1 ,UART_OMAP_MDR1_DISABLE );serial_out (up,UART_LCR ,UART_LCR_CONF_MODE_B ); up->efr =serial_in (up,UART_EFR );@@ -766,8 +865,8 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,serial_out (up,UART_IER ,0 );serial_out (up,UART_LCR ,UART_LCR_CONF_MODE_B ); -serial_out (up,UART_DLL , quot &0xff );/* LS of divisor */ -serial_out (up,UART_DLM , quot >>8 );/* MS of divisor */ +serial_out (up,UART_DLL , up->dll);/* LS of divisor */ +serial_out (up,UART_DLM , up->dlh);/* MS of divisor */ serial_out (up,UART_LCR ,0 );serial_out (up,UART_IER , up->ier);@@ -777,9 +876,14 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,serial_out (up,UART_LCR , cval);if (baud >230400 && baud !=3000000 ) -serial_out (up,UART_OMAP_MDR1 ,UART_OMAP_MDR1_13X_MODE ); + up->mdr1 =UART_OMAP_MDR1_13X_MODE ; +else + up->mdr1 =UART_OMAP_MDR1_16X_MODE ; + +if (up->errata & UART_ERRATA_i202_MDR1_ACCESS) +omap_uart_mdr1_errataset (up);else -serial_out (up,UART_OMAP_MDR1 ,UART_OMAP_MDR1_16X_MODE ); +serial_out (up,UART_OMAP_MDR1 , up->mdr1);/* Hardware Flow Control Configuration */ @@ -818,6 +922,8 @@ serial_omap_pm(struct uart_port *port, unsigned int state,unsigned char efr;dev_dbg (up->port.dev,"serial_omap_pm+%d\n" , up->pdev->id); + +serial_omap_port_enable (up);serial_out (up,UART_LCR ,UART_LCR_CONF_MODE_B ); efr =serial_in (up,UART_EFR );serial_out (up,UART_EFR , efr |UART_EFR_ECB );
drivers/tty/serial/omap-serial.c serial_omap_pm(struct uart_port *port, unsigned int state, · line 937
Quoted 5 lines
drivers/tty/serial/omap-serial.c +2
-0@@ -827,6 +933,8 @@ serial_omap_pm(struct uart_port *port, unsigned int state,serial_out (up,UART_LCR ,UART_LCR_CONF_MODE_B );serial_out (up,UART_EFR , efr);serial_out (up,UART_LCR ,0 ); +if (state) +serial_omap_port_disable (up);
FYI... this change doesn't apply when basing on the commit you mentioned in PATCH 0/7.
Quoted 120 lines
drivers/tty/serial/omap-serial.c +32
-12}static void serial_omap_release_port (struct uart_port *port)@@ -904,6 +1012,8 @@ static inline void wait_for_xmitr(struct uart_omap_port *up)static void serial_omap_poll_put_char (struct uart_port *port,unsigned char ch) {struct uart_omap_port *up = (struct uart_omap_port *)port; + +serial_omap_port_enable (up);wait_for_xmitr (up);serial_out (up,UART_TX , ch); }@@ -911,8 +1021,10 @@ static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch)static int serial_omap_poll_get_char (struct uart_port *port) {struct uart_omap_port *up = (struct uart_omap_port *)port; -unsigned int status =serial_in (up,UART_LSR ); +unsigned int status; +serial_omap_port_enable (up); + status =serial_in (up,UART_LSR );if (!(status &UART_LSR_DR ))return NO_POLL_CHAR ;@@ -922,7 +1034,6 @@ static int serial_omap_poll_get_char(struct uart_port *port)#endif /* CONFIG_CONSOLE_POLL */ #ifdef CONFIG_SERIAL_OMAP_CONSOLE -static struct uart_omap_port *serial_omap_console_ports[4 ];static struct uart_driver serial_omap_reg;@@ -931,6 +1042,7 @@ static void serial_omap_console_putchar(struct uart_port *port, int ch) {struct uart_omap_port *up = (struct uart_omap_port *)port; +serial_omap_port_enable (up);wait_for_xmitr (up);serial_out (up,UART_TX , ch); }@@ -944,6 +1056,7 @@ serial_omap_console_write(struct console *co, const char *s,unsigned int ier;int locked =1 ; +serial_omap_port_enable (up);local_irq_save (flags);if (up->port.sysrq) locked =0 ;@@ -1058,22 +1171,25 @@ static struct uart_driver serial_omap_reg = { .cons = OMAP_CONSOLE, }; -static int -serial_omap_suspend (struct platform_device *pdev,pm_message_t state) +static int serial_omap_suspend (struct device *dev) { -struct uart_omap_port *up =platform_get_drvdata (pdev); +struct uart_omap_port *up =dev_get_drvdata (dev); -if (up) +if (up) {uart_suspend_port (&serial_omap_reg, &up->port); +serial_omap_port_disable (up); + } +return 0 ; } -static int serial_omap_resume (struct platform_device *dev) +static int serial_omap_resume (struct device *dev) { -struct uart_omap_port *up =platform_get_drvdata (dev); +struct uart_omap_port *up =dev_get_drvdata (dev);if (up)uart_resume_port (&serial_omap_reg, &up->port); +return 0 ; }@@ -1221,9 +1337,10 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)static int serial_omap_probe (struct platform_device *pdev) { -struct uart_omap_port *up; +struct uart_omap_port *up =NULL ;struct resource *mem, *irq, *dma_tx, *dma_rx;struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data; +struct omap_device *od;int ret = -ENOSPC ; mem =platform_get_resource (pdev,IORESOURCE_MEM ,0 );@@ -1273,12 +1390,23 @@ static int serial_omap_probe(struct platform_device *pdev) up->port.ops = &serial_omap_pops; up->port.line = pdev->id; - up->port.membase = omap_up_info->membase; - up->port.mapbase = omap_up_info->mapbase; + up->port.mapbase = mem->start; + up->port.membase =ioremap (mem->start, mem->end - mem->start); + +if (!up->port.membase) { +dev_err (&pdev->dev,"can't ioremap UART\n" ); + ret = -ENOMEM ; + goto err1; + } + up->port.flags = omap_up_info->flags; - up->port.irqflags = omap_up_info->irqflags; up->port.uartclk = omap_up_info->uartclk; up->uart_dma.uart_base = mem->start; + up->errata = omap_up_info->errata; + + up->wk_st = omap_up_info->wk_st; + up->wk_en = omap_up_info->wk_en; + up->wk_mask = omap_up_info->wk_mask;if (omap_up_info->dma_enabled) { up->uart_dma.uart_dma_tx = dma_tx->start;
drivers/tty/serial/omap-serial.c static int serial_omap_probe(struct platform_device *pdev) · line 1427
Quoted 9 lines
drivers/tty/serial/omap-serial.c +6
-0@@ -1291,19 +1419,35 @@ static int serial_omap_probe(struct platform_device *pdev) up->uart_dma.tx_dma_channel =OMAP_UART_DMA_CH_FREE ; up->uart_dma.rx_dma_channel =OMAP_UART_DMA_CH_FREE ; } +init_timer (&(up->inactivity_timer)); + up->inactivity_timer.function = serial_omap_inactivity_timer; + up->inactivity_timer.data = up->pdev->id; + +pm_runtime_enable (&pdev->dev); +pm_runtime_irq_safe (&pdev->dev);
The changelog should describe why the IRQ-safe mode is needed.
drivers/tty/serial/omap-serial.c static int serial_omap_probe(struct platform_device *pdev) · line 1431
Quoted 3 lines
drivers/tty/serial/omap-serial.c +3
-0+if (omap_up_info->console_uart) { + od = container_of(pdev, struct omap_device, pdev); +omap_hwmod_idle (od->hwmods[0 ]);
This was only in mach-omap2/serial.c because the early UART probing was accessing registers. With this driver becoming runtime PM aware, this hack should not be needed, and the
oh->flags |= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET;
should be removed from mach-omap2/serial.c
Quoted 108 lines
drivers/tty/serial/omap-serial.c +82
-1+serial_omap_port_enable (up); + } ui[pdev->id] = up;serial_omap_add_console_port (up); ret =uart_add_one_port (&serial_omap_reg, &up->port);if (ret !=0 ) - goto do_release_region; + goto err1; +dev_set_drvdata (&pdev->dev, up);platform_set_drvdata (pdev, up); +return 0 ; err:dev_err (&pdev->dev,"[UART%d]: failure [%s]: %d\n" , pdev->id, __func__, ret); +err1: +kfree (up); do_release_region:release_mem_region (mem->start, (mem->end - mem->start) +1 );return ret;@@ -1315,20 +1459,138 @@ static int serial_omap_remove(struct platform_device *dev)platform_set_drvdata (dev,NULL );if (up) { +pm_runtime_disable (&up->pdev->dev);uart_remove_one_port (&serial_omap_reg, &up->port);kfree (up); }return 0 ; } +/* +* Work Around for Errata i202 (3430 - 1.12, 3630 - 1.6) +* The access to uart register after MDR1 Access +* causes UART to corrupt data. +* +* Need a delay = +* 5 L4 clock cycles + 5 UART functional clock cycle (@48MHz = ~0.2uS) +* give 10 times as much +*/ +static void omap_uart_mdr1_errataset (struct uart_omap_port *up) +{ +u8 timeout =255 ; + +serial_out (up,UART_OMAP_MDR1 , up->mdr1); +udelay (2 ); +serial_out (up,UART_FCR , up->fcr |UART_FCR_CLEAR_XMIT | +UART_FCR_CLEAR_RCVR ); +/* +* Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and +* TX_FIFO_E bit is 1. +*/ +while (UART_LSR_THRE != (serial_in (up,UART_LSR ) & + (UART_LSR_THRE |UART_LSR_DR ))) { + timeout--; +if (!timeout) { +/* Should *never* happen. we warn and carry on */ +dev_crit (&up->pdev->dev,"Errata i202: timedout %x\n" , +serial_in (up,UART_LSR )); +break ; + } +udelay (1 ); + } +} + +static void omap_uart_restore_context (struct uart_omap_port *up) +{ +u16 efr =0 ; + +if (up->errata & UART_ERRATA_i202_MDR1_ACCESS) +omap_uart_mdr1_errataset (up); +else +serial_out (up,UART_OMAP_MDR1 , up->mdr1); +serial_out (up,UART_LCR ,0xBF );/* Config B mode */ + efr =serial_in (up,UART_EFR ); +serial_out (up,UART_EFR ,UART_EFR_ECB ); +serial_out (up,UART_LCR ,0x0 );/* Operational mode */ +serial_out (up,UART_IER ,0x0 ); +serial_out (up,UART_LCR ,0xBF );/* Config B mode */ +serial_out (up,UART_DLL , up->dll); +serial_out (up,UART_DLM , up->dlh); +serial_out (up,UART_LCR ,0x0 );/* Operational mode */ +serial_out (up,UART_IER , up->ier); +serial_out (up,UART_FCR , up->fcr); +serial_out (up,UART_LCR ,0x80 ); +serial_out (up,UART_MCR , up->mcr); +serial_out (up,UART_LCR ,0xBF );/* Config B mode */ +serial_out (up,UART_EFR , efr); +serial_out (up,UART_LCR ,UART_LCR_WLEN8 ); +if (up->errata & UART_ERRATA_i202_MDR1_ACCESS) +omap_uart_mdr1_errataset (up); +else +/* UART 16x mode */ +serial_out (up,UART_OMAP_MDR1 , up->mdr1); +} + +static void omap_uart_enable_wakeup (struct uart_omap_port *up) +{ +/* Set wake-enable bit */ +if (up->wk_en && up->wk_mask) { +u32 v =__raw_readl (up->wk_en); + v |= up->wk_mask; +__raw_writel (v, up->wk_en); + } +}
drivers/tty/serial/omap-serial.c static int serial_omap_remove(struct platform_device *dev) · line 1552
Quoted 10 lines
drivers/tty/serial/omap-serial.c +10
-0+ +static void omap_uart_disable_wakeup (struct uart_omap_port *up) +{ +/* Clear wake-enable bit */ +if (up->wk_en && up->wk_mask) { +u32 v =__raw_readl (up->wk_en); + v &= ~up->wk_mask; +__raw_writel (v, up->wk_en); + } +}
Again, driver should not be doing direct PRCM accesses here.
For now, how about leaving these also in mach-omap2/serial.c and calling them via pdata function pointers:
if (pdata->enable_wakeup)
pdata->enable_wakeup()
Quoted 35 lines
drivers/tty/serial/omap-serial.c +34
-0+static int omap_serial_runtime_suspend (struct device *dev) +{ +struct uart_omap_port *up =dev_get_drvdata (dev); + +if (!up) + goto done; + +if (device_may_wakeup (&up->pdev->dev)) +omap_uart_enable_wakeup (up); +else +omap_uart_disable_wakeup (up); +done: +return 0 ; +} + +static int omap_serial_runtime_resume (struct device *dev) +{ +struct uart_omap_port *up =dev_get_drvdata (dev); + +if (!up) + goto done; + +omap_uart_restore_context (up); +done: +return 0 ; +} + +static const struct dev_pm_ops omap_serial_dev_pm_ops = { + .suspend = serial_omap_suspend, + .resume = serial_omap_resume, + .runtime_suspend = omap_serial_runtime_suspend, + .runtime_resume = omap_serial_runtime_resume, +}; +static struct platform_driver serial_omap_driver = {
drivers/tty/serial/omap-serial.c static int serial_omap_remove(struct platform_device *dev) · line 1595
Quoted 10 lines
drivers/tty/serial/omap-serial.c +1
-3.probe = serial_omap_probe, .remove = serial_omap_remove, - - .suspend = serial_omap_suspend, - .resume = serial_omap_resume, .driver = { .name = DRIVER_NAME, + .pm = &omap_serial_dev_pm_ops, }, };
Kevin
PATCH 5/7 Serial: OMAP: add runtime pm support for omap-serial driver
Quoted 11 lines · Kevin Hilman
Quoted 8 lines · Govindraj.R
Adapts omap-serial driver to use
pm_runtimeapi's.1.) Populate reg values to uart port which can be used for context restore. 2.) Moved Erratum handling func to driver from
serial.c
3.) adding port_enable/disable func to enable/disable given uart port. 4.) using prepare/resume api's to cut and enable back uartfunc_clks. 5.) using timer to set flag to cut uart clocks based on this flag in ? ?sram_idlepath.
Quoted 3 lines
At least the errata handling should be in a separate patch as it's not related to runtime PM.
ok. will move to separate patch
Quoted 3 lines
Also, please be sure to test building this driver as a module. ?Because of direct access to hwmod in this patch, it will currently build as a module.
yes will check this out. I can check this only
on zoom board I think as most of other boards
seem to use omap-uart as console uart.
Quoted 64 lines
Quoted 51 lines
Signed-off-by Govindraj.R <[email protected]>---
?drivers/tty/serial/omap-serial.c | ?304 +++++++++++++++++++++++++++++++++++--- ?1 files changed, 283 insertions(+), 21 deletions(-)drivers/tty/serial/omap-serial.c +0
-0@@ -33,10 +33,21 @@?#include <
linux/clk.h>
?#include <linux/serial_core.h>
?#include <linux/irq.h>
+#include <linux/pm_runtime.h>?#include <
plat/dma.h>
?#include <plat/dmtimer.h>
?#include <plat/omap-serial.h>drivers/tty/serial/omap-serial.c +10
-0+#include <plat/serial.h> +#include <plat/omap_device.h> + +#ifdef CONFIG_SERIAL_OMAP_CONSOLE +#define omap_uart_console (port) ((port)->cons && (port)->cons->index == (port)->line) +#else +#define omap_uart_console (port) ? ? ?NULL +#endif + +#define OMAP_UART_CLK_PUT_DELAY (5 * HZ)?static struct
uart_omap_port*ui[OMAP_MAX_HSUART_PORTS];drivers/tty/serial/omap-serial.c +9
-0@@ -44,6 +55,7 @@ static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS]; ?static void uart_tx_dma_callback(int lch, u16 ch_status, void *data); ?static void serial_omap_rx_timeout(unsigned long uart_no); ?static int serial_omap_start_rxdma(struct uart_omap_port *up); +static void omap_uart_mdr1_errataset (struct uart_omap_port *up); ?static inline unsigned int serial_in(struct uart_omap_port *up, int offset) ?{@@ -90,6 +102,73 @@ serial_omap_get_divisor(struct uart_port *port, unsigned int baud) ? ? ? return port->uartclk/(baud * divisor); ?} +static void omap_uart_smart_idle (struct uart_omap_port *up) +{ + ? ? struct platform_device *pdev = up->pdev; + ? ? struct omap_device *od = container_of(pdev, struct omap_device, pdev); + + ? ? omap_hwmod_set_slave_idlemode(od->hwmods[0], HWMOD_IDLEMODE_SMART); +} +drivers/tty/serial/omap-serial.c serial_omap_get_divisor(struct uart_port *port, unsigned int baud) · line 122
Quoted 10 lines
drivers/tty/serial/omap-serial.c +10
-0+static void serial_omap_port_disable (struct uart_omap_port *up) +{ + ? ? if (!pm_runtime_suspended(&up->pdev->dev)) { + ? ? ? ? ? ? del_timer(&up->inactivity_timer); + ? ? ? ? ? ? if (omap_uart_console(&up->port)) + ? ? ? ? ? ? ? ? ? ? console_stop(up->port.cons); + + ? ? ? ? ? ? pm_runtime_put_sync(&up->pdev->dev); + ? ? } +}This function should not be needed.
Quoted 1 line
The timer should be replaced by the auto-suspend feature of runtime PM.
If I use autosuspend based on timer runtime framework will disable clocks based on autosuspend timeout.
But if I cut clocks outside sram idle path module level wakeup will not work. if I cut func clocks outside prepare for idle wake_up is a problem. So I am going with existing model where we are cutting clocks in prepare idle and enabling the clock back in resume_idle based on wakeup event as any other combination doesn't seem to work.
[As stated in other thread to reproduce the issue with module level wakeup]
Even with existing framework if I try to experiment by cutting clocks after uart timeout in allow_sleep func, module level wakeup doesn't seem to happen.
Quoted 10 lines
Instead of calling
omap_port_disable()callers should callpm_runtime_put_autosuspend(), and theconsole_stop()should be part of the ->runtime_suspend() callback.Also, why do you check for
pm_runtime_suspended()? ?Just call it for every time and we get runtime PM use-counting and statistics for free and the ->runtime_suspend() callback will be called when the usecount goes to zero.
Yes correct, but I can't balance the put_sync and get_sync as said above. I can call put_sync only once in prepare_idle to cut clocks. But having put_sync outside prepare_idle, if clocks are cut module level wakeup doesn't seem to happen.
Quoted 9 lines
drivers/tty/serial/omap-serial.c serial_omap_get_divisor(struct uart_port *port, unsigned int baud) · line 130
Quoted 7 lines
drivers/tty/serial/omap-serial.c +7
-0+static void serial_omap_inactivity_timer (unsigned long uart_no) +{ + ? ? struct uart_omap_port *up = ui[uart_no]; + + ? ? up->can_sleep = 1; + ? ? omap_uart_smart_idle(up); +}This will not be needed if using the autosuspend feature.
Using autosuspend, module level wakeup will not happen since autosuspend cuts clocks outside prepare_idle based on autosuspend timeout.
Quoted 17 lines
drivers/tty/serial/omap-serial.c serial_omap_get_divisor(struct uart_port *port, unsigned int baud) · line 141
Quoted 13 lines
drivers/tty/serial/omap-serial.c +12
-0+static void serial_omap_port_enable (struct uart_omap_port *up) +{ + ? ? if (pm_runtime_suspended(&up->pdev->dev)) { + ? ? ? ? ? ? if (omap_uart_console(&up->port)) + ? ? ? ? ? ? ? ? ? ? console_start(up->port.cons); + + ? ? ? ? ? ? pm_runtime_get_sync(&up->pdev->dev); + ? ? } + + ? ? up->can_sleep = 0; + ? ? mod_timer(&up->inactivity_timer, jiffies + OMAP_UART_CLK_PUT_DELAY); +}Similarily to the disable side, callers of this function should call
pm_runtime_get_sync()and theconsole_start()should be in the ->runtime_resume method.
Agree, will move console_start/console_stop func to runtime sync callbacks.
Quoted 4 lines
Again, no need to check
pm_runtime_suspended()since the runtime PM core does usecounting already.
Agree, but balancing put_sync is an issue currently for uart with get_sync as we can use put_sync just once in prepare_idle.
Quoted 34 lines
drivers/tty/serial/omap-serial.c serial_omap_get_divisor(struct uart_port *port, unsigned int baud)
Quoted 6 lines
drivers/tty/serial/omap-serial.c +6
-0+void omap_uart_prepare_idle (int num) +{ + ? ? struct uart_omap_port *up = ui[num]; + + ? ? if (up && up->can_sleep) + ? ? ? ? ? ? serial_omap_port_disable(up);? ? ? ? ? ? ? ?pm_runtime_put_autosuspend()
drivers/tty/serial/omap-serial.c serial_omap_get_divisor(struct uart_port *port, unsigned int baud) · line 160
Quoted 13 lines
drivers/tty/serial/omap-serial.c +13
-0+} + +void omap_uart_resume_idle (int num) +{ + ? ? struct uart_omap_port *up = ui[num]; + ? ? struct omap_device *od; + ? ? struct platform_device *pdev; + + ? ? if (!up) + ? ? ? ? ? ? return; + + ? ? pdev = up->pdev; + ? ? od = container_of(pdev, struct omap_device, pdev);? ? ? ?od =
to_omap_device(pdev);drivers/tty/serial/omap-serial.c serial_omap_get_divisor(struct uart_port *port, unsigned int baud) · line 166
Quoted 6 lines
drivers/tty/serial/omap-serial.c +6
-0+ ? ? if (omap_hmwod_pad_wakeup_status(od->hwmods[0]) == true) + ? ? ? ? ? ? serial_omap_port_enable(up); + + ? ? if (up->wk_st && (__raw_readl(up->wk_st) & up->wk_mask)) + ? ? ? ? ? ? serial_omap_port_enable(up); +}c.f. comments from PATCH 2/7
Quoted 5 lines
Also, direct hwmod access and PRCM accesses do not belong in drivers.
Until it is understood why wakeups are not working, these hacks should stay in
mach-omap2/serial.c
Ok. I will add callbacks to handle wk_mask and wk_st
will retain these funcs in serial.c but new format of this func can use uart_port id based on which i can select wk_st and wk_mask values and then read/write into these.
Quoted 160 lines
drivers/tty/serial/omap-serial.c static void serial_omap_enable_ms(struct uart_port *port) · line 187
Quoted 8 lines
drivers/tty/serial/omap-serial.c +1
-0?static void serial_omap_stop_rxdma(struct uart_omap_port *up) ?{ ? ? ? if (up->uart_dma.rx_dma_used) {@@ -105,6 +184,7 @@ static void serial_omap_enable_ms(struct uart_port *port) ?{ ? ? ? struct uart_omap_port *up = (struct uart_omap_port *)port; + ? ? serial_omap_port_enable(up);? ? ? ?pm_runtime_put_autosuspend()
similarily for all calls to
omap_port_enable()Quoted 147 lines
drivers/tty/serial/omap-serial.c +1
-0? ? ? dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->pdev->id); ? ? ? up->ier |= UART_IER_MSI; ? ? ? serial_out(up, UART_IER, up->ier);@@ -114,6 +194,7 @@ static void serial_omap_stop_tx(struct uart_port *port) ?{ ? ? ? struct uart_omap_port *up = (struct uart_omap_port *)port; + ? ? serial_omap_port_enable(up);? ? ? if (
up->use_dma&&
? ? ? ? ? ? ?up->uart_dma.tx_dma_channel!=OMAP_UART_DMA_CH_FREE) { ? ? ? ? ? ? ? /*drivers/tty/serial/omap-serial.c +8
-0@@ -137,6 +218,7 @@ static void serial_omap_stop_rx(struct uart_port *port) ?{ ? ? ? struct uart_omap_port *up = (struct uart_omap_port *)port; + ? ? serial_omap_port_enable(up); ? ? ? if (up->use_dma) ? ? ? ? ? ? ? serial_omap_stop_rxdma(up); ? ? ? up->ier &= ~UART_IER_RLSI;@@ -258,6 +340,7 @@ static void serial_omap_start_tx(struct uart_port *port) ? ? ? unsigned int start; ? ? ? int ret = 0; + ? ? serial_omap_port_enable(up); ? ? ? if (!up->use_dma) { ? ? ? ? ? ? ? serial_omap_enable_ier_thri(up); ? ? ? ? ? ? ? return;@@ -351,6 +434,7 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id) ? ? ? unsigned int iir, lsr; ? ? ? unsigned long flags; + ? ? serial_omap_port_enable(up); ? ? ? iir = serial_in(up, UART_IIR); ? ? ? if (iir & UART_IIR_NO_INT) ? ? ? ? ? ? ? return IRQ_NONE;@@ -385,6 +469,7 @@ static unsigned int serial_omap_tx_empty(struct uart_port *port) ? ? ? unsigned long flags = 0; ? ? ? unsigned int ret = 0; + ? ? serial_omap_port_enable(up); ? ? ? dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->pdev->id); ? ? ? spin_lock_irqsave(&up->port.lock, flags); ? ? ? ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;@@ -399,6 +484,7 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port) ? ? ? unsigned char status; ? ? ? unsigned int ret = 0; + ? ? serial_omap_port_enable(up); ? ? ? status = check_modem_status(up); ? ? ? dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->pdev->id);@@ -419,6 +505,7 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) ? ? ? unsigned char mcr = 0; ? ? ? dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->pdev->id); + ? ? serial_omap_port_enable(up); ? ? ? if (mctrl & TIOCM_RTS) ? ? ? ? ? ? ? mcr |= UART_MCR_RTS; ? ? ? if (mctrl & TIOCM_DTR)@@ -440,6 +527,7 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state) ? ? ? unsigned long flags = 0; ? ? ? dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->pdev->id); + ? ? serial_omap_port_enable(up); ? ? ? spin_lock_irqsave(&up->port.lock, flags); ? ? ? if (break_state == -1) ? ? ? ? ? ? ? up->lcr |= UART_LCR_SBC;@@ -465,6 +553,7 @@ static int serial_omap_startup(struct uart_port *port) ? ? ? dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->pdev->id); + ? ? serial_omap_port_enable(up);? ? ? /*
? ? ? ?* Clear the FIFO buffers and disable them. ? ? ? ?* (they will be reenabled inset_termios())drivers/tty/serial/omap-serial.c +2
-0@@ -530,6 +619,8 @@ static void serial_omap_shutdown(struct uart_port *port) ? ? ? unsigned long flags = 0; ? ? ? dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->pdev->id); + + ? ? serial_omap_port_enable(up);? ? ? /*
? ? ? ?* Disable interrupts from this port
? ? ? ?*/drivers/tty/serial/omap-serial.c +4
-0@@ -668,6 +759,10 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, ? ? ? baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/13); ? ? ? quot = serial_omap_get_divisor(port, baud); + ? ? up->dll = quot & 0xff; + ? ? up->dlh = quot >> 8; + ? ? up->mdr1 = UART_OMAP_MDR1_DISABLE; +? ? ?
up->fcr=UART_FCR_R_TRIG_01|UART_FCR_T_TRIG_01| ? ? ? ? ? ? ? ? ? ? ?UART_FCR_ENABLE_FIFO;
? ? ? if (up->use_dma)drivers/tty/serial/omap-serial.c +0
-0@@ -677,6 +772,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,? ? ? ?* Ok, we're now changing the port state. Do it with ? ? ? ?* interrupts disabled.
? ? ? ?*/
+ ? ?serial_omap_port_enable(up);
? ? ?spin_lock_irqsave(&up->port.lock, flags);? ? ? /*
drivers/tty/serial/omap-serial.c +0
-0@@ -755,8 +851,11 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, ? ? ? serial_out(up, UART_MCR, up->mcr);? ? ? /* Protocol, Baud Rate, and Interrupt Settings */
+ ? ? if (up->errata&UART_ERRATA_i202_MDR1_ACCESS)
+ ? ? ? ? ? ?omap_uart_mdr1_errataset(up);
+ ? ? else
+ ? ? ? ? ? ?serial_out(up, UART_OMAP_MDR1, up->mdr1);- ? ?
serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE); ? ? ?serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);? ? ?
up->efr=serial_in(up, UART_EFR);drivers/tty/serial/omap-serial.c +8
-3@@ -766,8 +865,8 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, ? ? ? serial_out(up, UART_IER, 0); ? ? ? serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - ? ? serial_out(up, UART_DLL, quot & 0xff); ? ? ? ? ?/* LS of divisor */ - ? ? serial_out(up, UART_DLM, quot >> 8); ? ? ? ? ? ?/* MS of divisor */ + ? ? serial_out(up, UART_DLL, up->dll); ? ? ?/* LS of divisor */ + ? ? serial_out(up, UART_DLM, up->dlh); ? ? ?/* MS of divisor */ ? ? ? serial_out(up, UART_LCR, 0); ? ? ? serial_out(up, UART_IER, up->ier);@@ -777,9 +876,14 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, ? ? ? serial_out(up, UART_LCR, cval); ? ? ? if (baud > 230400 && baud != 3000000) - ? ? ? ? ? ? serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_13X_MODE); + ? ? ? ? ? ? up->mdr1 = UART_OMAP_MDR1_13X_MODE; + ? ? else + ? ? ? ? ? ? up->mdr1 = UART_OMAP_MDR1_16X_MODE; + + ? ? if (up->errata & UART_ERRATA_i202_MDR1_ACCESS) + ? ? ? ? ? ? omap_uart_mdr1_errataset(up);? ? ? else
- ? ? ? ? ? ?serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_16X_MODE);
+ ? ? ? ? ? ?serial_out(up, UART_OMAP_MDR1, up->mdr1);? ? ? /* Hardware Flow Control Configuration */
drivers/tty/serial/omap-serial.c +0
-0@@ -818,6 +922,8 @@ serial_omap_pm(struct uart_port *port, unsigned int state, ? ? ? unsigned char efr;
Quoted 16 lines
drivers/tty/serial/omap-serial.c serial_omap_pm(struct uart_port *port, unsigned int state, · line 937
Quoted 12 lines
drivers/tty/serial/omap-serial.c +4
-0? ? ? dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->pdev->id); + + ? ? serial_omap_port_enable(up); ? ? ? serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); ? ? ? efr = serial_in(up, UART_EFR); ? ? ? serial_out(up, UART_EFR, efr | UART_EFR_ECB);@@ -827,6 +933,8 @@ serial_omap_pm(struct uart_port *port, unsigned int state, ? ? ? serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); ? ? ? serial_out(up, UART_EFR, efr); ? ? ? serial_out(up, UART_LCR, 0); + ? ? if (state) + ? ? ? ? ? ? serial_omap_port_disable(up);FYI... this change doesn't apply when basing on the commit you mentioned in PATCH 0/7.
this patch series will apply on top the
dependency patches specified in cover letter.
Specially needs
https://patchwork.kernel.org/patch/501211/
without which it will fail here.
Quoted 117 lines
Quoted 117 lines
drivers/tty/serial/omap-serial.c +5
-1?} ?static void serial_omap_release_port(struct uart_port *port)@@ -904,6 +1012,8 @@ static inline void wait_for_xmitr(struct uart_omap_port *up) ?static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch) ?{ ? ? ? struct uart_omap_port *up = (struct uart_omap_port *)port; + + ? ? serial_omap_port_enable(up); ? ? ? wait_for_xmitr(up); ? ? ? serial_out(up, UART_TX, ch); ?}@@ -911,8 +1021,10 @@ static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch) ?static int serial_omap_poll_get_char(struct uart_port *port) ?{ ? ? ? struct uart_omap_port *up = (struct uart_omap_port *)port; - ? ? unsigned int status = serial_in(up, UART_LSR); + ? ? unsigned int status; + ? ? serial_omap_port_enable(up); + ? ? status = serial_in(up, UART_LSR); ? ? ? if (!(status & UART_LSR_DR)) ? ? ? ? ? ? ? return NO_POLL_CHAR;@@ -922,7 +1034,6 @@ static int serial_omap_poll_get_char(struct uart_port *port)?#endif /*
CONFIG_CONSOLE_POLL*/?#ifdef
CONFIG_SERIAL_OMAP_CONSOLE
-
?static structuart_omap_port*serial_omap_console_ports[4];?static struct
uart_driverserial_omap_reg;drivers/tty/serial/omap-serial.c +27
-10@@ -931,6 +1042,7 @@ static void serial_omap_console_putchar(struct uart_port *port, int ch) ?{ ? ? ? struct uart_omap_port *up = (struct uart_omap_port *)port; + ? ? serial_omap_port_enable(up); ? ? ? wait_for_xmitr(up); ? ? ? serial_out(up, UART_TX, ch); ?}@@ -944,6 +1056,7 @@ serial_omap_console_write(struct console *co, const char *s, ? ? ? unsigned int ier; ? ? ? int locked = 1; + ? ? serial_omap_port_enable(up); ? ? ? local_irq_save(flags); ? ? ? if (up->port.sysrq) ? ? ? ? ? ? ? locked = 0;@@ -1058,22 +1171,25 @@ static struct uart_driver serial_omap_reg = { ? ? ? .cons ? ? ? ? ? = OMAP_CONSOLE, ?}; -static int -serial_omap_suspend (struct platform_device *pdev,pm_message_t state) +static int serial_omap_suspend (struct device *dev) ?{ - ? ? struct uart_omap_port *up = platform_get_drvdata(pdev); + ? ? struct uart_omap_port *up = dev_get_drvdata(dev); - ? ? if (up) + ? ? if (up) { ? ? ? ? ? ? ? uart_suspend_port(&serial_omap_reg, &up->port); + ? ? ? ? ? ? serial_omap_port_disable(up); + ? ? } + ? ? ? return 0; ?} -static int serial_omap_resume (struct platform_device *dev) +static int serial_omap_resume (struct device *dev) ?{ - ? ? struct uart_omap_port *up = platform_get_drvdata(dev); + ? ? struct uart_omap_port *up = dev_get_drvdata(dev); ? ? ? if (up) ? ? ? ? ? ? ? uart_resume_port(&serial_omap_reg, &up->port); + ? ? ? return 0; ?}@@ -1221,9 +1337,10 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data) ?static int serial_omap_probe(struct platform_device *pdev) ?{ - ? ? struct uart_omap_port ? *up; + ? ? struct uart_omap_port ? *up = NULL; ? ? ? struct resource ? ? ? ? *mem, *irq, *dma_tx, *dma_rx; ? ? ? struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data; + ? ? struct omap_device *od; ? ? ? int ret = -ENOSPC; ? ? ? mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);@@ -1273,12 +1390,23 @@ static int serial_omap_probe(struct platform_device *pdev) ? ? ? up->port.ops = &serial_omap_pops; ? ? ? up->port.line = pdev->id; - ? ? up->port.membase = omap_up_info->membase; - ? ? up->port.mapbase = omap_up_info->mapbase; + ? ? up->port.mapbase = mem->start; + ? ? up->port.membase = ioremap(mem->start, mem->end - mem->start); + + ? ? if (!up->port.membase) { + ? ? ? ? ? ? dev_err(&pdev->dev, "can't ioremap UART\n"); + ? ? ? ? ? ? ret = -ENOMEM; + ? ? ? ? ? ? goto err1; + ? ? } + ? ? ? up->port.flags = omap_up_info->flags; - ? ? up->port.irqflags = omap_up_info->irqflags; ? ? ? up->port.uartclk = omap_up_info->uartclk; ? ? ? up->uart_dma.uart_base = mem->start; + ? ? up->errata = omap_up_info->errata; + + ? ? up->wk_st = omap_up_info->wk_st; + ? ? up->wk_en = omap_up_info->wk_en; + ? ? up->wk_mask = omap_up_info->wk_mask;
Quoted 14 lines
drivers/tty/serial/omap-serial.c static int serial_omap_probe(struct platform_device *pdev) · line 1427
Quoted 12 lines
drivers/tty/serial/omap-serial.c +6
-0? ? ? if (omap_up_info->dma_enabled) { ? ? ? ? ? ? ? up->uart_dma.uart_dma_tx = dma_tx->start;@@ -1291,19 +1419,35 @@ static int serial_omap_probe(struct platform_device *pdev) ? ? ? ? ? ? ? up->uart_dma.tx_dma_channel = OMAP_UART_DMA_CH_FREE; ? ? ? ? ? ? ? up->uart_dma.rx_dma_channel = OMAP_UART_DMA_CH_FREE; ? ? ? } + ? ? init_timer(&(up->inactivity_timer)); + ? ? up->inactivity_timer.function = serial_omap_inactivity_timer; + ? ? up->inactivity_timer.data = up->pdev->id; + + ? ? pm_runtime_enable(&pdev->dev); + ? ? pm_runtime_irq_safe(&pdev->dev);The changelog should describe why the IRQ-safe mode is needed.
yes will add.
we need to use get_sync in irq_context hence needed.
Quoted 5 lines
drivers/tty/serial/omap-serial.c static int serial_omap_probe(struct platform_device *pdev) · line 1430
Quoted 4 lines
drivers/tty/serial/omap-serial.c +3
-0+ ? ? if (omap_up_info->console_uart) { + ? ? ? ? ? ? od = container_of(pdev, struct omap_device, pdev); + ? ? ? ? ? ? omap_hwmod_idle(od->hwmods[0]);
Quoted 7 lines
This was only in
mach-omap2/serial.cbecause the early UART probing was accessing registers. ?With this driver becoming runtime PM aware, this hack should not be needed, and the? ? ? ?oh->flags |=
HWMOD_INIT_NO_IDLE|HWMOD_INIT_NO_RESET;should be removed from
mach-omap2/serial.c
Yes. Since any omap-uart can be used as
console uart and the console uart can be used
for earlyprintk's.
For earlyprintk's the early console driver will use printch from debug macro to print through uart during which hwmod is getting initialized
--> _setup
--> _idle
---> _disable_clocksat this point of time while printch is happening and hwmod disables uart clocks I dont have uart-console driver available which can enable clocks back.
So I have to use those flags when earlyprintk is enabled. I have added some more changes into omap_serial_early_init which uses these flags only when earlyprintk config is defined and earlyprintk word is used in bootarg, snip below.
<<Function SNIP>>
==================================
static int __init omap_serial_early_init(void)
{
#ifdef CONFIG_EARLY_PRINTK
int i = 0;
char omap_tty_name[MAX_UART_HWMOD_NAME_LEN];
struct omap_hwmod *oh;
if (!cmdline_find_option("earlyprintk"))
return 0;
for (i = 0; i < OMAP_MAX_HSUART_PORTS; i++) {
snprintf(omap_tty_name, MAX_UART_HWMOD_NAME_LEN,
"%s%d", OMAP_SERIAL_NAME, i);
if (cmdline_find_option(omap_tty_name)) {
omap_uart_con_id = i;
oh = omap_uart_hwmod_lookup(i);
oh->flags |= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET;
return 0;
}
}
#endif
return 0;
}core_initcall(omap_serial_early_init);
=========================================
Quoted 122 lines
Quoted 109 lines
drivers/tty/serial/omap-serial.c +5
-1+ ? ? ? ? ? ? serial_omap_port_enable(up); + ? ? } ? ? ? ui[pdev->id] = up; ? ? ? serial_omap_add_console_port(up); ? ? ? ret = uart_add_one_port(&serial_omap_reg, &up->port); ? ? ? if (ret != 0) - ? ? ? ? ? ? goto do_release_region; + ? ? ? ? ? ? goto err1; + ? ? dev_set_drvdata(&pdev->dev, up); ? ? ? platform_set_drvdata(pdev, up); + ? ? ? return 0;?err:
? ? ?dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pdev->id, __func__, ret); +err1:
+ ? ? kfree(up);
?do_release_region:
? ? ?release_mem_region(mem->start, (mem->end - mem->start) + 1); ? ? ? return ret;drivers/tty/serial/omap-serial.c +75
-0@@ -1315,20 +1459,138 @@ static int serial_omap_remove(struct platform_device *dev) ? ? ? platform_set_drvdata(dev, NULL); ? ? ? if (up) { + ? ? ? ? ? ? pm_runtime_disable(&up->pdev->dev); ? ? ? ? ? ? ? uart_remove_one_port(&serial_omap_reg, &up->port); ? ? ? ? ? ? ? kfree(up); ? ? ? } ? ? ? return 0; ?} +/* +* Work Around for Errata i202 (3430 - 1.12, 3630 - 1.6) +* The access to uart register after MDR1 Access +* causes UART to corrupt data. +* +* Need a delay = +* 5 L4 clock cycles + 5 UART functional clock cycle (@48MHz = ~0.2uS) +* give 10 times as much +*/ +static void omap_uart_mdr1_errataset (struct uart_omap_port *up) +{ + ? ? u8 timeout = 255; + + ? ? serial_out(up, UART_OMAP_MDR1, up->mdr1); + ? ? udelay(2); + ? ? serial_out(up, UART_FCR, up->fcr | UART_FCR_CLEAR_XMIT | + ? ? ? ? ? ? ? ? ? ? UART_FCR_CLEAR_RCVR); + ? ? /* + ? ? ?* Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and + ? ? ?* TX_FIFO_E bit is 1. + ? ? ?*/ + ? ? while (UART_LSR_THRE != (serial_in(up, UART_LSR) & + ? ? ? ? ? ? ? ? ? ? ? ? ? ? (UART_LSR_THRE | UART_LSR_DR))) { + ? ? ? ? ? ? timeout--; + ? ? ? ? ? ? if (!timeout) { + ? ? ? ? ? ? ? ? ? ? /* Should *never* happen. we warn and carry on */ + ? ? ? ? ? ? ? ? ? ? dev_crit(&up->pdev->dev, "Errata i202: timedout %x\n", + ? ? ? ? ? ? ? ? ? ? serial_in(up, UART_LSR)); + ? ? ? ? ? ? ? ? ? ? break; + ? ? ? ? ? ? } + ? ? ? ? ? ? udelay(1); + ? ? } +} + +static void omap_uart_restore_context (struct uart_omap_port *up) +{ + ? ? u16 efr = 0; + + ? ? if (up->errata & UART_ERRATA_i202_MDR1_ACCESS) + ? ? ? ? ? ? omap_uart_mdr1_errataset(up); + ? ? else + ? ? ? ? ? ? serial_out(up, UART_OMAP_MDR1, up->mdr1); + ? ? serial_out(up, UART_LCR, 0xBF); /* Config B mode */ + ? ? efr = serial_in(up, UART_EFR); + ? ? serial_out(up, UART_EFR, UART_EFR_ECB); + ? ? serial_out(up, UART_LCR, 0x0); /* Operational mode */ + ? ? serial_out(up, UART_IER, 0x0); + ? ? serial_out(up, UART_LCR, 0xBF); /* Config B mode */ + ? ? serial_out(up, UART_DLL, up->dll); + ? ? serial_out(up, UART_DLM, up->dlh); + ? ? serial_out(up, UART_LCR, 0x0); /* Operational mode */ + ? ? serial_out(up, UART_IER, up->ier); + ? ? serial_out(up, UART_FCR, up->fcr); + ? ? serial_out(up, UART_LCR, 0x80); + ? ? serial_out(up, UART_MCR, up->mcr); + ? ? serial_out(up, UART_LCR, 0xBF); /* Config B mode */ + ? ? serial_out(up, UART_EFR, efr); + ? ? serial_out(up, UART_LCR, UART_LCR_WLEN8); + ? ? if (up->errata & UART_ERRATA_i202_MDR1_ACCESS) + ? ? ? ? ? ? omap_uart_mdr1_errataset(up); + ? ? else + ? ? ? ? ? ? /* UART 16x mode */ + ? ? ? ? ? ? serial_out(up, UART_OMAP_MDR1, up->mdr1); +} + +static void omap_uart_enable_wakeup (struct uart_omap_port *up) +{ + ? ? /* Set wake-enable bit */ + ? ? if (up->wk_en && up->wk_mask) { + ? ? ? ? ? ? u32 v = __raw_readl(up->wk_en); + ? ? ? ? ? ? v |= up->wk_mask; + ? ? ? ? ? ? __raw_writel(v, up->wk_en); + ? ? } +}drivers/tty/serial/omap-serial.c static int serial_omap_remove(struct platform_device *dev) · line 1552
Quoted 10 lines
drivers/tty/serial/omap-serial.c +10
-0+ +static void omap_uart_disable_wakeup (struct uart_omap_port *up) +{ + ? ? /* Clear wake-enable bit */ + ? ? if (up->wk_en && up->wk_mask) { + ? ? ? ? ? ? u32 v = __raw_readl(up->wk_en); + ? ? ? ? ? ? v &= ~up->wk_mask; + ? ? ? ? ? ? __raw_writel(v, up->wk_en); + ? ? } +}Again, driver should not be doing direct PRCM accesses here.
Quoted 6 lines
For now, how about leaving these also in
mach-omap2/serial.cand calling them via pdata function pointers:?if (
pdata->enable_wakeup)
? ? ?pdata->enable_wakeup()
Agree will move these func's and use func. pointer.
--
Thanks,
Govindraj.R
Quoted 52 lines
Quoted 35 lines
drivers/tty/serial/omap-serial.c +34
-0+static int omap_serial_runtime_suspend (struct device *dev) +{ + ? ? struct uart_omap_port *up = dev_get_drvdata(dev); + + ? ? if (!up) + ? ? ? ? ? ? goto done; + + ? ? if (device_may_wakeup(&up->pdev->dev)) + ? ? ? ? ? ? omap_uart_enable_wakeup(up); + ? ? else + ? ? ? ? ? ? omap_uart_disable_wakeup(up); +done: + ? ? return 0; +} + +static int omap_serial_runtime_resume (struct device *dev) +{ + ? ? struct uart_omap_port *up = dev_get_drvdata(dev); + + ? ? if (!up) + ? ? ? ? ? ? goto done; + + ? ? omap_uart_restore_context(up); +done: + ? ? return 0; +} + +static const struct dev_pm_ops omap_serial_dev_pm_ops = { + ? ? .suspend = serial_omap_suspend, + ? ? .resume = serial_omap_resume, + ? ? .runtime_suspend = omap_serial_runtime_suspend, + ? ? .runtime_resume = omap_serial_runtime_resume, +}; + ?static struct platform_driver serial_omap_driver = {drivers/tty/serial/omap-serial.c static int serial_omap_remove(struct platform_device *dev) · line 1594
Quoted 10 lines
drivers/tty/serial/omap-serial.c +1
-3? ? ? .probe ? ? ? ? ?= serial_omap_probe, ? ? ? .remove ? ? ? ? = serial_omap_remove, - - ? ? .suspend ? ? ? ?= serial_omap_suspend, - ? ? .resume ? ? ? ? = serial_omap_resume, ? ? ? .driver ? ? ? ? = { ? ? ? ? ? ? ? .name ? = DRIVER_NAME, + ? ? ? ? ? ? .pm = &omap_serial_dev_pm_ops, ? ? ? }, ?};Kevin
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo at vger.kernel.org
More majordomo info at ?http://vger.kernel.org/majordomo-info.html
PATCH 5/7 Serial: OMAP: add runtime pm support for omap-serial driver
Govindraj <[email protected]> writes:
[...]
Quoted 11 lines
Quoted 3 lines
This function should not be needed.
The timer should be replaced by the auto-suspend feature of runtime PM.
If I use autosuspend based on timer runtime framework will disable clocks based on autosuspend timeout.
But if I cut clocks outside sram idle path module level wakeup will not work.
if I cut func clocks outside prepare for idlewake_upis a problem.
As I mentioned in the other thread, module wakeups are not the problem, rather the module generating the interrupt is the problem. So cutting clocks outside prepare_for_idle path is not the problem. It's the re-enabling of the clocks that is important.
Quoted 37 lines
So I am going with existing model where we are cutting clocks in prepare idle and enabling the clock back in
resume_idlebased on wakeup event as any other combination doesn't seem to work.[As stated in other thread to reproduce the issue
with module level wakeup]Even with existing framework if I try to experiment by cutting clocks after uart timeout in
allow_sleepfunc, module level wakeup doesn't seem to happen.Quoted 10 lines
Instead of calling
omap_port_disable()callers should callpm_runtime_put_autosuspend(), and theconsole_stop()should be part of the ->runtime_suspend() callback.Also, why do you check for
pm_runtime_suspended()? ?Just call it for every time and we get runtime PM use-counting and statistics for free and the ->runtime_suspend() callback will be called when the usecount goes to zero.Yes correct, but I can't balance the
put_syncandget_syncas said above. I can callput_synconly once inprepare_idleto cut clocks. But havingput_syncoutsideprepare_idle, if clocks are cut module level wakeup doesn't seem to happen.Quoted 9 lines
drivers/tty/serial/omap-serial.c serial_omap_get_divisor(struct uart_port *port, unsigned int baud) · line 130
Quoted 7 lines
drivers/tty/serial/omap-serial.c +7
-0+static void serial_omap_inactivity_timer (unsigned long uart_no) +{ + ? ? struct uart_omap_port *up = ui[uart_no]; + + ? ? up->can_sleep = 1; + ? ? omap_uart_smart_idle(up); +}This will not be needed if using the autosuspend feature.
Quoted 3 lines
Using autosuspend, module level wakeup will not happen since autosuspend cuts clocks outside
prepare_idlebased on autosuspend timeout.
OK, I get the point. You mentioned module level wakeups about 10 times in this message. ;)
However, rather than continue to hack around this problem we need to understand the root cause. Thanks to Paul, I think I undersand the root cause as explained in the other thread, and I think there's a relatively easy way to make them work.
So here's an experiment to try with autosuspend. I suspect this will work, just hack it up to prove the concept. If it works, we can make something more generic. Here are a few alternatives to try. I may experiment with some of them tomorrow as well, but please let me know what you try:
Using autosuspend, clocks will get cut independently of the idle path. Then, use the PRCM ISR detection of UART module wakeups to call the UART's interrupt handler. The interrupt handler will pm_runtime_get(), enable the clocks, and then take care of the interrupt. Done.
Alternatively, you could test it on current code by simply removing the resume_from_idle call from the idle path and calling it instead from the PRCM ISR when UART module wakeups are detected.
Another option to experiment with: use PRCM ISR to trigger a SW interrupt of the UART IRQ (cf. MPU_INTC.INTCPS_ISR_SETn registers.) This may be the cleanest approach, and not require calling into the driver, but I'm not sure if the normal interrupt clearing process will also clear the SW interrupt.
The best longer-term solution is will be to use the chained PRCM interrupt handler[1] (not yet finished.) Using that, drivers could directly register for their individual module wakeup interrupts.
Kevin
Paul Walmsley
maintainerPATCH 5/7 Serial: OMAP: add runtime pm support for omap-serial driver
Hi Govindraj,
what also would be good to find out is why the UART is apparently sending asynchronous wakeups even when the driver doesn't set SCR_REG.RX_CTS_WU_EN. This seems contrary to the expectation that 34xx TRM vZH section 17.4.4.1.4.1 "Wake-up Interrupt" sets. Could you please clarify under which circumstances the RX_CTS_WU_EN bit is used? I suppose that, given that it's also mentioned under section 17.4.5.1.1 "Module Power Savings", it might only be used when SLEEP_MODE is enabled.
- Paul
PATCH 5/7 Serial: OMAP: add runtime pm support for omap-serial driver
Quoted 11 lines · Paul Walmsley
Hi Govindraj,
what also would be good to find out is why the UART is apparently sending asynchronous wakeups even when the driver doesn't set SCR_REG.RX_CTS_WU_EN. ?This seems contrary to the expectation that 34xx TRM vZH section 17.4.4.1.4.1 "Wake-up Interrupt" sets. ?Could you please clarify under which circumstances the
RX_CTS_WU_ENbit is used? ?I suppose that, given that it's also mentioned under section 17.4.5.1.1 "Module Power Savings", it might only be used whenSLEEP_MODEis enabled.
AFAIK, sleep_mode is used only for uart internal power saving options if fifo's are empty which inturn can stop uart internal baud clock. To enable back uart baud clock and start uart internal activity it will depend on RX_CTS_WU_EN from scr to restart uart_baud_clock.
For system level powers saving like cutting uart_fclks wakeup will depend on WER reg for wakeup event or io-pad wakeup depending on power state.
Since I am cutting fclks directly I am depending on WER reg wakeup events.
--
Thanks,
Govindraj.R
Quoted 3 lines
- Paul
PATCH 5/7 Serial: OMAP: add runtime pm support for omap-serial driver
In reply to Kevin HilmanQuoted 76 lines · Kevin Hilman
Govindraj <[email protected]> writes:
[...]
Quoted 11 lines
Quoted 3 lines
This function should not be needed.
The timer should be replaced by the auto-suspend feature of runtime PM.
If I use autosuspend based on timer runtime framework will disable clocks based on autosuspend timeout.
But if I cut clocks outside sram idle path module level wakeup will not work.
if I cut func clocks outside prepare for idlewake_upis a problem.As I mentioned in the other thread, module wakeups are not the problem, rather the module generating the interrupt is the problem. ?So cutting clocks outside
prepare_for_idlepath is not the problem. ?It's the re-enabling of the clocks that is important.Quoted 37 lines
So I am going with existing model where we are cutting clocks in prepare idle and enabling the clock back in
resume_idlebased on wakeup event as any other combination doesn't seem to work.[As stated in other thread to reproduce the issue
with module level wakeup]Even with existing framework if I try to experiment by cutting clocks after uart timeout in
allow_sleepfunc, module level wakeup doesn't seem to happen.Quoted 10 lines
Instead of calling
omap_port_disable()callers should callpm_runtime_put_autosuspend(), and theconsole_stop()should be part of the ->runtime_suspend() callback.Also, why do you check for
pm_runtime_suspended()? ?Just call it for every time and we get runtime PM use-counting and statistics for free and the ->runtime_suspend() callback will be called when the usecount goes to zero.Yes correct, but I can't balance the
put_syncandget_syncas said above. I can callput_synconly once inprepare_idleto cut clocks. But havingput_syncoutsideprepare_idle, if clocks are cut module level wakeup doesn't seem to happen.Quoted 9 lines
drivers/tty/serial/omap-serial.c serial_omap_get_divisor(struct uart_port *port, unsigned int baud) · line 130
Quoted 7 lines
drivers/tty/serial/omap-serial.c +7
-0+static void serial_omap_inactivity_timer (unsigned long uart_no) +{ + ? ? struct uart_omap_port *up = ui[uart_no]; + + ? ? up->can_sleep = 1; + ? ? omap_uart_smart_idle(up); +}This will not be needed if using the autosuspend feature.
Quoted 3 lines
Using autosuspend, module level wakeup will not happen since autosuspend cuts clocks outside
prepare_idlebased on autosuspend timeout.OK, I get the point. ?You mentioned module level wakeups about 10 times in this message. ?;)
However, rather than continue to hack around this problem we need to understand the root cause. ?Thanks to Paul, I think I undersand the root cause as explained in the other thread, and I think there's a relatively easy way to make them work.
So here's an experiment to try with autosuspend. ?I suspect this will work, just hack it up to prove the concept. ?If it works, we can make something more generic. ?Here are a few alternatives to try. ?I may experiment with some of them tomorrow as well, but please let me know what you try:
Quoted 8 lines
Using autosuspend, clocks will get cut independently of the idle path. Then, use the PRCM ISR detection of UART module wakeups to call the UART's interrupt handler. ?The interrupt handler will
pm_runtime_get(), enable the clocks, and then take care of the interrupt. ?Done.Alternatively, you could test it on current code by simply removing the
resume_from_idlecall from the idle path and calling it instead from the PRCM ISR when UART module wakeups are detected.
I remember doing similar experiment didn't seem to help,
Quoted 6 lines
Another option to experiment with: use PRCM ISR to trigger a SW interrupt of the UART IRQ (cf. MPU_INTC.INTCPS_ISR_SETn registers.) This may be the cleanest approach, and not require calling into the driver, but I'm not sure if the normal interrupt clearing process will also clear the SW interrupt.
need to check this.
Quoted 4 lines
The best longer-term solution is will be to use the chained PRCM interrupt handler[1] (not yet finished.) ?Using that, drivers could directly register for their individual module wakeup interrupts.
Agree.
Quoted 6 lines
Kevin
PATCH 5/7 Serial: OMAP: add runtime pm support for omap-serial driver
Govindraj <[email protected]> writes:
[...]
Quoted 12 lines
Quoted 12 lines
So here's an experiment to try with autosuspend. ?I suspect this will work, just hack it up to prove the concept. ?If it works, we can make something more generic. ?Here are a few alternatives to try. ?I may experiment with some of them tomorrow as well, but please let me know what you try:
Using autosuspend, clocks will get cut independently of the idle path. Then, use the PRCM ISR detection of UART module wakeups to call the UART's interrupt handler. ?The interrupt handler will
pm_runtime_get(), enable the clocks, and then take care of the interrupt. ?Done.
Quoted 6 lines
Quoted 3 lines
Alternatively, you could test it on current code by simply removing the
resume_from_idlecall from the idle path and calling it instead from the PRCM ISR when UART module wakeups are detected.I remember doing similar experiment didn't seem to help,
To show it's possible, I did really hacky proof of concept, hard-coded to UART3 console for n900/beagle, but at least it shows that this approach can work, and the module-level wakeups are working and can be used as the trigger for UART wakeup instead of resume_from_idle. Of course, it still has problems with using serial after non-UART wakeups, but once omap-serial is using runtime PM, that will no longer be an issue.
My hacky branch is called pm-wip/uart-wkup and is in my pm git tree[1] (based at the pm-core branch)
To test module-level wakeups (instead of IO-ring) I again forced CORE to stay on during suspend, and tested wakeup from suspend on 3430/n900:
echo 3 > /debug/pm_debug/core_pwrdm/suspend
echo mem > /sys/power/state
Kevin
[1] git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-omap-pm.git
PATCH 6/7 OMAP: Serial: Allow UART parameters to be configured from board file
In reply to Govindraj.RFrom: Jon Hunter <[email protected]>
The following UART parameters are defined within the UART driver:
1). Whether the UART uses DMA (dma_enabled), by default set to 0 2). The size of dma buffer (set to 4096 bytes)
3). The time after which the dma should stop if no more data is received. 4). The idle timeout (DEFAULT_TIMEOUT) that sets the can_sleep flag after
uart inactivity.
5). Add default serial pads to board data if no pad info is available from
board file to avoid breaking uart wakeup capability from rx pad.
Different UARTs may be used for different purpose such as the console, for interfacing bluetooth chip, for interfacing to a modem chip, etc. Therefore, it is necessary to be able to customize the above settings for a given board on a per UART basis.
This change allows these parameters to be configured from the board file and allows the parameters to be configured for each UART independently.
If a board does not define its own custom parameters for the UARTs, then use the default parameters in the structure "omap_serial_default_info". The default parameters are defined to be the same as the current settings in the UART driver to avoid breaking the UART for any board. By default, make all boards use the default UART parameters.
--- arch/arm/mach-omap2/board-2430sdp.c | 3 +- arch/arm/mach-omap2/board-3430sdp.c | 4 +- arch/arm/mach-omap2/board-4430sdp.c | 3 +- arch/arm/mach-omap2/board-am3517evm.c | 3 +- arch/arm/mach-omap2/board-apollon.c | 3 +- arch/arm/mach-omap2/board-cm-t35.c | 3 +- arch/arm/mach-omap2/board-cm-t3517.c | 3 +- arch/arm/mach-omap2/board-devkit8000.c | 3 +- arch/arm/mach-omap2/board-generic.c | 3 +- arch/arm/mach-omap2/board-h4.c | 3 +- arch/arm/mach-omap2/board-igep0020.c | 3 +- arch/arm/mach-omap2/board-igep0030.c | 3 +- arch/arm/mach-omap2/board-ldp.c | 3 +- arch/arm/mach-omap2/board-n8x0.c | 9 +- arch/arm/mach-omap2/board-omap3beagle.c | 3 +- arch/arm/mach-omap2/board-omap3evm.c | 3 +- arch/arm/mach-omap2/board-omap3logic.c | 3 +- arch/arm/mach-omap2/board-omap3pandora.c | 3 +- arch/arm/mach-omap2/board-omap3stalker.c | 3 +- arch/arm/mach-omap2/board-omap3touchbook.c | 3 +- arch/arm/mach-omap2/board-omap4panda.c | 3 +- arch/arm/mach-omap2/board-overo.c | 3 +- arch/arm/mach-omap2/board-rm680.c | 3 +- arch/arm/mach-omap2/board-rx51.c | 3 +- arch/arm/mach-omap2/board-ti8168evm.c | 2 +- arch/arm/mach-omap2/board-zoom-peripherals.c | 3 +- arch/arm/mach-omap2/serial.c | 108 +++++++++++++++++++++++- arch/arm/plat-omap/include/plat/omap-serial.h | 14 +++- arch/arm/plat-omap/include/plat/serial.h | 6 +- drivers/tty/serial/omap-serial.c | 10 +- 30 files changed, 177 insertions(+), 45 deletions(-)
arch/arm/mach-omap2/board-2430sdp.c +2 -1
@@ -38,6 +38,7 @@#include <plat/gpmc.h> #include <plat/usb.h> #include <plat/gpmc-smc91x.h> +#include <plat/omap-serial.h> #include "mux.h" #include "hsmmc.h"
@@ -249,7 +250,7 @@ static void __init omap_2430sdp_init(void)omap2430_i2c_init ();platform_add_devices (sdp2430_devices,ARRAY_SIZE (sdp2430_devices)); -omap_serial_init (); +omap_serial_init (NULL );omap2_hsmmc_init (mmc);omap2_usbfs_init (&sdp2430_usb_config);
arch/arm/mach-omap2/board-3430sdp.c +2 -2
@@ -39,8 +39,8 @@#include <plat/gpmc.h> #include <plat/display.h> #include <plat/panel-generic-dpi.h> -#include <plat/gpmc-smc91x.h> +#include <plat/omap-serial.h> #include "board-flash.h" #include "mux.h"
@@ -798,7 +798,7 @@ static void __init omap_3430sdp_init(void)spi_register_board_info (sdp3430_spi_board_info,ARRAY_SIZE (sdp3430_spi_board_info));ads7846_dev_init (); -omap_serial_init (); +omap_serial_init (NULL );usb_musb_init (&musb_board_data);board_smc91x_init ();board_flash_init (sdp_flash_partitions, chip_sel_3430,0 );
arch/arm/mach-omap2/board-4430sdp.c +2 -1
@@ -36,6 +36,7 @@#include <plat/usb.h> #include <plat/mmc.h> #include <plat/omap4-keypad.h> +#include <plat/omap-serial.h> #include "mux.h" #include "hsmmc.h"
@@ -643,7 +644,7 @@ static void __init omap_4430sdp_init(void)omap4_i2c_init ();omap_sfh7741prox_init ();platform_add_devices (sdp4430_devices,ARRAY_SIZE (sdp4430_devices)); -omap_serial_init (); +omap_serial_init (NULL );omap4_twl6030_hsmmc_init (mmc);usb_musb_init (&musb_board_data);
arch/arm/mach-omap2/board-am3517evm.c +2 -1
@@ -36,6 +36,7 @@#include <plat/usb.h> #include <plat/display.h> #include <plat/panel-generic-dpi.h> +#include <plat/omap-serial.h> #include "mux.h" #include "control.h"
@@ -487,7 +488,7 @@ static void __init am3517_evm_init(void)am3517_evm_i2c_init ();omap_display_init (&am3517_evm_dss_data); -omap_serial_init (); +omap_serial_init (NULL );/* Configure GPIO for EHCI port */ omap_mux_init_gpio (57 ,OMAP_PIN_OUTPUT );
arch/arm/mach-omap2/board-apollon.c +2 -1
@@ -39,6 +39,7 @@#include <plat/board.h> #include <plat/common.h> #include <plat/gpmc.h> +#include <plat/omap-serial.h> #include "mux.h" #include "control.h"
@@ -342,7 +343,7 @@ static void __init omap_apollon_init(void)* if not needed. */ platform_add_devices (apollon_devices,ARRAY_SIZE (apollon_devices)); -omap_serial_init (); +omap_serial_init (NULL ); }static void __init omap_apollon_map_io (void )
arch/arm/mach-omap2/board-cm-t35.c +2 -1
@@ -48,6 +48,7 @@#include <plat/display.h> #include <plat/panel-generic-dpi.h> #include <plat/mcspi.h> +#include <plat/omap-serial.h> #include <mach/hardware.h>
@@ -788,7 +789,7 @@ static struct omap_musb_board_data musb_board_data = {static void __init cm_t35_init (void ) {omap3_mux_init (board_mux,OMAP_PACKAGE_CUS ); -omap_serial_init (); +omap_serial_init (NULL );cm_t35_init_i2c ();cm_t35_init_nand ();cm_t35_init_ads7846 ();
arch/arm/mach-omap2/board-cm-t3517.c +2 -1
@@ -43,6 +43,7 @@#include <plat/usb.h> #include <plat/nand.h> #include <plat/gpmc.h> +#include <plat/omap-serial.h> #include <mach/am35xx.h>
@@ -292,7 +293,7 @@ static struct omap_board_mux board_mux[] __initdata = {static void __init cm_t3517_init (void ) {omap3_mux_init (board_mux,OMAP_PACKAGE_CBB ); -omap_serial_init (); +omap_serial_init (NULL );cm_t3517_init_leds ();cm_t3517_init_nand ();cm_t3517_init_rtc ();
arch/arm/mach-omap2/board-devkit8000.c +2 -1
@@ -47,6 +47,7 @@#include <plat/usb.h> #include <plat/display.h> #include <plat/panel-generic-dpi.h> +#include <plat/omap-serial.h> #include <plat/mcspi.h> #include <linux/input/matrix_keypad.h>
@@ -784,7 +785,7 @@ static struct omap_board_mux board_mux[] __initdata = {static void __init devkit8000_init (void ) {omap3_mux_init (board_mux,OMAP_PACKAGE_CUS ); -omap_serial_init (); +omap_serial_init (NULL );omap_dm9000_init ();
arch/arm/mach-omap2/board-generic.c +2 -1
@@ -29,6 +29,7 @@#include <plat/usb.h> #include <plat/board.h> #include <plat/common.h> +#include <plat/omap-serial.h> static struct omap_board_config_kernel generic_config[] = { };
@@ -43,7 +44,7 @@ static void __init omap_generic_init_early(void)static void __init omap_generic_init (void ) { -omap_serial_init (); +omap_serial_init (NULL ); }static void __init omap_generic_map_io (void )
arch/arm/mach-omap2/board-h4.c +2 -1
@@ -39,6 +39,7 @@#include <plat/menelaus.h> #include <plat/dma.h> #include <plat/gpmc.h> +#include <plat/omap-serial.h> #include "mux.h" #include "control.h"
@@ -370,7 +371,7 @@ static void __init omap_h4_init(void)platform_add_devices (h4_devices,ARRAY_SIZE (h4_devices));omap2_usbfs_init (&h4_usb_config); -omap_serial_init (); +omap_serial_init (NULL ); }static void __init omap_h4_map_io (void )
arch/arm/mach-omap2/board-igep0020.c +2 -1
@@ -34,6 +34,7 @@#include <plat/display.h> #include <plat/panel-generic-dpi.h> #include <plat/onenand.h> +#include <plat/omap-serial.h> #include "mux.h" #include "hsmmc.h"
@@ -686,7 +687,7 @@ static void __init igep2_init(void)igep2_i2c_init ();platform_add_devices (igep2_devices,ARRAY_SIZE (igep2_devices));omap_display_init (&igep2_dss_data); -omap_serial_init (); +omap_serial_init (NULL );usb_musb_init (&musb_board_data);usb_ehci_init (&ehci_pdata);
arch/arm/mach-omap2/board-igep0030.c +2 -1
@@ -31,6 +31,7 @@#include <plat/gpmc.h> #include <plat/usb.h> #include <plat/onenand.h> +#include <plat/omap-serial.h> #include "mux.h" #include "hsmmc.h"
@@ -432,7 +433,7 @@ static void __init igep3_init(void)/* Register I2C busses and drivers */ igep3_i2c_init ();platform_add_devices (igep3_devices,ARRAY_SIZE (igep3_devices)); -omap_serial_init (); +omap_serial_init (NULL );usb_musb_init (&musb_board_data);usb_ehci_init (&ehci_pdata);
arch/arm/mach-omap2/board-ldp.c +2 -1
@@ -40,6 +40,7 @@#include <plat/common.h> #include <plat/gpmc.h> #include <mach/board-zoom.h> +#include <plat/omap-serial.h> #include <asm/delay.h> #include <plat/usb.h>
@@ -430,7 +431,7 @@ static void __init omap_ldp_init(void)spi_register_board_info (ldp_spi_board_info,ARRAY_SIZE (ldp_spi_board_info));ads7846_dev_init (); -omap_serial_init (); +omap_serial_init (NULL );usb_musb_init (&musb_board_data);board_nand_init (ldp_nand_partitions,ARRAY_SIZE (ldp_nand_partitions),ZOOM_NAND_CS ,0 );
arch/arm/mach-omap2/board-n8x0.c +5 -4
@@ -33,6 +33,7 @@#include <plat/onenand.h> #include <plat/mmc.h> #include <plat/serial.h> +#include <plat/omap-serial.h> #include "mux.h"
@@ -662,22 +663,22 @@ static inline void board_serial_init(void) bdata.pads_cnt =0 ; bdata.id =0 ; -omap_serial_init_port (&bdata); +omap_serial_init_port (&bdata,NULL ); bdata.id =1 ; -omap_serial_init_port (&bdata); +omap_serial_init_port (&bdata,NULL ); bdata.id =2 ; bdata.pads = serial2_pads; bdata.pads_cnt =ARRAY_SIZE (serial2_pads); - omap_serial_init_port(&bdata); + omap_serial_init_port(&bdata, NULL); }#else static inline void board_serial_init (void ) { -omap_serial_init (); +omap_serial_init (NULL ); }#endif
arch/arm/mach-omap2/board-omap3beagle.c +2 -1
@@ -45,6 +45,7 @@#include <plat/gpmc.h> #include <plat/nand.h> #include <plat/usb.h> +#include <plat/omap-serial.h> #include "mux.h" #include "hsmmc.h"
@@ -613,7 +614,7 @@ static void __init omap3_beagle_init(void)platform_add_devices (omap3_beagle_devices,ARRAY_SIZE (omap3_beagle_devices));omap_display_init (&beagle_dss_data); -omap_serial_init (); +omap_serial_init (NULL );omap_mux_init_gpio (170 ,OMAP_PIN_INPUT );gpio_request (170 ,"DVI_nPD" );
arch/arm/mach-omap2/board-omap3evm.c +2 -1
@@ -46,6 +46,7 @@#include <plat/mcspi.h> #include <plat/display.h> #include <plat/panel-generic-dpi.h> +#include <plat/omap-serial.h> #include "mux.h" #include "sdram-micron-mt46h32m32lf-6.h"
@@ -831,7 +832,7 @@ static void __init omap3_evm_init(void)spi_register_board_info (omap3evm_spi_board_info,ARRAY_SIZE (omap3evm_spi_board_info)); -omap_serial_init (); +omap_serial_init (NULL );/* OMAP3EVM uses ISP1504 phy and so register nop transceiver */ usb_nop_xceiv_register ();
arch/arm/mach-omap2/board-omap3logic.c +2 -1
@@ -44,6 +44,7 @@#include <plat/gpmc-smsc911x.h> #include <plat/gpmc.h> #include <plat/sdrc.h> +#include <plat/omap-serial.h> #define OMAP3LOGIC_SMSC911X_CS 1
@@ -212,7 +213,7 @@ static void __init omap3logic_init(void)omap3_mux_init (board_mux,OMAP_PACKAGE_CBB );omap3torpedo_fix_pbias_voltage ();omap3logic_i2c_init (); -omap_serial_init (); +omap_serial_init (NULL );board_mmc_init ();board_smsc911x_init ();
arch/arm/mach-omap2/board-omap3pandora.c +2 -1
@@ -48,6 +48,7 @@#include <plat/usb.h> #include <plat/display.h> #include <plat/nand.h> +#include <plat/omap-serial.h> #include "mux.h" #include "sdram-micron-mt46h32m32lf-6.h"
@@ -703,7 +704,7 @@ static void __init omap3pandora_init(void)platform_add_devices (omap3pandora_devices,ARRAY_SIZE (omap3pandora_devices));omap_display_init (&pandora_dss_data); -omap_serial_init (); +omap_serial_init (NULL );spi_register_board_info (omap3pandora_spi_board_info,ARRAY_SIZE (omap3pandora_spi_board_info));omap3pandora_ads7846_init ();
arch/arm/mach-omap2/board-omap3stalker.c +2 -1
@@ -41,6 +41,7 @@#include <plat/usb.h> #include <plat/display.h> #include <plat/panel-generic-dpi.h> +#include <plat/omap-serial.h> #include <plat/mcspi.h> #include <linux/input/matrix_keypad.h>
@@ -639,7 +640,7 @@ static void __init omap3_stalker_init(void)spi_register_board_info (omap3stalker_spi_board_info,ARRAY_SIZE (omap3stalker_spi_board_info)); -omap_serial_init (); +omap_serial_init (NULL );usb_musb_init (&musb_board_data);usb_ehci_init (&ehci_pdata);ads7846_dev_init ();
arch/arm/mach-omap2/board-omap3touchbook.c +2 -1
@@ -48,6 +48,7 @@#include <plat/gpmc.h> #include <plat/nand.h> #include <plat/usb.h> +#include <plat/omap-serial.h> #include "mux.h" #include "hsmmc.h"
@@ -519,7 +520,7 @@ static void __init omap3_touchbook_init(void)omap3_touchbook_i2c_init ();platform_add_devices (omap3_touchbook_devices,ARRAY_SIZE (omap3_touchbook_devices)); -omap_serial_init (); +omap_serial_init (NULL );omap_mux_init_gpio (170 ,OMAP_PIN_INPUT );gpio_request (176 ,"DVI_nPD" );
arch/arm/mach-omap2/board-omap4panda.c +2 -1
@@ -39,6 +39,7 @@#include <plat/common.h> #include <plat/usb.h> #include <plat/mmc.h> +#include <plat/omap-serial.h> #include "timer-gp.h" #include "hsmmc.h"
@@ -470,7 +471,7 @@ static void __init omap4_panda_init(void)omap4_panda_i2c_init ();platform_add_devices (panda_devices,ARRAY_SIZE (panda_devices));platform_device_register (&omap_vwlan_device); -omap_serial_init (); +omap_serial_init (NULL );omap4_twl6030_hsmmc_init (mmc);omap4_ehci_init ();usb_musb_init (&musb_board_data);
arch/arm/mach-omap2/board-overo.c +2 -1
@@ -46,6 +46,7 @@#include <mach/hardware.h> #include <plat/nand.h> #include <plat/usb.h> +#include <plat/omap-serial.h> #include "mux.h" #include "sdram-micron-mt46h32m32lf-6.h"
@@ -450,7 +451,7 @@ static void __init overo_init(void)omap3_mux_init (board_mux,OMAP_PACKAGE_CBB );overo_i2c_init ();platform_add_devices (overo_devices,ARRAY_SIZE (overo_devices)); -omap_serial_init (); +omap_serial_init (NULL );overo_flash_init ();usb_musb_init (&musb_board_data);usb_ehci_init (&ehci_pdata);
arch/arm/mach-omap2/board-rm680.c +2 -1
@@ -27,6 +27,7 @@#include <plat/gpmc.h> #include <plat/common.h> #include <plat/onenand.h> +#include <plat/omap-serial.h> #include "mux.h" #include "hsmmc.h"
@@ -162,7 +163,7 @@ static struct omap_musb_board_data rm680_musb_data = {static void __init rm680_init (void ) {omap3_mux_init (board_mux,OMAP_PACKAGE_CBB ); -omap_serial_init (); +omap_serial_init (NULL );usb_musb_init (&rm680_musb_data);rm680_peripherals_init (); }
arch/arm/mach-omap2/board-rx51.c +2 -1
@@ -29,6 +29,7 @@#include <plat/dma.h> #include <plat/gpmc.h> #include <plat/usb.h> +#include <plat/omap-serial.h> #include "mux.h" #include "pm.h"
@@ -127,7 +128,7 @@ static struct omap_musb_board_data musb_board_data = {static void __init rx51_init (void ) {omap3_mux_init (board_mux,OMAP_PACKAGE_CBB ); -omap_serial_init (); +omap_serial_init (NULL );usb_musb_init (&musb_board_data);rx51_peripherals_init ();
arch/arm/mach-omap2/board-ti8168evm.c +1 -1
@@ -42,7 +42,7 @@ static void __init ti8168_evm_init_irq(void)static void __init ti8168_evm_init (void ) { -omap_serial_init (); +omap_serial_init (NULL ); }static void __init ti8168_evm_map_io (void )
arch/arm/mach-omap2/board-zoom-peripherals.c +2 -1
@@ -26,6 +26,7 @@#include <plat/common.h> #include <plat/usb.h> +#include <plat/omap-serial.h> #include <mach/board-zoom.h>
@@ -394,5 +395,5 @@ void __init zoom_peripherals_init(void)platform_device_register (&omap_vwlan_device);usb_musb_init (&musb_board_data);enable_board_wakeup_source (); -omap_serial_init (); +omap_serial_init (NULL ); }
arch/arm/mach-omap2/serial.c +103 -5
161 lines not on this page · raw message
arch/arm/plat-omap/include/plat/omap-serial.h +11 -3
@@ -51,7 +51,11 @@#define OMAP_UART_DMA_CH_FREE -1 -#define RX_TIMEOUT (3 * HZ) +#define RX_TIMEOUT (3 * HZ)/* RX DMA timeout (jiffies) */ +#define DEFAULT_RXDMA_TIMEOUT 1/* RX DMA polling rate (us) */ +#define DEFAULT_RXDMA_BUFSIZE 4096/* RX DMA buffer size */ +#define DEFAULT_IDLE_TIMEOUT (5 * HZ)/* UART idle timeout (secs) */ +#define OMAP_MAX_HSUART_PORTS 4#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
@@ -64,6 +68,9 @@ struct omap_uart_port_info {upf_t flags;/* UPF_* flags */ unsigned int errata;unsigned int console_uart; +unsigned int dma_rx_buf_size;/* DMA Rx Buffer Size */ +unsigned int dma_rx_timeout;/* DMA RX timeout */ +unsigned int idle_timeout;/* OMAP UART idle timeout */ void __iomem *wk_st;void __iomem *wk_en;
@@ -91,8 +98,8 @@ struct uart_omap_dma {spinlock_t rx_lock;/* timer to poll activity on rx dma */ struct timer_list rx_timer; -int rx_buf_size; -int rx_timeout; +unsigned int rx_buf_size; +unsigned int rx_timeout; };struct uart_omap_port {
@@ -120,6 +127,7 @@ struct uart_omap_port {char name[20 ];unsigned long port_activity;struct timer_list inactivity_timer; +unsigned int idle_timeout;unsigned int errata;int can_sleep;
arch/arm/plat-omap/include/plat/serial.h +4 -2
@@ -103,9 +103,11 @@#ifndef __ASSEMBLER__struct omap_board_data ; +struct omap_uart_port_info ; -extern void omap_serial_init (void ); -extern void omap_serial_init_port (struct omap_board_data *bdata); +extern void omap_serial_init (struct omap_uart_port_info *platform_data); +extern void omap_serial_init_port (struct omap_board_data *bdata, +struct omap_uart_port_info *platform_data);extern void omap_uart_prepare_idle (int num);extern void omap_uart_resume_idle (int num);#endif
drivers/tty/serial/omap-serial.c +5 -5
@@ -47,8 +47,6 @@#define omap_uart_console (port) NULL#endif -#define OMAP_UART_CLK_PUT_DELAY (5 * HZ) -static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS ];/* Forward declaration of functions */
@@ -139,7 +137,7 @@ static void serial_omap_port_enable(struct uart_omap_port *up) } up->can_sleep =0 ; -mod_timer (&up->inactivity_timer, jiffies +OMAP_UART_CLK_PUT_DELAY ); +mod_timer (&up->inactivity_timer, jiffies + up->idle_timeout); }void omap_uart_prepare_idle (int num)
@@ -1412,16 +1410,18 @@ static int serial_omap_probe(struct platform_device *pdev) up->uart_dma.uart_dma_tx = dma_tx->start; up->uart_dma.uart_dma_rx = dma_rx->start; up->use_dma =1 ; - up->uart_dma.rx_buf_size =4096 ; - up->uart_dma.rx_timeout =2 ; + up->uart_dma.rx_buf_size = omap_up_info->dma_rx_buf_size; + up->uart_dma.rx_timeout = omap_up_info->dma_rx_timeout;spin_lock_init (&(up->uart_dma.tx_lock));spin_lock_init (&(up->uart_dma.rx_lock)); up->uart_dma.tx_dma_channel =OMAP_UART_DMA_CH_FREE ; up->uart_dma.rx_dma_channel =OMAP_UART_DMA_CH_FREE ; } +init_timer (&(up->inactivity_timer)); up->inactivity_timer.function = serial_omap_inactivity_timer; up->inactivity_timer.data = up->pdev->id; + up->idle_timeout = omap_up_info->idle_timeout;pm_runtime_enable (&pdev->dev);pm_runtime_irq_safe (&pdev->dev);
Signature · 1 line
1.7.1
PATCH 6/7 OMAP: Serial: Allow UART parameters to be configured from board file
Hi,
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency
Quoted 21 lines
arch/arm/mach-omap2/serial.c +9
-0@@ -44,6 +44,15 @@static int omap_uart_con_id__initdata =-1 ; +static struct omap_uart_port_info omap_serial_default_info[] = { + { + .dma_enabled =0 , + .dma_rx_buf_size =DEFAULT_RXDMA_BUFSIZE , + .dma_rx_timeout =DEFAULT_RXDMA_TIMEOUT , + .idle_timeout =DEFAULT_IDLE_TIMEOUT , + }, +}; +static int uart_idle_hwmod (struct omap_device *od) {omap_hwmod_idle (od->hwmods[0 ]);@@ -66,6 +75,54 @@ static struct omap_device_pm_latency
omap_uart_latency[]
Quoted 20 lines
arch/arm/mach-omap2/serial.c +16
-0= { }, }; +#ifdef CONFIG_OMAP_MUX +static struct omap_device_pad default_serial0_pads[]__initdata = { + { + .name ="uart1_rx.uart1_rx" , + .flags =OMAP_DEVICE_PAD_REMUX |OMAP_DEVICE_PAD_WAKEUP , + .enable =OMAP_MUX_MODE0 , + }, +}; + +static struct omap_device_pad default_serial1_pads[]__initdata = { + { + .name ="uart2_rx.uart2_rx" , + .flags =OMAP_DEVICE_PAD_REMUX |OMAP_DEVICE_PAD_WAKEUP , + .enable =OMAP_MUX_MODE0 , + }, +};
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency omap_uart_latency[] = {
Quoted 10 lines
arch/arm/mach-omap2/serial.c +10
-0+ +static struct omap_device_pad default_serial2_pads[]__initdata = { + { + .name ="uart3_rx_irrx.uart3_rx_irrx" , + .flags =OMAP_DEVICE_PAD_REMUX |OMAP_DEVICE_PAD_WAKEUP , + .enable =OMAP_MUX_MODE0 , + }, +}; + +static struct omap_device_pad default_omap36xx_serial3_pads[]__initdata
=
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency omap_uart_latency[] = {
Quoted 9 lines
arch/arm/mach-omap2/serial.c +8
-0{ + { + .name = "gpmc_wait3.uart4_rx", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = OMAP_MUX_MODE2, + }, +}; + +static struct omap_device_pad default_omap4_serial3_pads[] __initdata =
{
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency omap_uart_latency[] = { · line 117
Quoted 6 lines
arch/arm/mach-omap2/serial.c +6
-0+ { + .name = "uart4_rx.uart4_rx", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = OMAP_MUX_MODE0, + }, +};
Here only the UART RX pins are muxed, so what about the cts, rts, tx pins? Is it consistent that across all socs that only UART3 would have UART/IRDA functions capability so that serial2 pads can always be called "rx_irxx" ?.
Thanks,
sricharan
Quoted 5 lines
arch/arm/mach-omap2/serial.c +0
-1--To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 6/7 OMAP: Serial: Allow UART parameters to be configured from board file
Quoted 64 lines · Sricharan R
Hi,
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency
Quoted 21 lines
arch/arm/mach-omap2/serial.c +9
-0@@ -44,6 +44,15 @@static int omap_uart_con_id__initdata =-1 ; +static struct omap_uart_port_info omap_serial_default_info[] = { + ? ? ?{ + ? ? ? ? ? ? ?.dma_enabled ? ?= 0, + ? ? ? ? ? ? ?.dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE, + ? ? ? ? ? ? ?.dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT, + ? ? ? ? ? ? ?.idle_timeout ? = DEFAULT_IDLE_TIMEOUT, + ? ? ?}, +}; +static int uart_idle_hwmod (struct omap_device *od) { ? ? ? omap_hwmod_idle(od->hwmods[0]);@@ -66,6 +75,54 @@ static struct omap_device_pm_latencyomap_uart_latency[]
Quoted 20 lines
arch/arm/mach-omap2/serial.c +16
-0= { ? ? ? }, }; +#ifdef CONFIG_OMAP_MUX +static struct omap_device_pad default_serial0_pads[]__initdata = { + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart1_rx.uart1_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +}; + +static struct omap_device_pad default_serial1_pads[]__initdata = { + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart2_rx.uart2_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +};arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 104
Quoted 10 lines
arch/arm/mach-omap2/serial.c +10
-0+ +static struct omap_device_pad default_serial2_pads[]__initdata = { + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart3_rx_irrx.uart3_rx_irrx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +}; + +static struct omap_device_pad default_omap36xx_serial3_pads[]__initdata =
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 113
Quoted 9 lines
arch/arm/mach-omap2/serial.c +8
-0{ + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "gpmc_wait3.uart4_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE2, + ? ? ?}, +}; + +static struct omap_device_pad default_omap4_serial3_pads[] __initdata ={
Quoted 7 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 119
Quoted 6 lines
arch/arm/mach-omap2/serial.c +6
-0+ ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart4_rx.uart4_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +};Here only the UART RX pins are muxed, so what about the cts, rts, tx pins?
The intention here is to enable wakeup capabilities for uart rx pad.
AFAIK most of the boards are currently dependent on bootloader for uart-muxing if any board is not dependent on bootloader then we can use omap_serial_init_port along with board_mux_info from board.
Prior to this change uart wakeup is based on rx_pad and we were populating offset and using omap_ctrl api's to read/write which is cleaned up now. Most of boards are dependent on uart-rx wakeup to avoid breaking any board support we
are using omap_serial_init by filling default values, which provides us with same
environment but with right approach towards handling mux data with a handshake with
hwmod framework.
So if any board needs specific mux they can go ahead and add required mux data in
board file and use map_serial_init_port instead of current omap_serial_init.
Quoted 3 lines
Is it consistent that across all socs that only UART3 would have UART/IRDA functions capability so that serial2 pads can always be called "
rx_irxx" ?.
Yes from OMAP2420 to OMAP4430 uart3 can used as irda.
--
Thanks,
Govindraj.R
PATCH 6/7 OMAP: Serial: Allow UART parameters to be configured from board file
Hi,
Quoted 5 lines
-----Original Message-----
From: Govindraj [mailto:govindraj.ti at gmail.com]
Sent: Wednesday, March 02, 2011 1:11 PM
To: Sricharan R
Cc: Govindraj.R; linux-omap at vger.kernel.org;
linux-serial at vger.kernel.org;
Quoted 8 lines
linux-arm-kernel at lists.infradead.org; Jon Hunter; Tony Lindgren; Benoit Cousson; Kevin Hilman; Paul Walmsley; Rajendra Nayak; Deepak Kattungal
Subject: Re: [PATCH 6/7] OMAP: Serial: Allow UART parameters to be configured from board fileQuoted 2 lines · Sricharan R
Hi,
Review
Quoted 1 line
(quoted diff) +0
-0
b/arch/arm/mach-omap2/serial.c
Quoted 25 lines
Quoted 25 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency
Quoted 20 lines
index 755f4aa..530e9e3 100644
arch/arm/mach-omap2/serial.c +9
-0@@ -44,6 +44,15 @@static int omap_uart_con_id__initdata =-1 ; +static struct omap_uart_port_info omap_serial_default_info[] = { + ? ? ?{ + ? ? ? ? ? ? ?.dma_enabled ? ?= 0, + ? ? ? ? ? ? ?.dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE, + ? ? ? ? ? ? ?.dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT, + ? ? ? ? ? ? ?.idle_timeout ? = DEFAULT_IDLE_TIMEOUT, + ? ? ?}, +}; +static int uart_idle_hwmod (struct omap_device *od) { ? ? ? omap_hwmod_idle(od->hwmods[0]);@@ -66,6 +75,54 @@ static struct omap_device_pm_latencyomap_uart_latency[]
Quoted 4 lines
arch/arm/mach-omap2/serial.c +0
-0= { ? ? ? }, };
Quoted 5 lines
Quoted 5 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 83
Quoted 5 lines
arch/arm/mach-omap2/serial.c +5
-0+#ifdef CONFIG_OMAP_MUX +static struct omap_device_pad default_serial0_pads[] __initdata = { + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart1_rx.uart1_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |
OMAP_DEVICE_PAD_WAKEUP,
Quoted 8 lines
Quoted 8 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 91
Quoted 8 lines
arch/arm/mach-omap2/serial.c +8
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +}; + +static struct omap_device_pad default_serial1_pads[]__initdata = { + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart2_rx.uart2_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |
OMAP_DEVICE_PAD_WAKEUP,
Quoted 8 lines
Quoted 8 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 99
Quoted 8 lines
arch/arm/mach-omap2/serial.c +8
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +}; + +static struct omap_device_pad default_serial2_pads[]__initdata = { + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart3_rx_irrx.uart3_rx_irrx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |
OMAP_DEVICE_PAD_WAKEUP,
Quoted 5 lines
Quoted 5 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 104
Quoted 5 lines
arch/arm/mach-omap2/serial.c +5
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +}; + +static struct omap_device_pad default_omap36xx_serial3_pads[]
__initdata
Quoted 5 lines
Quoted 5 lines
=
Quoted 4 lines
arch/arm/mach-omap2/serial.c +3
-0{ + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "gpmc_wait3.uart4_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |
OMAP_DEVICE_PAD_WAKEUP,
Quoted 5 lines
Quoted 5 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 113
Quoted 5 lines
arch/arm/mach-omap2/serial.c +5
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE2, + ? ? ?}, +}; + +static struct omap_device_pad default_omap4_serial3_pads[]__initdata
=
Quoted 4 lines
Quoted 4 lines
{
Quoted 3 lines
arch/arm/mach-omap2/serial.c +3
-0+ ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart4_rx.uart4_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |
OMAP_DEVICE_PAD_WAKEUP,
Quoted 12 lines
Quoted 4 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 119
Quoted 3 lines
arch/arm/mach-omap2/serial.c +3
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +};Here only the UART RX pins are muxed, so what about the cts, rts, tx
pins?
The intention here is to enable wakeup capabilities for uart rx pad.
AFAIK most of the boards are currently dependent on bootloader for uart-muxing if any board is not dependent on bootloader then we can use
omap_serial_init_portalong withboard_mux_infofrom board.
Yes. The idea is to be independent of the bootloaders for mux settings.
Quoted 1 line
Prior to this change uart wakeup is based on
rx_padand we were
populating
Quoted 9 lines
offset and using
omap_ctrlapi's to read/write which is cleaned up now. Most of boards are dependent on uart-rx wakeup to avoid breaking any board support we
are usingomap_serial_initby filling default values, which provides us with same
environment but with right approach towards handling mux data with a handshake with
hwmod framework.
Now, in this change only the RX pin is configured. So if some board uses omap_serial_init then only the RX is going to be configured. How will they configure the rest of the pins?
They cannot call omap_serial_init_port after this just to configure the rest of the mux pins( cts, rts, tx).
So data which is passed from omap_serial_init should have the configuration
for all the pins, and this default data should be consistent across atleast
some boards, so that they can use this. This will reduce the data duplication across board files.
If this is not true, then all the pads can be configured from the board files itself using omap_serial_init_port and you can set the required RX wakeup capability there as well.
Quoted 9 lines
So if any board needs specific mux they can go ahead and add required mux data in
board file and usemap_serial_init_portinstead of currentomap_serial_init.Quoted 1 line
Is it consistent that across all socs that only UART3 would have
UART/IRDA
Quoted 1 line
functions capability so that serial2 pads can always be called
"rx_irxx"
Quoted 4 lines
Quoted 1 line
?.
Yes from OMAP2420 to OMAP4430 uart3 can used as irda.
Ok.
Quoted 3 lines
--
Thanks,
Govindraj.R
PATCH 6/7 OMAP: Serial: Allow UART parameters to be configured from board file
Quoted 113 lines · Sricharan R
Hi,
Quoted 5 lines
-----Original Message-----
From: Govindraj [mailto:govindraj.ti at gmail.com]
Sent: Wednesday, March 02, 2011 1:11 PM
To: Sricharan R
Cc: Govindraj.R; linux-omap at vger.kernel.org;linux-serial at vger.kernel.org;
Quoted 8 lines
linux-arm-kernel at lists.infradead.org; Jon Hunter; Tony Lindgren; Benoit Cousson; Kevin Hilman; Paul Walmsley; Rajendra Nayak; Deepak Kattungal
Subject: Re: [PATCH 6/7] OMAP: Serial: Allow UART parameters to be configured from board fileQuoted 2 lines · Sricharan R
Hi,
Review
Quoted 1 line
(quoted diff) +0
-0
b/arch/arm/mach-omap2/serial.cQuoted 25 lines
Quoted 25 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency
Quoted 20 lines
index 755f4aa..530e9e3 100644
arch/arm/mach-omap2/serial.c +9
-0@@ -44,6 +44,15 @@static int omap_uart_con_id__initdata =-1 ; +static struct omap_uart_port_info omap_serial_default_info[] = { + ? ? ?{ + ? ? ? ? ? ? ?.dma_enabled ? ?= 0, + ? ? ? ? ? ? ?.dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE, + ? ? ? ? ? ? ?.dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT, + ? ? ? ? ? ? ?.idle_timeout ? = DEFAULT_IDLE_TIMEOUT, + ? ? ?}, +}; +static int uart_idle_hwmod (struct omap_device *od) { ? ? ? omap_hwmod_idle(od->hwmods[0]);@@ -66,6 +75,54 @@ static struct omap_device_pm_latencyomap_uart_latency[]
Quoted 4 lines
arch/arm/mach-omap2/serial.c +0
-0= { ? ? ? }, };Quoted 5 lines
Quoted 5 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 83
Quoted 5 lines
arch/arm/mach-omap2/serial.c +5
-0+#ifdef CONFIG_OMAP_MUX +static struct omap_device_pad default_serial0_pads[] __initdata = { + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart1_rx.uart1_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |
OMAP_DEVICE_PAD_WAKEUP,Quoted 8 lines
Quoted 8 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 91
Quoted 8 lines
arch/arm/mach-omap2/serial.c +8
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +}; + +static struct omap_device_pad default_serial1_pads[]__initdata = { + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart2_rx.uart2_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |
OMAP_DEVICE_PAD_WAKEUP,Quoted 8 lines
Quoted 8 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 99
Quoted 8 lines
arch/arm/mach-omap2/serial.c +8
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +}; + +static struct omap_device_pad default_serial2_pads[]__initdata = { + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart3_rx_irrx.uart3_rx_irrx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |
OMAP_DEVICE_PAD_WAKEUP,Quoted 5 lines
Quoted 5 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 104
Quoted 5 lines
arch/arm/mach-omap2/serial.c +5
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +}; + +static struct omap_device_pad default_omap36xx_serial3_pads[]
__initdataQuoted 5 lines
Quoted 5 lines
=
Quoted 4 lines
arch/arm/mach-omap2/serial.c +3
-0{ + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "gpmc_wait3.uart4_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |
OMAP_DEVICE_PAD_WAKEUP,Quoted 5 lines
Quoted 5 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 113
Quoted 5 lines
arch/arm/mach-omap2/serial.c +5
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE2, + ? ? ?}, +}; + +static struct omap_device_pad default_omap4_serial3_pads[]__initdata =
Quoted 4 lines
Quoted 4 lines
{
Quoted 3 lines
arch/arm/mach-omap2/serial.c +3
-0+ ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart4_rx.uart4_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |
OMAP_DEVICE_PAD_WAKEUP,Quoted 12 lines
Quoted 4 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 119
Quoted 3 lines
arch/arm/mach-omap2/serial.c +3
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +};Here only the UART RX pins are muxed, so what about the cts, rts, tx
pins?
The intention here is to enable wakeup capabilities for uart rx pad.
AFAIK most of the boards are currently dependent on bootloader for uart-muxing if any board is not dependent on bootloader then we can use
omap_serial_init_portalong withboard_mux_infofrom board.Yes. The idea is to be independent of the bootloaders for mux settings.
Quoted 1 line
Prior to this change uart wakeup is based on
rx_padand we werepopulating
Quoted 9 lines
offset and using
omap_ctrlapi's to read/write which is cleaned up now. Most of boards are dependent on uart-rx wakeup to avoid breaking any board support we
are usingomap_serial_initby filling default values, which provides us with same
environment but with right approach towards handling mux data with a handshake with
hwmod framework.
Quoted 3 lines
Now, in this change only the RX pin is configured. So if some board uses
omap_serial_initthen only the RX is going to be configured. How will they configure the rest of the pins?
They should call omap_serial_init_port to configure each individual uart with mux_info filled and not use omap_serial_init.
If any board is not dependent for mux from u-boot then they use above said init_port func.
Quoted 2 lines
They cannot call
omap_serial_init_portafter this just to configure the rest of the muxpins( cts, rts, tx).
No. You need to use either omap_serial_init_port or omap_serial_init you cannot call both apis from board file please refer to both func documentation.
Also please note i am not configuring all uart pins for pullups and pull downs with this patch series and its not related to this patch series. I am only enabling wakeup-enable pin for rx as it was done before.
Quoted 11 lines
So data which is passed from
omap_serial_initshould have the configuration
for all the pins, and this default data should be consistent across atleast
some boards, so that they can use this. This will reduce the data duplication across board files.If this is not true, then all the pads can be configured from the board files itself using
omap_serial_init_portand you can set the required RX wakeup capability there as well.
Yes that be done but currently but that is not in my intention here with my patch
I just want to retain rx wakeup by default to avoid breaking support for any board.
Adding pin mux for each individual pin is a separate activity where I also need access to various boards So I am leaving that to developers who want to configure
for the corresponding boards using init_port api.
Removing mux from u-boot level and adding it to board file is beyond the scope of this
patch series and is a separate topic of discussion, as current patch series assumes that uarts are muxed from u-boot level and needs to only enable wakeup capability for rx-pin.
Hope this clarifies.
--
Thanks,
Govindraj.R
Quoted 19 lines
Quoted 9 lines
So if any board needs specific mux they can go ahead and add required mux data in
board file and usemap_serial_init_portinstead of currentomap_serial_init.Quoted 1 line
Is it consistent that across all socs that only UART3 would have
UART/IRDA
Quoted 1 line
functions capability so that serial2 pads can always be called
"
rx_irxx"Quoted 4 lines
Quoted 1 line
?.
Yes from OMAP2420 to OMAP4430 uart3 can used as irda.
Ok.
Quoted 3 lines
--
Thanks,
Govindraj.R
Tony Lindgren
maintainerPATCH 6/7 OMAP: Serial: Allow UART parameters to be configured from board file
Quoted 8 lines · Govindraj
Quoted 8 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
+static struct
omap_device_paddefault_serial1_pads[]__initdata= {
+ ? ? ?{
+ ? ? ? ? ? ? ?.name ? = "uart2_rx.uart2_rx",
+ ? ? ? ? ? ? ?.flags ?=OMAP_DEVICE_PAD_REMUX|
OMAP_DEVICE_PAD_WAKEUP,Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
+ ? ? ? ? ? ? ?.enable =
OMAP_MUX_MODE0,
+ ? ? ?},
...
AFAIK you should only need the OMAP_DEVICE_PAD_REMUX option for omap24xx. And if you use that option, you also need the .idle value.
Tony
PATCH 6/7 OMAP: Serial: Allow UART parameters to be configured from board file
Quoted 6 lines · Tony Lindgren
Quoted 5 lines · Govindraj
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
+static struct
omap_device_paddefault_serial1_pads[]__initdata= {
+ ? ? ?{
+ ? ? ? ? ? ? ?.name ? = "uart2_rx.uart2_rx",
+ ? ? ? ? ? ? ?.flags ?=OMAP_DEVICE_PAD_REMUX|
Quoted 9 lines
Quoted 3 lines
Quoted 3 lines
OMAP_DEVICE_PAD_WAKEUP,Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
+ ? ? ? ? ? ? ?.enable =
OMAP_MUX_MODE0,
+ ? ? ?},...
AFAIK you should only need the
OMAP_DEVICE_PAD_REMUXoption for omap24xx. And if you use that option, you also need the .idle value.
Yes correct. I should avoid enabling rx-pad wakeup for omap24xx and populate rx pad wakeup only for 3xxx onwards as done prior to this patch.
Will correct this in next version.
--
Thanks,
Govindraj.R
Quoted 2 lines
Tony
PATCH 6/7 OMAP: Serial: Allow UART parameters to be configured from board file
In reply to GovindrajHi,
Quoted 5 lines
-----Original Message-----
From: Govindraj [mailto:govindraj.ti at gmail.com]
Sent: Wednesday, March 02, 2011 3:37 PM
To: Sricharan R
Cc: Govindraj.R; linux-omap at vger.kernel.org;
linux-serial at vger.kernel.org;
Quoted 19 lines
linux-arm-kernel at lists.infradead.org; Jon Hunter; Tony Lindgren; Benoit Cousson; Kevin Hilman; Paul Walmsley; Rajendra Nayak; Deepak Kattungal
Subject: Re: [PATCH 6/7] OMAP: Serial: Allow UART parameters to be configured from board fileQuoted 13 lines · Sricharan R
Hi,
Quoted 5 lines
-----Original Message-----
From: Govindraj [mailto:govindraj.ti at gmail.com]
Sent: Wednesday, March 02, 2011 1:11 PM
To: Sricharan R
Cc: Govindraj.R; linux-omap at vger.kernel.org;linux-serial at vger.kernel.org;
Quoted 6 lines
linux-arm-kernel at lists.infradead.org; Jon Hunter; Tony Lindgren; Benoit Cousson; Kevin Hilman; Paul Walmsley; Rajendra Nayak; Deepak Kattungal
Subject: Re: [PATCH 6/7] OMAP: Serial: Allow UART parameters to be configured from board fileOn Wed, Mar 2, 2011 at 12:46 AM, Sricharan R <[email protected]>
Quoted 63 lines · wrote:
Quoted 63 lines
Quoted 2 lines
Quoted 2 lines
Hi,
Review
Quoted 1 line
(quoted diff) +0
-0
b/arch/arm/mach-omap2/serial.cQuoted 25 lines
Quoted 25 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency
Quoted 20 lines
index 755f4aa..530e9e3 100644
arch/arm/mach-omap2/serial.c +9
-0@@ -44,6 +44,15 @@static int omap_uart_con_id__initdata =-1 ; +static struct omap_uart_port_info omap_serial_default_info[] = { + ? ? ?{ + ? ? ? ? ? ? ?.dma_enabled ? ?= 0, + ? ? ? ? ? ? ?.dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE, + ? ? ? ? ? ? ?.dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT, + ? ? ? ? ? ? ?.idle_timeout ? = DEFAULT_IDLE_TIMEOUT, + ? ? ?}, +}; +static int uart_idle_hwmod (struct omap_device *od) { ? ? ? omap_hwmod_idle(od->hwmods[0]);@@ -66,6 +75,54 @@ static struct omap_device_pm_latencyomap_uart_latency[]
Quoted 4 lines
arch/arm/mach-omap2/serial.c +0
-0= { ? ? ? }, };Quoted 5 lines
Quoted 5 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 83
Quoted 5 lines
arch/arm/mach-omap2/serial.c +5
-0+#ifdef CONFIG_OMAP_MUX +static struct omap_device_pad default_serial0_pads[] __initdata = { + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart1_rx.uart1_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |
OMAP_DEVICE_PAD_WAKEUP,Quoted 8 lines
Quoted 8 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 91
Quoted 8 lines
arch/arm/mach-omap2/serial.c +8
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +}; + +static struct omap_device_pad default_serial1_pads[]__initdata = { + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart2_rx.uart2_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |
OMAP_DEVICE_PAD_WAKEUP,Quoted 8 lines
Quoted 8 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 99
Quoted 8 lines
arch/arm/mach-omap2/serial.c +8
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +}; + +static struct omap_device_pad default_serial2_pads[]__initdata = { + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart3_rx_irrx.uart3_rx_irrx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |
OMAP_DEVICE_PAD_WAKEUP,Quoted 5 lines
Quoted 5 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 104
Quoted 5 lines
arch/arm/mach-omap2/serial.c +5
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +}; + +static struct omap_device_pad default_omap36xx_serial3_pads[]
__initdataQuoted 5 lines
Quoted 5 lines
=
Quoted 4 lines
arch/arm/mach-omap2/serial.c +3
-0{ + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "gpmc_wait3.uart4_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |
Quoted 6 lines
Quoted 6 lines
OMAP_DEVICE_PAD_WAKEUP,Quoted 5 lines
Quoted 5 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 113
Quoted 5 lines
arch/arm/mach-omap2/serial.c +5
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE2, + ? ? ?}, +}; + +static struct omap_device_pad default_omap4_serial3_pads[]
__initdata
Quoted 31 lines
Quoted 31 lines
=
Quoted 4 lines
Quoted 4 lines
{
Quoted 3 lines
arch/arm/mach-omap2/serial.c +3
-0+ ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart4_rx.uart4_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |
OMAP_DEVICE_PAD_WAKEUP,Quoted 12 lines
Quoted 4 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 119
Quoted 3 lines
arch/arm/mach-omap2/serial.c +3
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +};Here only the UART RX pins are muxed, so what about the cts, rts, tx
pins?
The intention here is to enable wakeup capabilities for uart rx pad.
AFAIK most of the boards are currently dependent on bootloader for uart-muxing if any board is not dependent on bootloader then we can use
omap_serial_init_portalong withboard_mux_infofrom board.Yes. The idea is to be independent of the bootloaders for mux settings.
Quoted 1 line
Prior to this change uart wakeup is based on
rx_padand we werepopulating
Quoted 9 lines
offset and using
omap_ctrlapi's to read/write which is cleaned up now. Most of boards are dependent on uart-rx wakeup to avoid breaking any board support we
are usingomap_serial_initby filling default values, which provides us with same
environment but with right approach towards handling mux data with a handshake with
hwmod framework.
Quoted 1 line
Quoted 1 line
Now, in this change only the RX pin is configured. So if some board
uses
Quoted 9 lines
Quoted 2 lines
omap_serial_initthen only the RX is going to be configured. How will they configure the rest of the pins?They should call
omap_serial_init_portto configure each individual uart withmux_infofilled and not useomap_serial_init.If any board is not dependent for mux from u-boot then they use above
said
Quoted 27 lines
init_portfunc.Quoted 2 lines
They cannot call
omap_serial_init_portafter this just to configure the rest of the muxpins( cts, rts, tx).No. You need to use either
omap_serial_init_portoromap_serial_inityou cannot call both apis from board file please refer to both func documentation.Also please note i am not configuring all uart pins for pullups and pull downs
with this patch series and its not related to this patch series. I am only enabling wakeup-enable pin for rx as it was done before.Quoted 11 lines
So data which is passed from
omap_serial_initshould have the configuration
for all the pins, and this default data should be consistent across atleast
some boards, so that they can use this. This will reduce the data duplication across board files.If this is not true, then all the pads can be configured from the board files itself using
omap_serial_init_portand you can set the required RX wakeup capability there as well.
Quoted 6 lines
Yes that be done but currently but that is not in my intention here with my patch
I just want to retain rx wakeup by default to avoid breaking support for any board.Adding pin mux for each individual pin is a separate activity where I
also
Quoted 7 lines
need access to various boards So I am leaving that to developers who want to configure
for the corresponding boards usinginit_portapi.Removing mux from u-boot level and adding it to board file is beyond the scope of this
patch series and is a separate topic of discussion, as current patch
series
Quoted 6 lines
assumes that uarts are muxed from u-boot level and needs to only enable wakeup
capability for rx-pin.Hope this clarifies.
It is true that this patch is not intending to configure the pads.
But my question is, after this patch say
1) some board file calls omap_serial_port.
2) As a result , all the uarts devices are build and only the Rx pad is
configured for each device.
3) After this there will be no way of configuring the rest of the pads
??
That should not happen. Also relying that the bootloaders are going to do the configuration is not correct.
So if some board calls omap_serial_port then there should be default
values for all pads which a board can use, otherwise the board calls omap_serial_init_port for each of the device.
Quoted 24 lines
--
Thanks,
Govindraj.RQuoted 19 lines
Quoted 9 lines
So if any board needs specific mux they can go ahead and add required mux data in
board file and usemap_serial_init_portinstead of currentomap_serial_init.Quoted 1 line
Is it consistent that across all socs that only UART3 would have
UART/IRDA
Quoted 1 line
functions capability so that serial2 pads can always be called
"
rx_irxx"Quoted 4 lines
Quoted 1 line
?.
Yes from OMAP2420 to OMAP4430 uart3 can used as irda.
Ok.
Quoted 3 lines
--
Thanks,
Govindraj.R
PATCH 6/7 OMAP: Serial: Allow UART parameters to be configured from board file
Quoted 199 lines · Sricharan R
Hi,
Quoted 5 lines
-----Original Message-----
From: Govindraj [mailto:govindraj.ti at gmail.com]
Sent: Wednesday, March 02, 2011 3:37 PM
To: Sricharan R
Cc: Govindraj.R; linux-omap at vger.kernel.org;linux-serial at vger.kernel.org;
Quoted 19 lines
linux-arm-kernel at lists.infradead.org; Jon Hunter; Tony Lindgren; Benoit Cousson; Kevin Hilman; Paul Walmsley; Rajendra Nayak; Deepak Kattungal
Subject: Re: [PATCH 6/7] OMAP: Serial: Allow UART parameters to be configured from board fileQuoted 13 lines · Sricharan R
Hi,
Quoted 5 lines
-----Original Message-----
From: Govindraj [mailto:govindraj.ti at gmail.com]
Sent: Wednesday, March 02, 2011 1:11 PM
To: Sricharan R
Cc: Govindraj.R; linux-omap at vger.kernel.org;linux-serial at vger.kernel.org;
Quoted 6 lines
linux-arm-kernel at lists.infradead.org; Jon Hunter; Tony Lindgren; Benoit Cousson; Kevin Hilman; Paul Walmsley; Rajendra Nayak; Deepak Kattungal
Subject: Re: [PATCH 6/7] OMAP: Serial: Allow UART parameters to be configured from board fileOn Wed, Mar 2, 2011 at 12:46 AM, Sricharan R <[email protected]>
Quoted 63 lines · wrote:
Quoted 63 lines
Quoted 2 lines
Quoted 2 lines
Hi,
Review
Quoted 1 line
(quoted diff) +0
-0
b/arch/arm/mach-omap2/serial.cQuoted 25 lines
Quoted 25 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency
Quoted 20 lines
index 755f4aa..530e9e3 100644
arch/arm/mach-omap2/serial.c +9
-0@@ -44,6 +44,15 @@static int omap_uart_con_id__initdata =-1 ; +static struct omap_uart_port_info omap_serial_default_info[] = { + ? ? ?{ + ? ? ? ? ? ? ?.dma_enabled ? ?= 0, + ? ? ? ? ? ? ?.dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE, + ? ? ? ? ? ? ?.dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT, + ? ? ? ? ? ? ?.idle_timeout ? = DEFAULT_IDLE_TIMEOUT, + ? ? ?}, +}; +static int uart_idle_hwmod (struct omap_device *od) { ? ? ? omap_hwmod_idle(od->hwmods[0]);@@ -66,6 +75,54 @@ static struct omap_device_pm_latencyomap_uart_latency[]
Quoted 4 lines
arch/arm/mach-omap2/serial.c +0
-0= { ? ? ? }, };Quoted 5 lines
Quoted 5 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 83
Quoted 5 lines
arch/arm/mach-omap2/serial.c +5
-0+#ifdef CONFIG_OMAP_MUX +static struct omap_device_pad default_serial0_pads[] __initdata = { + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart1_rx.uart1_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |
OMAP_DEVICE_PAD_WAKEUP,Quoted 8 lines
Quoted 8 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 91
Quoted 8 lines
arch/arm/mach-omap2/serial.c +8
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +}; + +static struct omap_device_pad default_serial1_pads[]__initdata = { + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart2_rx.uart2_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |
OMAP_DEVICE_PAD_WAKEUP,Quoted 8 lines
Quoted 8 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 99
Quoted 8 lines
arch/arm/mach-omap2/serial.c +8
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +}; + +static struct omap_device_pad default_serial2_pads[]__initdata = { + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart3_rx_irrx.uart3_rx_irrx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |
OMAP_DEVICE_PAD_WAKEUP,Quoted 5 lines
Quoted 5 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 104
Quoted 5 lines
arch/arm/mach-omap2/serial.c +5
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +}; + +static struct omap_device_pad default_omap36xx_serial3_pads[]
__initdataQuoted 5 lines
Quoted 5 lines
=
Quoted 4 lines
arch/arm/mach-omap2/serial.c +3
-0{ + ? ? ?{ + ? ? ? ? ? ? ?.name ? = "gpmc_wait3.uart4_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |Quoted 6 lines
Quoted 6 lines
OMAP_DEVICE_PAD_WAKEUP,Quoted 5 lines
Quoted 5 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 113
Quoted 5 lines
arch/arm/mach-omap2/serial.c +5
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE2, + ? ? ?}, +}; + +static struct omap_device_pad default_omap4_serial3_pads[]
__initdataQuoted 31 lines
Quoted 31 lines
=
Quoted 4 lines
Quoted 4 lines
{
Quoted 3 lines
arch/arm/mach-omap2/serial.c +3
-0+ ? ? ?{ + ? ? ? ? ? ? ?.name ? = "uart4_rx.uart4_rx", + ? ? ? ? ? ? ?.flags ?= OMAP_DEVICE_PAD_REMUX |
OMAP_DEVICE_PAD_WAKEUP,Quoted 12 lines
Quoted 4 lines
arch/arm/mach-omap2/serial.c static struct omap_device_pm_latency · line 119
Quoted 3 lines
arch/arm/mach-omap2/serial.c +3
-0+ ? ? ? ? ? ? ?.enable = OMAP_MUX_MODE0, + ? ? ?}, +};Here only the UART RX pins are muxed, so what about the cts, rts, tx
pins?
The intention here is to enable wakeup capabilities for uart rx pad.
AFAIK most of the boards are currently dependent on bootloader for uart-muxing if any board is not dependent on bootloader then we can use
omap_serial_init_portalong withboard_mux_infofrom board.Yes. The idea is to be independent of the bootloaders for mux settings.
Quoted 1 line
Prior to this change uart wakeup is based on
rx_padand we werepopulating
Quoted 9 lines
offset and using
omap_ctrlapi's to read/write which is cleaned up now. Most of boards are dependent on uart-rx wakeup to avoid breaking any board support we
are usingomap_serial_initby filling default values, which provides us with same
environment but with right approach towards handling mux data with a handshake with
hwmod framework.Quoted 1 line
Quoted 1 line
Now, in this change only the RX pin is configured. So if some board
uses
Quoted 9 lines
Quoted 2 lines
omap_serial_initthen only the RX is going to be configured. How will they configure the rest of the pins?They should call
omap_serial_init_portto configure each individual uart withmux_infofilled and not useomap_serial_init.If any board is not dependent for mux from u-boot then they use above
said
Quoted 27 lines
init_portfunc.Quoted 2 lines
They cannot call
omap_serial_init_portafter this just to configure the rest of the muxpins( cts, rts, tx).No. You need to use either
omap_serial_init_portoromap_serial_inityou cannot call both apis from board file please refer to both func documentation.Also please note i am not configuring all uart pins for pullups and pull downs
with this patch series and its not related to this patch series. I am only enabling wakeup-enable pin for rx as it was done before.Quoted 11 lines
So data which is passed from
omap_serial_initshould have the configuration
for all the pins, and this default data should be consistent across atleast
some boards, so that they can use this. This will reduce the data duplication across board files.If this is not true, then all the pads can be configured from the board files itself using
omap_serial_init_portand you can set the required RX wakeup capability there as well.Quoted 6 lines
Yes that be done but currently but that is not in my intention here with my patch
I just want to retain rx wakeup by default to avoid breaking support for any board.Adding pin mux for each individual pin is a separate activity where I
also
Quoted 7 lines
need access to various boards So I am leaving that to developers who want to configure
for the corresponding boards usinginit_portapi.Removing mux from u-boot level and adding it to board file is beyond the scope of this
patch series and is a separate topic of discussion, as current patchseries
Quoted 6 lines
assumes that uarts are muxed from u-boot level and needs to only enable wakeup
capability for rx-pin.Hope this clarifies.
It is true that this patch is not intending to configure the pads.
But my question is, after this patch say
? 1) some board file callsomap_serial_port.
? 2) As a result , all the uarts devices are build and only the Rx pad is configured for each device.
? 3) After this there will be no way of configuring the rest of the pads ??
? ? ?That should not happen. Also relying that the bootloaders are going ? ? ?to do the configuration is not correct.
Quoted 3 lines
? ? ?So if some board calls
omap_serial_portthen there should be default values for all pads which a board can use, otherwise the board callsomap_serial_init_portfor each of the device.
ok I will add default values for all pads and enable rx wakeup for rx pad.
Will incorporate in next version.
--
Thanks,
Govindraj.R
Quoted 27 lines
Quoted 26 lines
--
Thanks,
Govindraj.RQuoted 19 lines
Quoted 9 lines
So if any board needs specific mux they can go ahead and add required mux data in
board file and usemap_serial_init_portinstead of currentomap_serial_init.Quoted 1 line
Is it consistent that across all socs that only UART3 would have
UART/IRDA
Quoted 1 line
functions capability so that serial2 pads can always be called
"
rx_irxx"Quoted 4 lines
Quoted 1 line
?.
Yes from OMAP2420 to OMAP4430 uart3 can used as irda.
Ok.
Quoted 3 lines
--
Thanks,
Govindraj.R
PATCH 7/7 Serial: OMAP2+: Make the RX_TIMEOUT for DMA configurable for each UART
In reply to Govindraj.RFrom: Jon Hunter <[email protected]>
When using DMA there are two timeouts defined. The first timeout, rx_timeout, is really a polling rate in which software polls the DMA status to see if the DMA has finished. This is necessary for the RX side because we do not know how much data we will receive. The secound timeout, RX_TIMEOUT, is a timeout after which the DMA will be stopped if no more data is received. To make this clearer, rename rx_timeout as rx_poll_rate and rename the function serial_omap_rx_timeout() to serial_omap_rxdma_poll().
The OMAP-Serial driver defines an RX_TIMEOUT of 3 seconds that is used to indicate when the DMA for UART can be stopped if no more data is received. The value is a global definition that is applied to all instances of the UART.
Each UART may be used for a different purpose and so the timeout required may differ. Make this value configurable for each UART so that this value can be optimised for power savings.
--- arch/arm/mach-omap2/serial.c | 2 ++ arch/arm/plat-omap/include/plat/omap-serial.h | 6 ++++-- drivers/tty/serial/omap-serial.c | 15 ++++++++------- 3 files changed, 14 insertions(+), 9 deletions(-)
arch/arm/mach-omap2/serial.c +2 -0
@@ -48,6 +48,7 @@ static struct omap_uart_port_info omap_serial_default_info[] = { { .dma_enabled = 0, .dma_rx_buf_size = DEFAULT_RXDMA_BUFSIZE, + .dma_rx_poll_rate = DEFAULT_RXDMA_POLLRATE, .dma_rx_timeout = DEFAULT_RXDMA_TIMEOUT, .idle_timeout = DEFAULT_IDLE_TIMEOUT, },
@@ -268,6 +269,7 @@ void __init omap_serial_init_port(struct omap_board_data *bdata, pdata->flags =UPF_BOOT_AUTOCONF ; pdata->dma_enabled = info->dma_enabled; pdata->dma_rx_buf_size = info->dma_rx_buf_size; + pdata->dma_rx_poll_rate = info->dma_rx_poll_rate; pdata->dma_rx_timeout = info->dma_rx_timeout; pdata->idle_timeout = info->idle_timeout;if (bdata->id == omap_uart_con_id)
arch/arm/plat-omap/include/plat/omap-serial.h +4 -2
@@ -51,8 +51,8 @@#define OMAP_UART_DMA_CH_FREE -1 -#define RX_TIMEOUT (3 * HZ)/* RX DMA timeout (jiffies) */ -#define DEFAULT_RXDMA_TIMEOUT 1/* RX DMA polling rate (us) */ +#define DEFAULT_RXDMA_TIMEOUT (3 * HZ)/* RX DMA timeout (jiffies) */ +#define DEFAULT_RXDMA_POLLRATE 1/* RX DMA polling rate (us) */ #define DEFAULT_RXDMA_BUFSIZE 4096/* RX DMA buffer size */ #define DEFAULT_IDLE_TIMEOUT (5 * HZ)/* UART idle timeout (secs) */
@@ -70,6 +70,7 @@ struct omap_uart_port_info {unsigned int console_uart;unsigned int dma_rx_buf_size;/* DMA Rx Buffer Size */ unsigned int dma_rx_timeout;/* DMA RX timeout */ +unsigned int dma_rx_poll_rate;/* DMA RX timeout */ unsigned int idle_timeout;/* OMAP UART idle timeout */ void __iomem *wk_st;
@@ -99,6 +100,7 @@ struct uart_omap_dma {/* timer to poll activity on rx dma */ struct timer_list rx_timer;unsigned int rx_buf_size; +unsigned int rx_poll_rate;unsigned int rx_timeout; };
drivers/tty/serial/omap-serial.c +8 -7
@@ -51,7 +51,7 @@ static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];/* Forward declaration of functions */ static void uart_tx_dma_callback (int lch,u16 ch_status,void *data); -static void serial_omap_rx_timeout (unsigned long uart_no); +static void serial_omap_rxdma_poll (unsigned long uart_no);static int serial_omap_start_rxdma (struct uart_omap_port *up);static void omap_uart_mdr1_errataset (struct uart_omap_port *up);
@@ -589,7 +589,7 @@ static int serial_omap_startup(struct uart_port *port) (dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys), 0);init_timer (&(up->uart_dma.rx_timer)); - up->uart_dma.rx_timer.function = serial_omap_rx_timeout; + up->uart_dma.rx_timer.function = serial_omap_rxdma_poll; up->uart_dma.rx_timer.data = up->pdev->id;/* Currently the buffer size is 4KB. Can increase it */ up->uart_dma.rx_buf = dma_alloc_coherent(NULL,
@@ -1191,7 +1191,7 @@ static int serial_omap_resume(struct device *dev)return 0 ; } -static void serial_omap_rx_timeout (unsigned long uart_no) +static void serial_omap_rxdma_poll (unsigned long uart_no) {struct uart_omap_port *up = ui[uart_no];unsigned int curr_dma_pos, curr_transmitted_size;
@@ -1201,9 +1201,9 @@ static void serial_omap_rx_timeout(unsigned long uart_no)if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) || (curr_dma_pos ==0 )) {if (jiffies_to_msecs (jiffies - up->port_activity) < -RX_TIMEOUT ) { + up->uart_dma.rx_timeout) {mod_timer (&up->uart_dma.rx_timer, jiffies + -usecs_to_jiffies (up->uart_dma.rx_timeout)); +usecs_to_jiffies (up->uart_dma.rx_poll_rate)); }else {serial_omap_stop_rxdma (up); up->ier |= (UART_IER_RDI |UART_IER_RLSI );
@@ -1232,7 +1232,7 @@ static void serial_omap_rx_timeout(unsigned long uart_no) } }else {mod_timer (&up->uart_dma.rx_timer, jiffies + -usecs_to_jiffies (up->uart_dma.rx_timeout)); +usecs_to_jiffies (up->uart_dma.rx_poll_rate)); } up->port_activity = jiffies; }
@@ -1270,7 +1270,7 @@ static int serial_omap_start_rxdma(struct uart_omap_port *up)/* FIXME: Cache maintenance needed here? */ omap_start_dma (up->uart_dma.rx_dma_channel);mod_timer (&up->uart_dma.rx_timer, jiffies + -usecs_to_jiffies (up->uart_dma.rx_timeout)); +usecs_to_jiffies (up->uart_dma.rx_poll_rate)); up->uart_dma.rx_dma_used = true;return ret; }
@@ -1412,6 +1412,7 @@ static int serial_omap_probe(struct platform_device *pdev) up->use_dma =1 ; up->uart_dma.rx_buf_size = omap_up_info->dma_rx_buf_size; up->uart_dma.rx_timeout = omap_up_info->dma_rx_timeout; + up->uart_dma.rx_poll_rate = omap_up_info->dma_rx_poll_rate;spin_lock_init (&(up->uart_dma.tx_lock));spin_lock_init (&(up->uart_dma.rx_lock)); up->uart_dma.tx_dma_channel =OMAP_UART_DMA_CH_FREE ;
Signature · 1 line
1.7.1