~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/avr32/mach-at32ap/pm.c

Version: ~ [ linux-5.8-rc4 ] ~ [ linux-5.7.7 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.50 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.131 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.187 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.229 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.229 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * AVR32 AP Power Management
  3  *
  4  * Copyright (C) 2008 Atmel Corporation
  5  *
  6  * This program is free software; you can redistribute it and/or
  7  * modify it under the terms of the GNU General Public License
  8  * version 2 as published by the Free Software Foundation.
  9  */
 10 #include <linux/io.h>
 11 #include <linux/suspend.h>
 12 #include <linux/vmalloc.h>
 13 
 14 #include <asm/cacheflush.h>
 15 #include <asm/sysreg.h>
 16 
 17 #include <mach/chip.h>
 18 #include <mach/pm.h>
 19 #include <mach/sram.h>
 20 
 21 #include "sdramc.h"
 22 
 23 #define SRAM_PAGE_FLAGS (SYSREG_BIT(TLBELO_D) | SYSREG_BF(SZ, 1)        \
 24                                 | SYSREG_BF(AP, 3) | SYSREG_BIT(G))
 25 
 26 
 27 static unsigned long    pm_sram_start;
 28 static size_t           pm_sram_size;
 29 static struct vm_struct *pm_sram_area;
 30 
 31 static void (*avr32_pm_enter_standby)(unsigned long sdramc_base);
 32 static void (*avr32_pm_enter_str)(unsigned long sdramc_base);
 33 
 34 /*
 35  * Must be called with interrupts disabled. Exceptions will be masked
 36  * on return (i.e. all exceptions will be "unrecoverable".)
 37  */
 38 static void *avr32_pm_map_sram(void)
 39 {
 40         unsigned long   vaddr;
 41         unsigned long   page_addr;
 42         u32             tlbehi;
 43         u32             mmucr;
 44 
 45         vaddr = (unsigned long)pm_sram_area->addr;
 46         page_addr = pm_sram_start & PAGE_MASK;
 47 
 48         /*
 49          * Mask exceptions and grab the first TLB entry. We won't be
 50          * needing it while sleeping.
 51          */
 52         asm volatile("ssrf      %0" : : "i"(SYSREG_EM_OFFSET) : "memory");
 53 
 54         mmucr = sysreg_read(MMUCR);
 55         tlbehi = sysreg_read(TLBEHI);
 56         sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr));
 57 
 58         tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
 59         tlbehi |= vaddr & PAGE_MASK;
 60         tlbehi |= SYSREG_BIT(TLBEHI_V);
 61 
 62         sysreg_write(TLBELO, page_addr | SRAM_PAGE_FLAGS);
 63         sysreg_write(TLBEHI, tlbehi);
 64         __builtin_tlbw();
 65 
 66         return (void *)(vaddr + pm_sram_start - page_addr);
 67 }
 68 
 69 /*
 70  * Must be called with interrupts disabled. Exceptions will be
 71  * unmasked on return.
 72  */
 73 static void avr32_pm_unmap_sram(void)
 74 {
 75         u32     mmucr;
 76         u32     tlbehi;
 77         u32     tlbarlo;
 78 
 79         /* Going to update TLB entry at index 0 */
 80         mmucr = sysreg_read(MMUCR);
 81         tlbehi = sysreg_read(TLBEHI);
 82         sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr));
 83 
 84         /* Clear the "valid" bit */
 85         tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
 86         sysreg_write(TLBEHI, tlbehi);
 87 
 88         /* Mark it as "not accessed" */
 89         tlbarlo = sysreg_read(TLBARLO);
 90         sysreg_write(TLBARLO, tlbarlo | 0x80000000U);
 91 
 92         /* Update the TLB */
 93         __builtin_tlbw();
 94 
 95         /* Unmask exceptions */
 96         asm volatile("csrf      %0" : : "i"(SYSREG_EM_OFFSET) : "memory");
 97 }
 98 
 99 static int avr32_pm_valid_state(suspend_state_t state)
100 {
101         switch (state) {
102         case PM_SUSPEND_ON:
103         case PM_SUSPEND_STANDBY:
104         case PM_SUSPEND_MEM:
105                 return 1;
106 
107         default:
108                 return 0;
109         }
110 }
111 
112 static int avr32_pm_enter(suspend_state_t state)
113 {
114         u32             lpr_saved;
115         u32             evba_saved;
116         void            *sram;
117 
118         switch (state) {
119         case PM_SUSPEND_STANDBY:
120                 sram = avr32_pm_map_sram();
121 
122                 /* Switch to in-sram exception handlers */
123                 evba_saved = sysreg_read(EVBA);
124                 sysreg_write(EVBA, (unsigned long)sram);
125 
126                 /*
127                  * Save the LPR register so that we can re-enable
128                  * SDRAM Low Power mode on resume.
129                  */
130                 lpr_saved = sdramc_readl(LPR);
131                 pr_debug("%s: Entering standby...\n", __func__);
132                 avr32_pm_enter_standby(SDRAMC_BASE);
133                 sdramc_writel(LPR, lpr_saved);
134 
135                 /* Switch back to regular exception handlers */
136                 sysreg_write(EVBA, evba_saved);
137 
138                 avr32_pm_unmap_sram();
139                 break;
140 
141         case PM_SUSPEND_MEM:
142                 sram = avr32_pm_map_sram();
143 
144                 /* Switch to in-sram exception handlers */
145                 evba_saved = sysreg_read(EVBA);
146                 sysreg_write(EVBA, (unsigned long)sram);
147 
148                 /*
149                  * Save the LPR register so that we can re-enable
150                  * SDRAM Low Power mode on resume.
151                  */
152                 lpr_saved = sdramc_readl(LPR);
153                 pr_debug("%s: Entering suspend-to-ram...\n", __func__);
154                 avr32_pm_enter_str(SDRAMC_BASE);
155                 sdramc_writel(LPR, lpr_saved);
156 
157                 /* Switch back to regular exception handlers */
158                 sysreg_write(EVBA, evba_saved);
159 
160                 avr32_pm_unmap_sram();
161                 break;
162 
163         case PM_SUSPEND_ON:
164                 pr_debug("%s: Entering idle...\n", __func__);
165                 cpu_enter_idle();
166                 break;
167 
168         default:
169                 pr_debug("%s: Invalid suspend state %d\n", __func__, state);
170                 goto out;
171         }
172 
173         pr_debug("%s: wakeup\n", __func__);
174 
175 out:
176         return 0;
177 }
178 
179 static const struct platform_suspend_ops avr32_pm_ops = {
180         .valid  = avr32_pm_valid_state,
181         .enter  = avr32_pm_enter,
182 };
183 
184 static unsigned long __init avr32_pm_offset(void *symbol)
185 {
186         extern u8 pm_exception[];
187 
188         return (unsigned long)symbol - (unsigned long)pm_exception;
189 }
190 
191 static int __init avr32_pm_init(void)
192 {
193         extern u8 pm_exception[];
194         extern u8 pm_irq0[];
195         extern u8 pm_standby[];
196         extern u8 pm_suspend_to_ram[];
197         extern u8 pm_sram_end[];
198         void *dst;
199 
200         /*
201          * To keep things simple, we depend on not needing more than a
202          * single page.
203          */
204         pm_sram_size = avr32_pm_offset(pm_sram_end);
205         if (pm_sram_size > PAGE_SIZE)
206                 goto err;
207 
208         pm_sram_start = sram_alloc(pm_sram_size);
209         if (!pm_sram_start)
210                 goto err_alloc_sram;
211 
212         /* Grab a virtual area we can use later on. */
213         pm_sram_area = get_vm_area(pm_sram_size, VM_IOREMAP);
214         if (!pm_sram_area)
215                 goto err_vm_area;
216         pm_sram_area->phys_addr = pm_sram_start;
217 
218         local_irq_disable();
219         dst = avr32_pm_map_sram();
220         memcpy(dst, pm_exception, pm_sram_size);
221         flush_dcache_region(dst, pm_sram_size);
222         invalidate_icache_region(dst, pm_sram_size);
223         avr32_pm_unmap_sram();
224         local_irq_enable();
225 
226         avr32_pm_enter_standby = dst + avr32_pm_offset(pm_standby);
227         avr32_pm_enter_str = dst + avr32_pm_offset(pm_suspend_to_ram);
228         intc_set_suspend_handler(avr32_pm_offset(pm_irq0));
229 
230         suspend_set_ops(&avr32_pm_ops);
231 
232         printk("AVR32 AP Power Management enabled\n");
233 
234         return 0;
235 
236 err_vm_area:
237         sram_free(pm_sram_start, pm_sram_size);
238 err_alloc_sram:
239 err:
240         pr_err("AVR32 Power Management initialization failed\n");
241         return -ENOMEM;
242 }
243 arch_initcall(avr32_pm_init);
244 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp