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

TOMOYO Linux Cross Reference
Linux/arch/arm/mach-imx/mmdc.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ 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.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /arch/arm/mach-imx/mmdc.c (Architecture i386) and /arch/sparc/mach-imx/mmdc.c (Architecture sparc)


  1 // SPDX-License-Identifier: GPL-2.0-or-later        1 
  2 /*                                                
  3  * Copyright 2017 NXP                             
  4  * Copyright 2011,2016 Freescale Semiconductor    
  5  * Copyright 2011 Linaro Ltd.                     
  6  */                                               
  7                                                   
  8 #include <linux/clk.h>                            
  9 #include <linux/hrtimer.h>                        
 10 #include <linux/init.h>                           
 11 #include <linux/interrupt.h>                      
 12 #include <linux/io.h>                             
 13 #include <linux/module.h>                         
 14 #include <linux/of.h>                             
 15 #include <linux/of_address.h>                     
 16 #include <linux/platform_device.h>                
 17 #include <linux/property.h>                       
 18 #include <linux/perf_event.h>                     
 19 #include <linux/slab.h>                           
 20                                                   
 21 #include "common.h"                               
 22                                                   
 23 #define MMDC_MAPSR              0x404             
 24 #define BP_MMDC_MAPSR_PSD       0                 
 25 #define BP_MMDC_MAPSR_PSS       4                 
 26                                                   
 27 #define MMDC_MDMISC             0x18              
 28 #define BM_MMDC_MDMISC_DDR_TYPE 0x18              
 29 #define BP_MMDC_MDMISC_DDR_TYPE 0x3               
 30                                                   
 31 #define TOTAL_CYCLES            0x0               
 32 #define BUSY_CYCLES             0x1               
 33 #define READ_ACCESSES           0x2               
 34 #define WRITE_ACCESSES          0x3               
 35 #define READ_BYTES              0x4               
 36 #define WRITE_BYTES             0x5               
 37                                                   
 38 /* Enables, resets, freezes, overflow profilin    
 39 #define DBG_DIS                 0x0               
 40 #define DBG_EN                  0x1               
 41 #define DBG_RST                 0x2               
 42 #define PRF_FRZ                 0x4               
 43 #define CYC_OVF                 0x8               
 44 #define PROFILE_SEL             0x10              
 45                                                   
 46 #define MMDC_MADPCR0    0x410                     
 47 #define MMDC_MADPCR1    0x414                     
 48 #define MMDC_MADPSR0    0x418                     
 49 #define MMDC_MADPSR1    0x41C                     
 50 #define MMDC_MADPSR2    0x420                     
 51 #define MMDC_MADPSR3    0x424                     
 52 #define MMDC_MADPSR4    0x428                     
 53 #define MMDC_MADPSR5    0x42C                     
 54                                                   
 55 #define MMDC_NUM_COUNTERS       6                 
 56                                                   
 57 #define MMDC_FLAG_PROFILE_SEL   0x1               
 58 #define MMDC_PRF_AXI_ID_CLEAR   0x0               
 59                                                   
 60 #define to_mmdc_pmu(p) container_of(p, struct     
 61                                                   
 62 static int ddr_type;                              
 63                                                   
 64 struct fsl_mmdc_devtype_data {                    
 65         unsigned int flags;                       
 66 };                                                
 67                                                   
 68 static const struct fsl_mmdc_devtype_data imx6    
 69 };                                                
 70                                                   
 71 static const struct fsl_mmdc_devtype_data imx6    
 72         .flags = MMDC_FLAG_PROFILE_SEL,           
 73 };                                                
 74                                                   
 75 static const struct of_device_id imx_mmdc_dt_i    
 76         { .compatible = "fsl,imx6q-mmdc", .dat    
 77         { .compatible = "fsl,imx6qp-mmdc", .da    
 78         { /* sentinel */ }                        
 79 };                                                
 80                                                   
 81 #ifdef CONFIG_PERF_EVENTS                         
 82                                                   
 83 static enum cpuhp_state cpuhp_mmdc_state;         
 84 static DEFINE_IDA(mmdc_ida);                      
 85                                                   
 86 PMU_EVENT_ATTR_STRING(total-cycles, mmdc_pmu_t    
 87 PMU_EVENT_ATTR_STRING(busy-cycles, mmdc_pmu_bu    
 88 PMU_EVENT_ATTR_STRING(read-accesses, mmdc_pmu_    
 89 PMU_EVENT_ATTR_STRING(write-accesses, mmdc_pmu    
 90 PMU_EVENT_ATTR_STRING(read-bytes, mmdc_pmu_rea    
 91 PMU_EVENT_ATTR_STRING(read-bytes.unit, mmdc_pm    
 92 PMU_EVENT_ATTR_STRING(read-bytes.scale, mmdc_p    
 93 PMU_EVENT_ATTR_STRING(write-bytes, mmdc_pmu_wr    
 94 PMU_EVENT_ATTR_STRING(write-bytes.unit, mmdc_p    
 95 PMU_EVENT_ATTR_STRING(write-bytes.scale, mmdc_    
 96                                                   
 97 struct mmdc_pmu {                                 
 98         struct pmu pmu;                           
 99         void __iomem *mmdc_base;                  
100         cpumask_t cpu;                            
101         struct hrtimer hrtimer;                   
102         unsigned int active_events;               
103         int id;                                   
104         struct device *dev;                       
105         struct perf_event *mmdc_events[MMDC_NU    
106         struct hlist_node node;                   
107         const struct fsl_mmdc_devtype_data *de    
108         struct clk *mmdc_ipg_clk;                 
109 };                                                
110                                                   
111 /*                                                
112  * Polling period is set to one second, overfl    
113  * increasing counter) takes ten seconds so on    
114  */                                               
115 static unsigned int mmdc_pmu_poll_period_us =     
116                                                   
117 module_param_named(pmu_pmu_poll_period_us, mmd    
118                 S_IRUGO | S_IWUSR);               
119                                                   
120 static ktime_t mmdc_pmu_timer_period(void)        
121 {                                                 
122         return ns_to_ktime((u64)mmdc_pmu_poll_    
123 }                                                 
124                                                   
125 static ssize_t mmdc_pmu_cpumask_show(struct de    
126                 struct device_attribute *attr,    
127 {                                                 
128         struct mmdc_pmu *pmu_mmdc = dev_get_dr    
129                                                   
130         return cpumap_print_to_pagebuf(true, b    
131 }                                                 
132                                                   
133 static struct device_attribute mmdc_pmu_cpumas    
134         __ATTR(cpumask, S_IRUGO, mmdc_pmu_cpum    
135                                                   
136 static struct attribute *mmdc_pmu_cpumask_attr    
137         &mmdc_pmu_cpumask_attr.attr,              
138         NULL,                                     
139 };                                                
140                                                   
141 static struct attribute_group mmdc_pmu_cpumask    
142         .attrs = mmdc_pmu_cpumask_attrs,          
143 };                                                
144                                                   
145 static struct attribute *mmdc_pmu_events_attrs    
146         &mmdc_pmu_total_cycles.attr.attr,         
147         &mmdc_pmu_busy_cycles.attr.attr,          
148         &mmdc_pmu_read_accesses.attr.attr,        
149         &mmdc_pmu_write_accesses.attr.attr,       
150         &mmdc_pmu_read_bytes.attr.attr,           
151         &mmdc_pmu_read_bytes_unit.attr.attr,      
152         &mmdc_pmu_read_bytes_scale.attr.attr,     
153         &mmdc_pmu_write_bytes.attr.attr,          
154         &mmdc_pmu_write_bytes_unit.attr.attr,     
155         &mmdc_pmu_write_bytes_scale.attr.attr,    
156         NULL,                                     
157 };                                                
158                                                   
159 static struct attribute_group mmdc_pmu_events_    
160         .name = "events",                         
161         .attrs = mmdc_pmu_events_attrs,           
162 };                                                
163                                                   
164 PMU_FORMAT_ATTR(event, "config:0-63");            
165 PMU_FORMAT_ATTR(axi_id, "config1:0-63");          
166                                                   
167 static struct attribute *mmdc_pmu_format_attrs    
168         &format_attr_event.attr,                  
169         &format_attr_axi_id.attr,                 
170         NULL,                                     
171 };                                                
172                                                   
173 static struct attribute_group mmdc_pmu_format_    
174         .name = "format",                         
175         .attrs = mmdc_pmu_format_attrs,           
176 };                                                
177                                                   
178 static const struct attribute_group *attr_grou    
179         &mmdc_pmu_events_attr_group,              
180         &mmdc_pmu_format_attr_group,              
181         &mmdc_pmu_cpumask_attr_group,             
182         NULL,                                     
183 };                                                
184                                                   
185 static u32 mmdc_pmu_read_counter(struct mmdc_p    
186 {                                                 
187         void __iomem *mmdc_base, *reg;            
188                                                   
189         mmdc_base = pmu_mmdc->mmdc_base;          
190                                                   
191         switch (cfg) {                            
192         case TOTAL_CYCLES:                        
193                 reg = mmdc_base + MMDC_MADPSR0    
194                 break;                            
195         case BUSY_CYCLES:                         
196                 reg = mmdc_base + MMDC_MADPSR1    
197                 break;                            
198         case READ_ACCESSES:                       
199                 reg = mmdc_base + MMDC_MADPSR2    
200                 break;                            
201         case WRITE_ACCESSES:                      
202                 reg = mmdc_base + MMDC_MADPSR3    
203                 break;                            
204         case READ_BYTES:                          
205                 reg = mmdc_base + MMDC_MADPSR4    
206                 break;                            
207         case WRITE_BYTES:                         
208                 reg = mmdc_base + MMDC_MADPSR5    
209                 break;                            
210         default:                                  
211                 return WARN_ONCE(1,               
212                         "invalid configuration    
213         }                                         
214         return readl(reg);                        
215 }                                                 
216                                                   
217 static int mmdc_pmu_offline_cpu(unsigned int c    
218 {                                                 
219         struct mmdc_pmu *pmu_mmdc = hlist_entr    
220         int target;                               
221                                                   
222         if (!cpumask_test_and_clear_cpu(cpu, &    
223                 return 0;                         
224                                                   
225         target = cpumask_any_but(cpu_online_ma    
226         if (target >= nr_cpu_ids)                 
227                 return 0;                         
228                                                   
229         perf_pmu_migrate_context(&pmu_mmdc->pm    
230         cpumask_set_cpu(target, &pmu_mmdc->cpu    
231                                                   
232         return 0;                                 
233 }                                                 
234                                                   
235 static bool mmdc_pmu_group_event_is_valid(stru    
236                                           stru    
237                                           unsi    
238 {                                                 
239         int cfg = event->attr.config;             
240                                                   
241         if (is_software_event(event))             
242                 return true;                      
243                                                   
244         if (event->pmu != pmu)                    
245                 return false;                     
246                                                   
247         return !test_and_set_bit(cfg, used_cou    
248 }                                                 
249                                                   
250 /*                                                
251  * Each event has a single fixed-purpose count    
252  * single active event for each at any point i    
253  * for duplicates, and rely on mmdc_pmu_event_    
254  * event numbers are valid.                       
255  */                                               
256 static bool mmdc_pmu_group_is_valid(struct per    
257 {                                                 
258         struct pmu *pmu = event->pmu;             
259         struct perf_event *leader = event->gro    
260         struct perf_event *sibling;               
261         unsigned long counter_mask = 0;           
262                                                   
263         set_bit(leader->attr.config, &counter_    
264                                                   
265         if (event != leader) {                    
266                 if (!mmdc_pmu_group_event_is_v    
267                         return false;             
268         }                                         
269                                                   
270         for_each_sibling_event(sibling, leader    
271                 if (!mmdc_pmu_group_event_is_v    
272                         return false;             
273         }                                         
274                                                   
275         return true;                              
276 }                                                 
277                                                   
278 static int mmdc_pmu_event_init(struct perf_eve    
279 {                                                 
280         struct mmdc_pmu *pmu_mmdc = to_mmdc_pm    
281         int cfg = event->attr.config;             
282                                                   
283         if (event->attr.type != event->pmu->ty    
284                 return -ENOENT;                   
285                                                   
286         if (is_sampling_event(event) || event-    
287                 return -EOPNOTSUPP;               
288                                                   
289         if (event->cpu < 0) {                     
290                 dev_warn(pmu_mmdc->dev, "Can't    
291                 return -EOPNOTSUPP;               
292         }                                         
293                                                   
294         if (event->attr.sample_period)            
295                 return -EINVAL;                   
296                                                   
297         if (cfg < 0 || cfg >= MMDC_NUM_COUNTER    
298                 return -EINVAL;                   
299                                                   
300         if (!mmdc_pmu_group_is_valid(event))      
301                 return -EINVAL;                   
302                                                   
303         event->cpu = cpumask_first(&pmu_mmdc->    
304         return 0;                                 
305 }                                                 
306                                                   
307 static void mmdc_pmu_event_update(struct perf_    
308 {                                                 
309         struct mmdc_pmu *pmu_mmdc = to_mmdc_pm    
310         struct hw_perf_event *hwc = &event->hw    
311         u64 delta, prev_raw_count, new_raw_cou    
312                                                   
313         do {                                      
314                 prev_raw_count = local64_read(    
315                 new_raw_count = mmdc_pmu_read_    
316                                                   
317         } while (local64_cmpxchg(&hwc->prev_co    
318                 new_raw_count) != prev_raw_cou    
319                                                   
320         delta = (new_raw_count - prev_raw_coun    
321                                                   
322         local64_add(delta, &event->count);        
323 }                                                 
324                                                   
325 static void mmdc_pmu_event_start(struct perf_e    
326 {                                                 
327         struct mmdc_pmu *pmu_mmdc = to_mmdc_pm    
328         struct hw_perf_event *hwc = &event->hw    
329         void __iomem *mmdc_base, *reg;            
330         u32 val;                                  
331                                                   
332         mmdc_base = pmu_mmdc->mmdc_base;          
333         reg = mmdc_base + MMDC_MADPCR0;           
334                                                   
335         /*                                        
336          * hrtimer is required because mmdc do    
337          * polling is necessary                   
338          */                                       
339         hrtimer_start(&pmu_mmdc->hrtimer, mmdc    
340                         HRTIMER_MODE_REL_PINNE    
341                                                   
342         local64_set(&hwc->prev_count, 0);         
343                                                   
344         writel(DBG_RST, reg);                     
345                                                   
346         /*                                        
347          * Write the AXI id parameter to MADPC    
348          */                                       
349         val = event->attr.config1;                
350         reg = mmdc_base + MMDC_MADPCR1;           
351         writel(val, reg);                         
352                                                   
353         reg = mmdc_base + MMDC_MADPCR0;           
354         val = DBG_EN;                             
355         if (pmu_mmdc->devtype_data->flags & MM    
356                 val |= PROFILE_SEL;               
357                                                   
358         writel(val, reg);                         
359 }                                                 
360                                                   
361 static int mmdc_pmu_event_add(struct perf_even    
362 {                                                 
363         struct mmdc_pmu *pmu_mmdc = to_mmdc_pm    
364         struct hw_perf_event *hwc = &event->hw    
365                                                   
366         int cfg = event->attr.config;             
367                                                   
368         if (flags & PERF_EF_START)                
369                 mmdc_pmu_event_start(event, fl    
370                                                   
371         if (pmu_mmdc->mmdc_events[cfg] != NULL    
372                 return -EAGAIN;                   
373                                                   
374         pmu_mmdc->mmdc_events[cfg] = event;       
375         pmu_mmdc->active_events++;                
376                                                   
377         local64_set(&hwc->prev_count, mmdc_pmu    
378                                                   
379         return 0;                                 
380 }                                                 
381                                                   
382 static void mmdc_pmu_event_stop(struct perf_ev    
383 {                                                 
384         struct mmdc_pmu *pmu_mmdc = to_mmdc_pm    
385         void __iomem *mmdc_base, *reg;            
386                                                   
387         mmdc_base = pmu_mmdc->mmdc_base;          
388         reg = mmdc_base + MMDC_MADPCR0;           
389                                                   
390         writel(PRF_FRZ, reg);                     
391                                                   
392         reg = mmdc_base + MMDC_MADPCR1;           
393         writel(MMDC_PRF_AXI_ID_CLEAR, reg);       
394                                                   
395         mmdc_pmu_event_update(event);             
396 }                                                 
397                                                   
398 static void mmdc_pmu_event_del(struct perf_eve    
399 {                                                 
400         struct mmdc_pmu *pmu_mmdc = to_mmdc_pm    
401         int cfg = event->attr.config;             
402                                                   
403         pmu_mmdc->mmdc_events[cfg] = NULL;        
404         pmu_mmdc->active_events--;                
405                                                   
406         if (pmu_mmdc->active_events == 0)         
407                 hrtimer_cancel(&pmu_mmdc->hrti    
408                                                   
409         mmdc_pmu_event_stop(event, PERF_EF_UPD    
410 }                                                 
411                                                   
412 static void mmdc_pmu_overflow_handler(struct m    
413 {                                                 
414         int i;                                    
415                                                   
416         for (i = 0; i < MMDC_NUM_COUNTERS; i++    
417                 struct perf_event *event = pmu    
418                                                   
419                 if (event)                        
420                         mmdc_pmu_event_update(    
421         }                                         
422 }                                                 
423                                                   
424 static enum hrtimer_restart mmdc_pmu_timer_han    
425 {                                                 
426         struct mmdc_pmu *pmu_mmdc = container_    
427                         hrtimer);                 
428                                                   
429         mmdc_pmu_overflow_handler(pmu_mmdc);      
430         hrtimer_forward_now(hrtimer, mmdc_pmu_    
431                                                   
432         return HRTIMER_RESTART;                   
433 }                                                 
434                                                   
435 static int mmdc_pmu_init(struct mmdc_pmu *pmu_    
436                 void __iomem *mmdc_base, struc    
437 {                                                 
438         *pmu_mmdc = (struct mmdc_pmu) {           
439                 .pmu = (struct pmu) {             
440                         .parent         = dev,    
441                         .task_ctx_nr    = perf    
442                         .attr_groups    = attr    
443                         .event_init     = mmdc    
444                         .add            = mmdc    
445                         .del            = mmdc    
446                         .start          = mmdc    
447                         .stop           = mmdc    
448                         .read           = mmdc    
449                         .capabilities   = PERF    
450                 },                                
451                 .mmdc_base = mmdc_base,           
452                 .dev = dev,                       
453                 .active_events = 0,               
454         };                                        
455                                                   
456         pmu_mmdc->id = ida_alloc(&mmdc_ida, GF    
457                                                   
458         return pmu_mmdc->id;                      
459 }                                                 
460                                                   
461 static void imx_mmdc_remove(struct platform_de    
462 {                                                 
463         struct mmdc_pmu *pmu_mmdc = platform_g    
464                                                   
465         ida_free(&mmdc_ida, pmu_mmdc->id);        
466         cpuhp_state_remove_instance_nocalls(cp    
467         perf_pmu_unregister(&pmu_mmdc->pmu);      
468         iounmap(pmu_mmdc->mmdc_base);             
469         clk_disable_unprepare(pmu_mmdc->mmdc_i    
470         kfree(pmu_mmdc);                          
471 }                                                 
472                                                   
473 static int imx_mmdc_perf_init(struct platform_    
474                               struct clk *mmdc    
475 {                                                 
476         struct mmdc_pmu *pmu_mmdc;                
477         char *name;                               
478         int ret;                                  
479                                                   
480         pmu_mmdc = kzalloc(sizeof(*pmu_mmdc),     
481         if (!pmu_mmdc) {                          
482                 pr_err("failed to allocate PMU    
483                 return -ENOMEM;                   
484         }                                         
485                                                   
486         /* The first instance registers the ho    
487         if (!cpuhp_mmdc_state) {                  
488                 ret = cpuhp_setup_state_multi(    
489                                                   
490                                                   
491                 if (ret < 0) {                    
492                         pr_err("cpuhp_setup_st    
493                         goto pmu_free;            
494                 }                                 
495                 cpuhp_mmdc_state = ret;           
496         }                                         
497                                                   
498         ret = mmdc_pmu_init(pmu_mmdc, mmdc_bas    
499         if (ret < 0)                              
500                 goto  pmu_free;                   
501                                                   
502         name = devm_kasprintf(&pdev->dev,         
503                                 GFP_KERNEL, "m    
504         if (!name) {                              
505                 ret = -ENOMEM;                    
506                 goto pmu_release_id;              
507         }                                         
508                                                   
509         pmu_mmdc->mmdc_ipg_clk = mmdc_ipg_clk;    
510         pmu_mmdc->devtype_data = device_get_ma    
511                                                   
512         hrtimer_init(&pmu_mmdc->hrtimer, CLOCK    
513                         HRTIMER_MODE_REL);        
514         pmu_mmdc->hrtimer.function = mmdc_pmu_    
515                                                   
516         cpumask_set_cpu(raw_smp_processor_id()    
517                                                   
518         /* Register the pmu instance for cpu h    
519         cpuhp_state_add_instance_nocalls(cpuhp    
520                                                   
521         ret = perf_pmu_register(&(pmu_mmdc->pm    
522         if (ret)                                  
523                 goto pmu_register_err;            
524                                                   
525         platform_set_drvdata(pdev, pmu_mmdc);     
526         return 0;                                 
527                                                   
528 pmu_register_err:                                 
529         pr_warn("MMDC Perf PMU failed (%d), di    
530         cpuhp_state_remove_instance_nocalls(cp    
531         hrtimer_cancel(&pmu_mmdc->hrtimer);       
532 pmu_release_id:                                   
533         ida_free(&mmdc_ida, pmu_mmdc->id);        
534 pmu_free:                                         
535         kfree(pmu_mmdc);                          
536         return ret;                               
537 }                                                 
538                                                   
539 #else                                             
540 #define imx_mmdc_remove NULL                      
541 #define imx_mmdc_perf_init(pdev, mmdc_base, mm    
542 #endif                                            
543                                                   
544 static int imx_mmdc_probe(struct platform_devi    
545 {                                                 
546         struct device_node *np = pdev->dev.of_    
547         void __iomem *mmdc_base, *reg;            
548         struct clk *mmdc_ipg_clk;                 
549         u32 val;                                  
550         int err;                                  
551                                                   
552         /* the ipg clock is optional */           
553         mmdc_ipg_clk = devm_clk_get(&pdev->dev    
554         if (IS_ERR(mmdc_ipg_clk))                 
555                 mmdc_ipg_clk = NULL;              
556                                                   
557         err = clk_prepare_enable(mmdc_ipg_clk)    
558         if (err) {                                
559                 dev_err(&pdev->dev, "Unable to    
560                 return err;                       
561         }                                         
562                                                   
563         mmdc_base = of_iomap(np, 0);              
564         WARN_ON(!mmdc_base);                      
565                                                   
566         reg = mmdc_base + MMDC_MDMISC;            
567         /* Get ddr type */                        
568         val = readl_relaxed(reg);                 
569         ddr_type = (val & BM_MMDC_MDMISC_DDR_T    
570                  BP_MMDC_MDMISC_DDR_TYPE;         
571                                                   
572         reg = mmdc_base + MMDC_MAPSR;             
573                                                   
574         /* Enable automatic power saving */       
575         val = readl_relaxed(reg);                 
576         val &= ~(1 << BP_MMDC_MAPSR_PSD);         
577         writel_relaxed(val, reg);                 
578                                                   
579         err = imx_mmdc_perf_init(pdev, mmdc_ba    
580         if (err) {                                
581                 iounmap(mmdc_base);               
582                 clk_disable_unprepare(mmdc_ipg    
583         }                                         
584                                                   
585         return err;                               
586 }                                                 
587                                                   
588 int imx_mmdc_get_ddr_type(void)                   
589 {                                                 
590         return ddr_type;                          
591 }                                                 
592                                                   
593 static struct platform_driver imx_mmdc_driver     
594         .driver         = {                       
595                 .name   = "imx-mmdc",             
596                 .of_match_table = imx_mmdc_dt_    
597         },                                        
598         .probe          = imx_mmdc_probe,         
599         .remove_new     = imx_mmdc_remove,        
600 };                                                
601                                                   
602 static int __init imx_mmdc_init(void)             
603 {                                                 
604         return platform_driver_register(&imx_m    
605 }                                                 
606 postcore_initcall(imx_mmdc_init);                 
607                                                   

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

kernel.org | git.kernel.org | LWN.net | Project Home | 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.

sflogo.php