Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
lite5200_pm.c
Go to the documentation of this file.
1 #include <linux/init.h>
2 #include <linux/suspend.h>
3 #include <asm/io.h>
4 #include <asm/time.h>
5 #include <asm/mpc52xx.h>
6 #include <asm/switch_to.h>
7 
8 /* defined in lite5200_sleep.S and only used here */
9 extern void lite5200_low_power(void __iomem *sram, void __iomem *mbar);
10 
11 static struct mpc52xx_cdm __iomem *cdm;
12 static struct mpc52xx_intr __iomem *pic;
13 static struct mpc52xx_sdma __iomem *bes;
14 static struct mpc52xx_xlb __iomem *xlb;
15 static struct mpc52xx_gpio __iomem *gps;
16 static struct mpc52xx_gpio_wkup __iomem *gpw;
17 static void __iomem *pci;
18 static void __iomem *sram;
19 static const int sram_size = 0x4000; /* 16 kBytes */
20 static void __iomem *mbar;
21 
22 static suspend_state_t lite5200_pm_target_state;
23 
24 static int lite5200_pm_valid(suspend_state_t state)
25 {
26  switch (state) {
27  case PM_SUSPEND_STANDBY:
28  case PM_SUSPEND_MEM:
29  return 1;
30  default:
31  return 0;
32  }
33 }
34 
35 static int lite5200_pm_begin(suspend_state_t state)
36 {
37  if (lite5200_pm_valid(state)) {
38  lite5200_pm_target_state = state;
39  return 0;
40  }
41  return -EINVAL;
42 }
43 
44 static int lite5200_pm_prepare(void)
45 {
46  struct device_node *np;
47  const struct of_device_id immr_ids[] = {
48  { .compatible = "fsl,mpc5200-immr", },
49  { .compatible = "fsl,mpc5200b-immr", },
50  { .type = "soc", .compatible = "mpc5200", }, /* lite5200 */
51  { .type = "builtin", .compatible = "mpc5200", }, /* efika */
52  {}
53  };
54  u64 regaddr64 = 0;
55  const u32 *regaddr_p;
56 
57  /* deep sleep? let mpc52xx code handle that */
58  if (lite5200_pm_target_state == PM_SUSPEND_STANDBY)
59  return mpc52xx_pm_prepare();
60 
61  if (lite5200_pm_target_state != PM_SUSPEND_MEM)
62  return -EINVAL;
63 
64  /* map registers */
65  np = of_find_matching_node(NULL, immr_ids);
66  regaddr_p = of_get_address(np, 0, NULL, NULL);
67  if (regaddr_p)
68  regaddr64 = of_translate_address(np, regaddr_p);
69  of_node_put(np);
70 
71  mbar = ioremap((u32) regaddr64, 0xC000);
72  if (!mbar) {
73  printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__);
74  return -ENOSYS;
75  }
76 
77  cdm = mbar + 0x200;
78  pic = mbar + 0x500;
79  gps = mbar + 0xb00;
80  gpw = mbar + 0xc00;
81  pci = mbar + 0xd00;
82  bes = mbar + 0x1200;
83  xlb = mbar + 0x1f00;
84  sram = mbar + 0x8000;
85 
86  return 0;
87 }
88 
89 /* save and restore registers not bound to any real devices */
90 static struct mpc52xx_cdm scdm;
91 static struct mpc52xx_intr spic;
92 static struct mpc52xx_sdma sbes;
93 static struct mpc52xx_xlb sxlb;
94 static struct mpc52xx_gpio sgps;
95 static struct mpc52xx_gpio_wkup sgpw;
96 static char spci[0x200];
97 
98 static void lite5200_save_regs(void)
99 {
100  _memcpy_fromio(&spic, pic, sizeof(*pic));
101  _memcpy_fromio(&sbes, bes, sizeof(*bes));
102  _memcpy_fromio(&scdm, cdm, sizeof(*cdm));
103  _memcpy_fromio(&sxlb, xlb, sizeof(*xlb));
104  _memcpy_fromio(&sgps, gps, sizeof(*gps));
105  _memcpy_fromio(&sgpw, gpw, sizeof(*gpw));
106  _memcpy_fromio(spci, pci, 0x200);
107 
108  _memcpy_fromio(saved_sram, sram, sram_size);
109 }
110 
111 static void lite5200_restore_regs(void)
112 {
113  int i;
114  _memcpy_toio(sram, saved_sram, sram_size);
115 
116  /* PCI Configuration */
117  _memcpy_toio(pci, spci, 0x200);
118 
119  /*
120  * GPIOs. Interrupt Master Enable has higher address then other
121  * registers, so just memcpy is ok.
122  */
123  _memcpy_toio(gpw, &sgpw, sizeof(*gpw));
124  _memcpy_toio(gps, &sgps, sizeof(*gps));
125 
126 
127  /* XLB Arbitrer */
128  out_be32(&xlb->snoop_window, sxlb.snoop_window);
129  out_be32(&xlb->master_priority, sxlb.master_priority);
130  out_be32(&xlb->master_pri_enable, sxlb.master_pri_enable);
131 
132  /* enable */
133  out_be32(&xlb->int_enable, sxlb.int_enable);
134  out_be32(&xlb->config, sxlb.config);
135 
136 
137  /* CDM - Clock Distribution Module */
138  out_8(&cdm->ipb_clk_sel, scdm.ipb_clk_sel);
139  out_8(&cdm->pci_clk_sel, scdm.pci_clk_sel);
140 
141  out_8(&cdm->ext_48mhz_en, scdm.ext_48mhz_en);
142  out_8(&cdm->fd_enable, scdm.fd_enable);
143  out_be16(&cdm->fd_counters, scdm.fd_counters);
144 
145  out_be32(&cdm->clk_enables, scdm.clk_enables);
146 
147  out_8(&cdm->osc_disable, scdm.osc_disable);
148 
149  out_be16(&cdm->mclken_div_psc1, scdm.mclken_div_psc1);
150  out_be16(&cdm->mclken_div_psc2, scdm.mclken_div_psc2);
151  out_be16(&cdm->mclken_div_psc3, scdm.mclken_div_psc3);
152  out_be16(&cdm->mclken_div_psc6, scdm.mclken_div_psc6);
153 
154 
155  /* BESTCOMM */
156  out_be32(&bes->taskBar, sbes.taskBar);
157  out_be32(&bes->currentPointer, sbes.currentPointer);
158  out_be32(&bes->endPointer, sbes.endPointer);
159  out_be32(&bes->variablePointer, sbes.variablePointer);
160 
161  out_8(&bes->IntVect1, sbes.IntVect1);
162  out_8(&bes->IntVect2, sbes.IntVect2);
163  out_be16(&bes->PtdCntrl, sbes.PtdCntrl);
164 
165  for (i=0; i<32; i++)
166  out_8(&bes->ipr[i], sbes.ipr[i]);
167 
168  out_be32(&bes->cReqSelect, sbes.cReqSelect);
169  out_be32(&bes->task_size0, sbes.task_size0);
170  out_be32(&bes->task_size1, sbes.task_size1);
171  out_be32(&bes->MDEDebug, sbes.MDEDebug);
172  out_be32(&bes->ADSDebug, sbes.ADSDebug);
173  out_be32(&bes->Value1, sbes.Value1);
174  out_be32(&bes->Value2, sbes.Value2);
175  out_be32(&bes->Control, sbes.Control);
176  out_be32(&bes->Status, sbes.Status);
177  out_be32(&bes->PTDDebug, sbes.PTDDebug);
178 
179  /* restore tasks */
180  for (i=0; i<16; i++)
181  out_be16(&bes->tcr[i], sbes.tcr[i]);
182 
183  /* enable interrupts */
184  out_be32(&bes->IntPend, sbes.IntPend);
185  out_be32(&bes->IntMask, sbes.IntMask);
186 
187 
188  /* PIC */
189  out_be32(&pic->per_pri1, spic.per_pri1);
190  out_be32(&pic->per_pri2, spic.per_pri2);
191  out_be32(&pic->per_pri3, spic.per_pri3);
192 
193  out_be32(&pic->main_pri1, spic.main_pri1);
194  out_be32(&pic->main_pri2, spic.main_pri2);
195 
196  out_be32(&pic->enc_status, spic.enc_status);
197 
198  /* unmask and enable interrupts */
199  out_be32(&pic->per_mask, spic.per_mask);
200  out_be32(&pic->main_mask, spic.main_mask);
201  out_be32(&pic->ctrl, spic.ctrl);
202 }
203 
204 static int lite5200_pm_enter(suspend_state_t state)
205 {
206  /* deep sleep? let mpc52xx code handle that */
207  if (state == PM_SUSPEND_STANDBY) {
208  return mpc52xx_pm_enter(state);
209  }
210 
211  lite5200_save_regs();
212 
213  /* effectively save FP regs */
215 
216  lite5200_low_power(sram, mbar);
217 
218  lite5200_restore_regs();
219 
220  iounmap(mbar);
221  return 0;
222 }
223 
224 static void lite5200_pm_finish(void)
225 {
226  /* deep sleep? let mpc52xx code handle that */
227  if (lite5200_pm_target_state == PM_SUSPEND_STANDBY)
229 }
230 
231 static void lite5200_pm_end(void)
232 {
233  lite5200_pm_target_state = PM_SUSPEND_ON;
234 }
235 
236 static const struct platform_suspend_ops lite5200_pm_ops = {
237  .valid = lite5200_pm_valid,
238  .begin = lite5200_pm_begin,
239  .prepare = lite5200_pm_prepare,
240  .enter = lite5200_pm_enter,
241  .finish = lite5200_pm_finish,
242  .end = lite5200_pm_end,
243 };
244 
246 {
247  suspend_set_ops(&lite5200_pm_ops);
248  return 0;
249 }