]> git.sur5r.net Git - u-boot/blob - drivers/ddr/marvell/a38x/ddr3_training_db.c
Merge git://git.denx.de/u-boot-uniphier
[u-boot] / drivers / ddr / marvell / a38x / ddr3_training_db.c
1 /*
2  * Copyright (C) Marvell International Ltd. and its affiliates
3  *
4  * SPDX-License-Identifier:     GPL-2.0
5  */
6
7 #include <common.h>
8 #include <spl.h>
9 #include <asm/io.h>
10 #include <asm/arch/cpu.h>
11 #include <asm/arch/soc.h>
12
13 #include "ddr3_init.h"
14
15 /* List of allowed frequency listed in order of enum hws_ddr_freq */
16 u32 freq_val[DDR_FREQ_LIMIT] = {
17         0,                      /*DDR_FREQ_LOW_FREQ */
18         400,                    /*DDR_FREQ_400, */
19         533,                    /*DDR_FREQ_533, */
20         666,                    /*DDR_FREQ_667, */
21         800,                    /*DDR_FREQ_800, */
22         933,                    /*DDR_FREQ_933, */
23         1066,                   /*DDR_FREQ_1066, */
24         311,                    /*DDR_FREQ_311, */
25         333,                    /*DDR_FREQ_333, */
26         467,                    /*DDR_FREQ_467, */
27         850,                    /*DDR_FREQ_850, */
28         600,                    /*DDR_FREQ_600 */
29         300,                    /*DDR_FREQ_300 */
30         900,                    /*DDR_FREQ_900 */
31         360,                    /*DDR_FREQ_360 */
32         1000                    /*DDR_FREQ_1000 */
33 };
34
35 /* Table for CL values per frequency for each speed bin index */
36 struct cl_val_per_freq cas_latency_table[] = {
37         /*
38          * 400M   667M     933M   311M     467M  600M    360
39          * 100M    533M    800M    1066M   333M    850M      900
40          * 1000 (the order is 100, 400, 533 etc.)
41          */
42         /* DDR3-800D */
43         { {6, 5, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 5, 0, 5, 0} },
44         /* DDR3-800E */
45         { {6, 6, 0, 0, 0, 0, 0, 6, 6, 0, 0, 0, 6, 0, 6, 0} },
46         /* DDR3-1066E */
47         { {6, 5, 6, 0, 0, 0, 0, 5, 5, 6, 0, 0, 5, 0, 5, 0} },
48         /* DDR3-1066F */
49         { {6, 6, 7, 0, 0, 0, 0, 6, 6, 7, 0, 0, 6, 0, 6, 0} },
50         /* DDR3-1066G */
51         { {6, 6, 8, 0, 0, 0, 0, 6, 6, 8, 0, 0, 6, 0, 6, 0} },
52         /* DDR3-1333F* */
53         { {6, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
54         /* DDR3-1333G */
55         { {6, 5, 7, 8, 0, 0, 0, 5, 5, 7, 0, 8, 5, 0, 5, 0} },
56         /* DDR3-1333H */
57         { {6, 6, 8, 9, 0, 0, 0, 6, 6, 8, 0, 9, 6, 0, 6, 0} },
58         /* DDR3-1333J* */
59         { {6, 6, 8, 10, 0, 0, 0, 6, 6, 8, 0, 10, 6, 0, 6,  0}
60          /* DDR3-1600G* */},
61         { {6, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
62         /* DDR3-1600H */
63         { {6, 5, 6, 8, 9, 0, 0, 5, 5, 6, 0, 8, 5, 0, 5, 0} },
64         /* DDR3-1600J */
65         { {6, 5, 7, 9, 10, 0, 0, 5, 5, 7, 0, 9, 5, 0, 5, 0} },
66         /* DDR3-1600K */
67         { {6, 6, 8, 10, 11, 0, 0, 6, 6, 8, 0, 10, 6, 0, 6, 0 } },
68         /* DDR3-1866J* */
69         { {6, 5, 6, 8, 9, 11, 0, 5, 5, 6, 11, 8, 5, 0, 5, 0} },
70         /* DDR3-1866K */
71         { {6, 5, 7, 8, 10, 11, 0, 5, 5, 7, 11, 8, 5, 11, 5, 11} },
72         /* DDR3-1866L */
73         { {6, 6, 7, 9, 11, 12, 0, 6, 6, 7, 12, 9, 6, 12, 6, 12} },
74         /* DDR3-1866M* */
75         { {6, 6, 8, 10, 11, 13, 0, 6, 6, 8, 13, 10, 6, 13, 6, 13} },
76         /* DDR3-2133K* */
77         { {6, 5, 6, 7, 9, 10, 11, 5, 5, 6, 10, 7, 5, 11, 5, 11} },
78         /* DDR3-2133L */
79         { {6, 5, 6, 8, 9, 11, 12, 5, 5, 6, 11, 8, 5, 12, 5, 12} },
80         /* DDR3-2133M */
81         { {6, 5, 7, 9, 10, 12, 13, 5, 5, 7, 12, 9, 5, 13, 5, 13} },
82         /* DDR3-2133N* */
83         { {6, 6, 7, 9, 11, 13, 14, 6, 6, 7, 13, 9, 6, 14,  6, 14} },
84         /* DDR3-1333H-ext */
85         { {6, 6, 7, 9, 0, 0, 0, 6, 6, 7, 0, 9, 6, 0, 6, 0} },
86         /* DDR3-1600K-ext */
87         { {6, 6, 7, 9, 11, 0, 0, 6, 6, 7, 0, 9, 6, 0, 6, 0} },
88         /* DDR3-1866M-ext */
89         { {6, 6, 7, 9, 11, 13, 0, 6, 6, 7, 13, 9, 6, 13, 6, 13} },
90 };
91
92 /* Table for CWL values per speedbin index */
93 struct cl_val_per_freq cas_write_latency_table[] = {
94         /*
95          * 400M   667M     933M   311M     467M  600M    360
96          * 100M    533M    800M    1066M   333M    850M      900
97          * (the order is 100, 400, 533 etc.)
98          */
99         /* DDR3-800D  */
100         { {5, 5, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 5, 0, 5, 0} },
101         /* DDR3-800E  */
102         { {5, 5, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 5, 0, 5, 0} },
103         /* DDR3-1066E  */
104         { {5, 5, 6, 0, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
105         /* DDR3-1066F  */
106         { {5, 5, 6, 0, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
107         /* DDR3-1066G  */
108         { {5, 5, 6, 0, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
109         /* DDR3-1333F*  */
110         { {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
111         /* DDR3-1333G  */
112         { {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
113         /* DDR3-1333H  */
114         { {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
115         /* DDR3-1333J*  */
116         { {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
117         /* DDR3-1600G*  */
118         { {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
119         /* DDR3-1600H  */
120         { {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
121         /* DDR3-1600J  */
122         { {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
123         /* DDR3-1600K  */
124         { {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
125         /* DDR3-1866J*  */
126         { {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 0, 5, 0} },
127         /* DDR3-1866K  */
128         { {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 0, 5, 0} },
129         /* DDR3-1866L  */
130         { {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 9, 5, 9} },
131         /* DDR3-1866M*   */
132         { {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 9, 5, 9} },
133         /* DDR3-2133K*  */
134         { {5, 5, 6, 7, 8, 9, 10, 5, 5, 6, 9, 7, 5, 9, 5, 10} },
135         /* DDR3-2133L  */
136         { {5, 5, 6, 7, 8, 9, 10, 5, 5, 6, 9, 7, 5, 9, 5, 10} },
137         /* DDR3-2133M  */
138         { {5, 5, 6, 7, 8, 9, 10, 5, 5, 6, 9, 7, 5, 9, 5, 10} },
139         /* DDR3-2133N*  */
140         { {5, 5, 6, 7, 8, 9, 10, 5, 5, 6, 9, 7, 5, 9, 5, 10} },
141         /* DDR3-1333H-ext  */
142         { {5, 5, 6, 7, 0, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
143         /* DDR3-1600K-ext  */
144         { {5, 5, 6, 7, 8, 0, 0, 5, 5, 6, 0, 7, 5, 0, 5, 0} },
145         /* DDR3-1866M-ext  */
146         { {5, 5, 6, 7, 8, 9, 0, 5, 5, 6, 9, 7, 5, 9, 5, 9} },
147 };
148
149 u8 twr_mask_table[] = {
150         10,
151         10,
152         10,
153         10,
154         10,
155         1,                      /*5 */
156         2,                      /*6 */
157         3,                      /*7 */
158         10,
159         10,
160         5,                      /*10 */
161         10,
162         6,                      /*12 */
163         10,
164         7,                      /*14 */
165         10,
166         0                       /*16 */
167 };
168
169 u8 cl_mask_table[] = {
170         0,
171         0,
172         0,
173         0,
174         0,
175         0x2,
176         0x4,
177         0x6,
178         0x8,
179         0xa,
180         0xc,
181         0xe,
182         0x1,
183         0x3,
184         0x5,
185         0x5
186 };
187
188 u8 cwl_mask_table[] = {
189         0,
190         0,
191         0,
192         0,
193         0,
194         0,
195         0x1,
196         0x2,
197         0x3,
198         0x4,
199         0x5,
200         0x6,
201         0x7,
202         0x8,
203         0x9,
204         0x9
205 };
206
207 /* RFC values (in ns) */
208 u16 rfc_table[] = {
209         90,                     /* 512M */
210         110,                    /* 1G */
211         160,                    /* 2G */
212         260,                    /* 4G */
213         350                     /* 8G */
214 };
215
216 u32 speed_bin_table_t_rc[] = {
217         50000,
218         52500,
219         48750,
220         50625,
221         52500,
222         46500,
223         48000,
224         49500,
225         51000,
226         45000,
227         46250,
228         47500,
229         48750,
230         44700,
231         45770,
232         46840,
233         47910,
234         43285,
235         44220,
236         45155,
237         46900
238 };
239
240 u32 speed_bin_table_t_rcd_t_rp[] = {
241         12500,
242         15000,
243         11250,
244         13125,
245         15000,
246         10500,
247         12000,
248         13500,
249         15000,
250         10000,
251         11250,
252         12500,
253         13750,
254         10700,
255         11770,
256         12840,
257         13910,
258         10285,
259         11022,
260         12155,
261         13090,
262 };
263
264 enum {
265         PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_AGGRESSOR = 0,
266         PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM
267 };
268
269 static u8 pattern_killer_pattern_table_map[KILLER_PATTERN_LENGTH * 2][2] = {
270         /*Aggressor / Victim */
271         {1, 0},
272         {0, 0},
273         {1, 0},
274         {1, 1},
275         {0, 1},
276         {0, 1},
277         {1, 0},
278         {0, 1},
279         {1, 0},
280         {0, 1},
281         {1, 0},
282         {1, 0},
283         {0, 1},
284         {1, 0},
285         {0, 1},
286         {0, 0},
287         {1, 1},
288         {0, 0},
289         {1, 1},
290         {0, 0},
291         {1, 1},
292         {0, 0},
293         {1, 1},
294         {1, 0},
295         {0, 0},
296         {1, 1},
297         {0, 0},
298         {1, 1},
299         {0, 0},
300         {0, 0},
301         {0, 0},
302         {0, 1},
303         {0, 1},
304         {1, 1},
305         {0, 0},
306         {0, 0},
307         {1, 1},
308         {1, 1},
309         {0, 0},
310         {1, 1},
311         {0, 0},
312         {1, 1},
313         {1, 1},
314         {0, 0},
315         {0, 0},
316         {1, 1},
317         {0, 0},
318         {1, 1},
319         {0, 1},
320         {0, 0},
321         {0, 1},
322         {0, 1},
323         {0, 0},
324         {1, 1},
325         {1, 1},
326         {1, 0},
327         {1, 0},
328         {1, 1},
329         {1, 1},
330         {1, 1},
331         {1, 1},
332         {1, 1},
333         {1, 1},
334         {1, 1}
335 };
336
337 static u8 pattern_vref_pattern_table_map[] = {
338         /* 1 means 0xffffffff, 0 is 0x0 */
339         0xb8,
340         0x52,
341         0x55,
342         0x8a,
343         0x33,
344         0xa6,
345         0x6d,
346         0xfe
347 };
348
349 /* Return speed Bin value for selected index and t* element */
350 u32 speed_bin_table(u8 index, enum speed_bin_table_elements element)
351 {
352         u32 result = 0;
353
354         switch (element) {
355         case SPEED_BIN_TRCD:
356         case SPEED_BIN_TRP:
357                 result = speed_bin_table_t_rcd_t_rp[index];
358                 break;
359         case SPEED_BIN_TRAS:
360                 if (index < 6)
361                         result = 37500;
362                 else if (index < 10)
363                         result = 36000;
364                 else if (index < 14)
365                         result = 35000;
366                 else if (index < 18)
367                         result = 34000;
368                 else
369                         result = 33000;
370                 break;
371         case SPEED_BIN_TRC:
372                 result = speed_bin_table_t_rc[index];
373                 break;
374         case SPEED_BIN_TRRD1K:
375                 if (index < 3)
376                         result = 10000;
377                 else if (index < 6)
378                         result = 7005;
379                 else if (index < 14)
380                         result = 6000;
381                 else
382                         result = 5000;
383                 break;
384         case SPEED_BIN_TRRD2K:
385                 if (index < 6)
386                         result = 10000;
387                 else if (index < 14)
388                         result = 7005;
389                 else
390                         result = 6000;
391                 break;
392         case SPEED_BIN_TPD:
393                 if (index < 3)
394                         result = 7500;
395                 else if (index < 10)
396                         result = 5625;
397                 else
398                         result = 5000;
399                 break;
400         case SPEED_BIN_TFAW1K:
401                 if (index < 3)
402                         result = 40000;
403                 else if (index < 6)
404                         result = 37500;
405                 else if (index < 14)
406                         result = 30000;
407                 else if (index < 18)
408                         result = 27000;
409                 else
410                         result = 25000;
411                 break;
412         case SPEED_BIN_TFAW2K:
413                 if (index < 6)
414                         result = 50000;
415                 else if (index < 10)
416                         result = 45000;
417                 else if (index < 14)
418                         result = 40000;
419                 else
420                         result = 35000;
421                 break;
422         case SPEED_BIN_TWTR:
423                 result = 7500;
424                 break;
425         case SPEED_BIN_TRTP:
426                 result = 7500;
427                 break;
428         case SPEED_BIN_TWR:
429                 result = 15000;
430                 break;
431         case SPEED_BIN_TMOD:
432                 result = 15000;
433                 break;
434         default:
435                 break;
436         }
437
438         return result;
439 }
440
441 static inline u32 pattern_table_get_killer_word(u8 dqs, u8 index)
442 {
443         u8 i, byte = 0;
444         u8 role;
445
446         for (i = 0; i < 8; i++) {
447                 role = (i == dqs) ?
448                         (PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_AGGRESSOR) :
449                         (PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM);
450                 byte |= pattern_killer_pattern_table_map[index][role] << i;
451         }
452
453         return byte | (byte << 8) | (byte << 16) | (byte << 24);
454 }
455
456 static inline u32 pattern_table_get_killer_word16(u8 dqs, u8 index)
457 {
458         u8 i, byte0 = 0, byte1 = 0;
459         u8 role;
460
461         for (i = 0; i < 8; i++) {
462                 role = (i == dqs) ?
463                         (PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_AGGRESSOR) :
464                         (PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM);
465                 byte0 |= pattern_killer_pattern_table_map[index * 2][role] << i;
466         }
467
468         for (i = 0; i < 8; i++) {
469                 role = (i == dqs) ?
470                         (PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_AGGRESSOR) :
471                         (PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM);
472                 byte1 |= pattern_killer_pattern_table_map
473                         [index * 2 + 1][role] << i;
474         }
475
476         return byte0 | (byte0 << 8) | (byte1 << 16) | (byte1 << 24);
477 }
478
479 static inline u32 pattern_table_get_sso_word(u8 sso, u8 index)
480 {
481         u8 step = sso + 1;
482
483         if (0 == ((index / step) & 1))
484                 return 0x0;
485         else
486                 return 0xffffffff;
487 }
488
489 static inline u32 pattern_table_get_vref_word(u8 index)
490 {
491         if (0 == ((pattern_vref_pattern_table_map[index / 8] >>
492                    (index % 8)) & 1))
493                 return 0x0;
494         else
495                 return 0xffffffff;
496 }
497
498 static inline u32 pattern_table_get_vref_word16(u8 index)
499 {
500         if (0 == pattern_killer_pattern_table_map
501             [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2] &&
502             0 == pattern_killer_pattern_table_map
503             [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2 + 1])
504                 return 0x00000000;
505         else if (1 == pattern_killer_pattern_table_map
506                  [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2] &&
507                  0 == pattern_killer_pattern_table_map
508                  [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2 + 1])
509                 return 0xffff0000;
510         else if (0 == pattern_killer_pattern_table_map
511                  [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2] &&
512                  1 == pattern_killer_pattern_table_map
513                  [PATTERN_KILLER_PATTERN_TABLE_MAP_ROLE_VICTIM][index * 2 + 1])
514                 return 0x0000ffff;
515         else
516                 return 0xffffffff;
517 }
518
519 static inline u32 pattern_table_get_static_pbs_word(u8 index)
520 {
521         u16 temp;
522
523         temp = ((0x00ff << (index / 3)) & 0xff00) >> 8;
524
525         return temp | (temp << 8) | (temp << 16) | (temp << 24);
526 }
527
528 inline u32 pattern_table_get_word(u32 dev_num, enum hws_pattern type, u8 index)
529 {
530         u32 pattern;
531         struct hws_topology_map *tm = ddr3_get_topology_map();
532
533         if (DDR3_IS_16BIT_DRAM_MODE(tm->bus_act_mask) == 0) {
534                 /* 32bit patterns */
535                 switch (type) {
536                 case PATTERN_PBS1:
537                 case PATTERN_PBS2:
538                         if (index == 0 || index == 2 || index == 5 ||
539                             index == 7)
540                                 pattern = PATTERN_55;
541                         else
542                                 pattern = PATTERN_AA;
543                         break;
544                 case PATTERN_PBS3:
545                         if (0 == (index & 1))
546                                 pattern = PATTERN_55;
547                         else
548                                 pattern = PATTERN_AA;
549                         break;
550                 case PATTERN_RL:
551                         if (index < 6)
552                                 pattern = PATTERN_00;
553                         else
554                                 pattern = PATTERN_80;
555                         break;
556                 case PATTERN_STATIC_PBS:
557                         pattern = pattern_table_get_static_pbs_word(index);
558                         break;
559                 case PATTERN_KILLER_DQ0:
560                 case PATTERN_KILLER_DQ1:
561                 case PATTERN_KILLER_DQ2:
562                 case PATTERN_KILLER_DQ3:
563                 case PATTERN_KILLER_DQ4:
564                 case PATTERN_KILLER_DQ5:
565                 case PATTERN_KILLER_DQ6:
566                 case PATTERN_KILLER_DQ7:
567                         pattern = pattern_table_get_killer_word(
568                                 (u8)(type - PATTERN_KILLER_DQ0), index);
569                         break;
570                 case PATTERN_RL2:
571                         if (index < 6)
572                                 pattern = PATTERN_00;
573                         else
574                                 pattern = PATTERN_01;
575                         break;
576                 case PATTERN_TEST:
577                         if (index > 1 && index < 6)
578                                 pattern = PATTERN_20;
579                         else
580                                 pattern = PATTERN_00;
581                         break;
582                 case PATTERN_FULL_SSO0:
583                 case PATTERN_FULL_SSO1:
584                 case PATTERN_FULL_SSO2:
585                 case PATTERN_FULL_SSO3:
586                         pattern = pattern_table_get_sso_word(
587                                 (u8)(type - PATTERN_FULL_SSO0), index);
588                         break;
589                 case PATTERN_VREF:
590                         pattern = pattern_table_get_vref_word(index);
591                         break;
592                 default:
593                         pattern = 0;
594                         break;
595                 }
596         } else {
597                 /* 16bit patterns */
598                 switch (type) {
599                 case PATTERN_PBS1:
600                 case PATTERN_PBS2:
601                 case PATTERN_PBS3:
602                         pattern = PATTERN_55AA;
603                         break;
604                 case PATTERN_RL:
605                         if (index < 3)
606                                 pattern = PATTERN_00;
607                         else
608                                 pattern = PATTERN_80;
609                         break;
610                 case PATTERN_STATIC_PBS:
611                         pattern = PATTERN_00FF;
612                         break;
613                 case PATTERN_KILLER_DQ0:
614                 case PATTERN_KILLER_DQ1:
615                 case PATTERN_KILLER_DQ2:
616                 case PATTERN_KILLER_DQ3:
617                 case PATTERN_KILLER_DQ4:
618                 case PATTERN_KILLER_DQ5:
619                 case PATTERN_KILLER_DQ6:
620                 case PATTERN_KILLER_DQ7:
621                         pattern = pattern_table_get_killer_word16(
622                                 (u8)(type - PATTERN_KILLER_DQ0), index);
623                         break;
624                 case PATTERN_RL2:
625                         if (index < 3)
626                                 pattern = PATTERN_00;
627                         else
628                                 pattern = PATTERN_01;
629                         break;
630                 case PATTERN_TEST:
631                         pattern = PATTERN_0080;
632                         break;
633                 case PATTERN_FULL_SSO0:
634                         pattern = 0x0000ffff;
635                         break;
636                 case PATTERN_FULL_SSO1:
637                 case PATTERN_FULL_SSO2:
638                 case PATTERN_FULL_SSO3:
639                         pattern = pattern_table_get_sso_word(
640                                 (u8)(type - PATTERN_FULL_SSO1), index);
641                         break;
642                 case PATTERN_VREF:
643                         pattern = pattern_table_get_vref_word16(index);
644                         break;
645                 default:
646                         pattern = 0;
647                         break;
648                 }
649         }
650
651         return pattern;
652 }