Steven Miao | 93f8951 | 2012-05-16 18:26:10 +0800 | [diff] [blame^] | 1 | /* |
| 2 | * Blackfin bf609 power management |
| 3 | * |
| 4 | * Copyright 2011 Analog Devices Inc. |
| 5 | * |
| 6 | * Licensed under the GPL-2 |
| 7 | */ |
| 8 | |
| 9 | #include <linux/suspend.h> |
| 10 | #include <linux/io.h> |
| 11 | #include <linux/interrupt.h> |
| 12 | #include <linux/gpio.h> |
| 13 | #include <linux/irq.h> |
| 14 | |
| 15 | #include <linux/delay.h> |
| 16 | |
| 17 | #include <asm/dpmc.h> |
| 18 | #include <asm/pm.h> |
| 19 | #include <mach/pm.h> |
| 20 | #include <asm/blackfin.h> |
| 21 | |
| 22 | /***********************************************************/ |
| 23 | /* */ |
| 24 | /* Wakeup Actions for DPM_RESTORE */ |
| 25 | /* */ |
| 26 | /***********************************************************/ |
| 27 | #define BITP_ROM_WUA_CHKHDR 24 |
| 28 | #define BITP_ROM_WUA_DDRLOCK 7 |
| 29 | #define BITP_ROM_WUA_DDRDLLEN 6 |
| 30 | #define BITP_ROM_WUA_DDR 5 |
| 31 | #define BITP_ROM_WUA_CGU 4 |
| 32 | #define BITP_ROM_WUA_MEMBOOT 2 |
| 33 | #define BITP_ROM_WUA_EN 1 |
| 34 | |
| 35 | #define BITM_ROM_WUA_CHKHDR (0xFF000000) |
| 36 | #define ENUM_ROM_WUA_CHKHDR_AD 0xAD000000 |
| 37 | |
| 38 | #define BITM_ROM_WUA_DDRLOCK (0x00000080) |
| 39 | #define BITM_ROM_WUA_DDRDLLEN (0x00000040) |
| 40 | #define BITM_ROM_WUA_DDR (0x00000020) |
| 41 | #define BITM_ROM_WUA_CGU (0x00000010) |
| 42 | #define BITM_ROM_WUA_MEMBOOT (0x00000002) |
| 43 | #define BITM_ROM_WUA_EN (0x00000001) |
| 44 | |
| 45 | /***********************************************************/ |
| 46 | /* */ |
| 47 | /* Syscontrol */ |
| 48 | /* */ |
| 49 | /***********************************************************/ |
| 50 | #define BITP_ROM_SYSCTRL_CGU_LOCKINGEN 28 /* unlocks CGU_CTL register */ |
| 51 | #define BITP_ROM_SYSCTRL_WUA_OVERRIDE 24 |
| 52 | #define BITP_ROM_SYSCTRL_WUA_DDRDLLEN 20 /* Saves the DDR DLL and PADS registers to the DPM registers */ |
| 53 | #define BITP_ROM_SYSCTRL_WUA_DDR 19 /* Saves the DDR registers to the DPM registers */ |
| 54 | #define BITP_ROM_SYSCTRL_WUA_CGU 18 /* Saves the CGU registers into DPM registers */ |
| 55 | #define BITP_ROM_SYSCTRL_WUA_DPMWRITE 17 /* Saves the Syscontrol structure structure contents into DPM registers */ |
| 56 | #define BITP_ROM_SYSCTRL_WUA_EN 16 /* reads current PLL and DDR configuration into structure */ |
| 57 | #define BITP_ROM_SYSCTRL_DDR_WRITE 13 /* writes the DDR registers from Syscontrol structure for wakeup initialization of DDR */ |
| 58 | #define BITP_ROM_SYSCTRL_DDR_READ 12 /* Read the DDR registers into the Syscontrol structure for storing prior to hibernate */ |
| 59 | #define BITP_ROM_SYSCTRL_CGU_AUTODIS 11 /* Disables auto handling of UPDT and ALGN fields */ |
| 60 | #define BITP_ROM_SYSCTRL_CGU_CLKOUTSEL 7 /* access CGU_CLKOUTSEL register */ |
| 61 | #define BITP_ROM_SYSCTRL_CGU_DIV 6 /* access CGU_DIV register */ |
| 62 | #define BITP_ROM_SYSCTRL_CGU_STAT 5 /* access CGU_STAT register */ |
| 63 | #define BITP_ROM_SYSCTRL_CGU_CTL 4 /* access CGU_CTL register */ |
| 64 | #define BITP_ROM_SYSCTRL_CGU_RTNSTAT 2 /* Update structure STAT field upon error */ |
| 65 | #define BITP_ROM_SYSCTRL_WRITE 1 /* write registers */ |
| 66 | #define BITP_ROM_SYSCTRL_READ 0 /* read registers */ |
| 67 | |
| 68 | #define BITM_ROM_SYSCTRL_CGU_READ (0x00000001) /* Read CGU registers */ |
| 69 | #define BITM_ROM_SYSCTRL_CGU_WRITE (0x00000002) /* Write registers */ |
| 70 | #define BITM_ROM_SYSCTRL_CGU_RTNSTAT (0x00000004) /* Update structure STAT field upon error or after a write operation */ |
| 71 | #define BITM_ROM_SYSCTRL_CGU_CTL (0x00000010) /* Access CGU_CTL register */ |
| 72 | #define BITM_ROM_SYSCTRL_CGU_STAT (0x00000020) /* Access CGU_STAT register */ |
| 73 | #define BITM_ROM_SYSCTRL_CGU_DIV (0x00000040) /* Access CGU_DIV register */ |
| 74 | #define BITM_ROM_SYSCTRL_CGU_CLKOUTSEL (0x00000080) /* Access CGU_CLKOUTSEL register */ |
| 75 | #define BITM_ROM_SYSCTRL_CGU_AUTODIS (0x00000800) /* Disables auto handling of UPDT and ALGN fields */ |
| 76 | #define BITM_ROM_SYSCTRL_DDR_READ (0x00001000) /* Reads the contents of the DDR registers and stores them into the structure */ |
| 77 | #define BITM_ROM_SYSCTRL_DDR_WRITE (0x00002000) /* Writes the DDR registers from the structure, only really intented for wakeup functionality and not for full DDR configuration */ |
| 78 | #define BITM_ROM_SYSCTRL_WUA_EN (0x00010000) /* Wakeup entry or exit opertation enable */ |
| 79 | #define BITM_ROM_SYSCTRL_WUA_DPMWRITE (0x00020000) /* When set indicates a restore of the PLL and DDR is to be performed otherwise a save is required */ |
| 80 | #define BITM_ROM_SYSCTRL_WUA_CGU (0x00040000) /* Only applicable for a PLL and DDR save operation to the DPM, saves the current settings if cleared or the contents of the structure if set */ |
| 81 | #define BITM_ROM_SYSCTRL_WUA_DDR (0x00080000) /* Only applicable for a PLL and DDR save operation to the DPM, saves the current settings if cleared or the contents of the structure if set */ |
| 82 | #define BITM_ROM_SYSCTRL_WUA_DDRDLLEN (0x00100000) /* Enables saving/restoring of the DDR DLLCTL register */ |
| 83 | #define BITM_ROM_SYSCTRL_WUA_OVERRIDE (0x01000000) |
| 84 | #define BITM_ROM_SYSCTRL_CGU_LOCKINGEN (0x10000000) /* Unlocks the CGU_CTL register */ |
| 85 | |
| 86 | |
| 87 | /* Structures for the syscontrol() function */ |
| 88 | struct STRUCT_ROM_SYSCTRL { |
| 89 | uint32_t ulCGU_CTL; |
| 90 | uint32_t ulCGU_STAT; |
| 91 | uint32_t ulCGU_DIV; |
| 92 | uint32_t ulCGU_CLKOUTSEL; |
| 93 | uint32_t ulWUA_Flags; |
| 94 | uint32_t ulWUA_BootAddr; |
| 95 | uint32_t ulWUA_User; |
| 96 | uint32_t ulDDR_CTL; |
| 97 | uint32_t ulDDR_CFG; |
| 98 | uint32_t ulDDR_TR0; |
| 99 | uint32_t ulDDR_TR1; |
| 100 | uint32_t ulDDR_TR2; |
| 101 | uint32_t ulDDR_MR; |
| 102 | uint32_t ulDDR_EMR1; |
| 103 | uint32_t ulDDR_EMR2; |
| 104 | uint32_t ulDDR_PADCTL; |
| 105 | uint32_t ulDDR_DLLCTL; |
| 106 | uint32_t ulReserved; |
| 107 | }; |
| 108 | |
| 109 | struct bfin_pm_data { |
| 110 | uint32_t magic; |
| 111 | uint32_t resume_addr; |
| 112 | uint32_t sp; |
| 113 | }; |
| 114 | |
| 115 | struct bfin_pm_data bf609_pm_data; |
| 116 | |
| 117 | struct STRUCT_ROM_SYSCTRL configvalues; |
| 118 | uint32_t dactionflags; |
| 119 | |
| 120 | #define FUNC_ROM_SYSCONTROL 0xC8000080 |
| 121 | __attribute__((l1_data)) |
| 122 | static uint32_t (* const bfrom_SysControl)(uint32_t action_flags, struct STRUCT_ROM_SYSCTRL *settings, void *reserved) = (void *)FUNC_ROM_SYSCONTROL; |
| 123 | |
| 124 | __attribute__((l1_text)) |
| 125 | void bfin_cpu_suspend(void) |
| 126 | { |
| 127 | __asm__ __volatile__( \ |
| 128 | ".align 8;" \ |
| 129 | "idle;" \ |
| 130 | : : \ |
| 131 | ); |
| 132 | } |
| 133 | |
| 134 | __attribute__((l1_text)) |
| 135 | void bfin_deepsleep(unsigned long mask) |
| 136 | { |
| 137 | uint32_t dpm0_ctl; |
| 138 | |
| 139 | bfin_write32(DPM0_WAKE_EN, 0x10); |
| 140 | bfin_write32(DPM0_WAKE_POL, 0x10); |
| 141 | dpm0_ctl = bfin_read32(DPM0_CTL); |
| 142 | dpm0_ctl = 0x00000008; |
| 143 | bfin_write32(DPM0_CTL, dpm0_ctl); |
| 144 | SSYNC(); |
| 145 | __asm__ __volatile__( \ |
| 146 | ".align 8;" \ |
| 147 | "idle;" \ |
| 148 | : : \ |
| 149 | ); |
| 150 | } |
| 151 | |
| 152 | __attribute__((l1_text)) |
| 153 | void bf609_ddr_sr(void) |
| 154 | { |
| 155 | uint32_t reg; |
| 156 | |
| 157 | reg = bfin_read_DDR0_CTL(); |
| 158 | reg |= 0x8; |
| 159 | bfin_write_DDR0_CTL(reg); |
| 160 | |
| 161 | while (!(bfin_read_DDR0_STAT() & 0x8)) |
| 162 | continue; |
| 163 | } |
| 164 | |
| 165 | __attribute__((l1_text)) |
| 166 | void bf609_ddr_sr_exit(void) |
| 167 | { |
| 168 | uint32_t reg; |
| 169 | while (!(bfin_read_DDR0_STAT() & 0x1)) |
| 170 | continue; |
| 171 | |
| 172 | reg = bfin_read_DDR0_CTL(); |
| 173 | reg &= ~0x8; |
| 174 | bfin_write_DDR0_CTL(reg); |
| 175 | |
| 176 | while ((bfin_read_DDR0_STAT() & 0x8)) |
| 177 | continue; |
| 178 | } |
| 179 | |
| 180 | __attribute__((l1_text)) |
| 181 | void bfin_hibernate_syscontrol(void) |
| 182 | { |
| 183 | configvalues.ulWUA_Flags = (0xAD000000 | BITM_ROM_WUA_EN |
| 184 | | BITM_ROM_WUA_CGU | BITM_ROM_WUA_DDR | BITM_ROM_WUA_DDRDLLEN); |
| 185 | |
| 186 | dactionflags = (BITM_ROM_SYSCTRL_WUA_EN |
| 187 | | BITM_ROM_SYSCTRL_WUA_DPMWRITE | BITM_ROM_SYSCTRL_WUA_CGU |
| 188 | | BITM_ROM_SYSCTRL_WUA_DDR | BITM_ROM_SYSCTRL_WUA_DDRDLLEN); |
| 189 | |
| 190 | bfrom_SysControl(dactionflags, &configvalues, NULL); |
| 191 | |
| 192 | bfin_write32(DPM0_RESTORE5, bfin_read32(DPM0_RESTORE5) | 4); |
| 193 | } |
| 194 | |
| 195 | #ifndef CONFIG_BF60x |
| 196 | # define SIC_SYSIRQ(irq) (irq - (IRQ_CORETMR + 1)) |
| 197 | #else |
| 198 | # define SIC_SYSIRQ(irq) ((irq) - IVG15) |
| 199 | #endif |
| 200 | void bfin_hibernate(unsigned long mask) |
| 201 | { |
| 202 | bfin_write32(DPM0_WAKE_EN, 0x10); |
| 203 | bfin_write32(DPM0_WAKE_POL, 0x10); |
| 204 | bfin_write32(DPM0_PGCNTR, 0x0000FFFF); |
| 205 | bfin_write32(DPM0_HIB_DIS, 0xFFFF); |
| 206 | |
| 207 | printk(KERN_DEBUG "hibernate: restore %x pgcnt %x\n", bfin_read32(DPM0_RESTORE0), bfin_read32(DPM0_PGCNTR)); |
| 208 | |
| 209 | bf609_hibernate(); |
| 210 | } |
| 211 | |
| 212 | void bf609_cpu_pm_enter(suspend_state_t state) |
| 213 | { |
| 214 | int error; |
| 215 | error = irq_set_irq_wake(255, 1); |
| 216 | if(error < 0) |
| 217 | printk(KERN_DEBUG "Unable to get irq wake\n"); |
| 218 | error = irq_set_irq_wake(231, 1); |
| 219 | if (error < 0) |
| 220 | printk(KERN_DEBUG "Unable to get irq wake\n"); |
| 221 | |
| 222 | if (state == PM_SUSPEND_STANDBY) |
| 223 | bfin_deepsleep(0xffff); |
| 224 | else { |
| 225 | bfin_hibernate(0xffff); |
| 226 | } |
| 227 | } |
| 228 | |
| 229 | int bf609_cpu_pm_prepare(void) |
| 230 | { |
| 231 | return 0; |
| 232 | } |
| 233 | |
| 234 | void bf609_cpu_pm_finish(void) |
| 235 | { |
| 236 | |
| 237 | } |
| 238 | |
| 239 | static struct bfin_cpu_pm_fns bf609_cpu_pm = { |
| 240 | .enter = bf609_cpu_pm_enter, |
| 241 | .prepare = bf609_cpu_pm_prepare, |
| 242 | .finish = bf609_cpu_pm_finish, |
| 243 | }; |
| 244 | |
| 245 | static irqreturn_t test_isr(int irq, void *dev_id) |
| 246 | { |
| 247 | printk(KERN_DEBUG "gpio irq %d\n", irq); |
| 248 | return IRQ_HANDLED; |
| 249 | } |
| 250 | |
| 251 | static irqreturn_t dpm0_isr(int irq, void *dev_id) |
| 252 | { |
| 253 | uint32_t wake_stat; |
| 254 | |
| 255 | wake_stat = bfin_read32(DPM0_WAKE_STAT); |
| 256 | printk(KERN_DEBUG "enter %s wake stat %08x\n", __func__, wake_stat); |
| 257 | |
| 258 | bfin_write32(DPM0_WAKE_STAT, wake_stat); |
| 259 | return IRQ_HANDLED; |
| 260 | } |
| 261 | |
| 262 | static int __init bf609_init_pm(void) |
| 263 | { |
| 264 | int irq; |
| 265 | int error; |
| 266 | error = gpio_request(GPIO_PG4, "gpiopg4"); |
| 267 | if (error < 0) { |
| 268 | printk(KERN_DEBUG "failed to request GPIO %d, error %d\n", |
| 269 | GPIO_PG4, error); |
| 270 | } |
| 271 | |
| 272 | irq = gpio_to_irq(GPIO_PG4); |
| 273 | if (irq < 0) { |
| 274 | error = irq; |
| 275 | printk(KERN_DEBUG "Unable to get irq number for GPIO %d, error %d\n", |
| 276 | GPIO_PG4, error); |
| 277 | } |
| 278 | |
| 279 | printk(KERN_DEBUG "%s gpio %d irq %d\n", __func__, GPIO_PG4, irq); |
| 280 | |
| 281 | error = request_irq(irq, test_isr, IRQF_TRIGGER_FALLING | IRQF_NO_SUSPEND, "gpiopg4", NULL); |
| 282 | if(error < 0) |
| 283 | printk(KERN_DEBUG "Unable to get irq\n"); |
| 284 | |
| 285 | #if 1 |
| 286 | irq = gpio_to_irq(GPIO_PE12); |
| 287 | if (irq < 0) { |
| 288 | error = irq; |
| 289 | printk(KERN_DEBUG "Unable to get irq number for GPIO %d, error %d\n", |
| 290 | GPIO_PE12, error); |
| 291 | } |
| 292 | |
| 293 | error = request_irq(irq, test_isr, IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND, "gpiope12", NULL); |
| 294 | if(error < 0) |
| 295 | printk(KERN_DEBUG "Unable to get irq\n"); |
| 296 | #endif |
| 297 | |
| 298 | error = request_irq(IRQ_CGU_EVT, dpm0_isr, IRQF_NO_SUSPEND, "cgu0 event", NULL); |
| 299 | if(error < 0) |
| 300 | printk(KERN_DEBUG "Unable to get irq\n"); |
| 301 | |
| 302 | error = request_irq(IRQ_DPM, dpm0_isr, IRQF_NO_SUSPEND, "dpm0 event", NULL); |
| 303 | if (error < 0) |
| 304 | printk(KERN_DEBUG "Unable to get irq\n"); |
| 305 | |
| 306 | bfin_cpu_pm = &bf609_cpu_pm; |
| 307 | return 0; |
| 308 | } |
| 309 | |
| 310 | late_initcall(bf609_init_pm); |