1 | /* |
---|
2 | * AMBA Plug & Play routines |
---|
3 | * |
---|
4 | * COPYRIGHT (c) 2011 |
---|
5 | * Aeroflex Gaisler |
---|
6 | * |
---|
7 | * The license and distribution terms for this file may be |
---|
8 | * found in the file LICENSE in this distribution or at |
---|
9 | * http://www.rtems.org/license/LICENSE. |
---|
10 | */ |
---|
11 | |
---|
12 | #include <grlib/ambapp.h> |
---|
13 | |
---|
14 | /* Calculate AHB Bus frequency of |
---|
15 | * - Bus[0] (inverse=1), relative to the frequency of Bus[ahbidx] |
---|
16 | * NOTE: set freq_hz to frequency of Bus[ahbidx]. |
---|
17 | * or |
---|
18 | * - Bus[ahbidx] (inverse=0), relative to the frequency of Bus[0] |
---|
19 | * NOTE: set freq_hz to frequency of Bus[0]. |
---|
20 | * |
---|
21 | * If a unsupported bridge is found the invalid frequncy of 0Hz is |
---|
22 | * returned. |
---|
23 | */ |
---|
24 | static unsigned int ambapp_freq_calc( |
---|
25 | struct ambapp_bus *abus, |
---|
26 | int ahbidx, |
---|
27 | unsigned int freq_hz, |
---|
28 | int inverse) |
---|
29 | { |
---|
30 | struct ambapp_ahb_info *ahb; |
---|
31 | struct ambapp_dev *bridge; |
---|
32 | unsigned char ffact; |
---|
33 | int dir; |
---|
34 | |
---|
35 | /* Found Bus0? */ |
---|
36 | bridge = abus->ahbs[ahbidx].bridge; |
---|
37 | if (!bridge) |
---|
38 | return freq_hz; |
---|
39 | |
---|
40 | /* Find this bus frequency relative to freq_hz */ |
---|
41 | if ((bridge->vendor == VENDOR_GAISLER) && |
---|
42 | ((bridge->device == GAISLER_AHB2AHB) || |
---|
43 | (bridge->device == GAISLER_L2CACHE))) { |
---|
44 | ahb = DEV_TO_AHB(bridge); |
---|
45 | ffact = (ahb->custom[0] & AMBAPP_FLAG_FFACT) >> 4; |
---|
46 | if (ffact != 0) { |
---|
47 | dir = ahb->custom[0] & AMBAPP_FLAG_FFACT_DIR; |
---|
48 | |
---|
49 | /* Calculate frequency by dividing or |
---|
50 | * multiplying system frequency |
---|
51 | */ |
---|
52 | if ((dir && !inverse) || (!dir && inverse)) |
---|
53 | freq_hz = freq_hz * ffact; |
---|
54 | else |
---|
55 | freq_hz = freq_hz / ffact; |
---|
56 | } |
---|
57 | return ambapp_freq_calc(abus, ahb->ahbidx, freq_hz, inverse); |
---|
58 | } else { |
---|
59 | /* Unknown bridge, impossible to calc frequency */ |
---|
60 | return 0; |
---|
61 | } |
---|
62 | } |
---|
63 | |
---|
64 | /* Find the frequency of all AHB Buses from knowing the frequency of one |
---|
65 | * particular APB/AHB Device. |
---|
66 | */ |
---|
67 | void ambapp_freq_init( |
---|
68 | struct ambapp_bus *abus, |
---|
69 | struct ambapp_dev *dev, |
---|
70 | unsigned int freq_hz) |
---|
71 | { |
---|
72 | struct ambapp_common_info *info; |
---|
73 | int i; |
---|
74 | |
---|
75 | for (i=0; i<AHB_BUS_MAX; i++) |
---|
76 | abus->ahbs[i].freq_hz = 0; |
---|
77 | |
---|
78 | /* Register Frequency at the AHB bus that the device the user gave us |
---|
79 | * is located at. |
---|
80 | */ |
---|
81 | if (dev) { |
---|
82 | info = DEV_TO_COMMON(dev); |
---|
83 | abus->ahbs[info->ahbidx].freq_hz = freq_hz; |
---|
84 | |
---|
85 | /* Find Frequency of Bus 0 */ |
---|
86 | abus->ahbs[0].freq_hz = ambapp_freq_calc(abus, info->ahbidx, freq_hz, 1); |
---|
87 | } else { |
---|
88 | abus->ahbs[0].freq_hz = freq_hz; |
---|
89 | } |
---|
90 | |
---|
91 | /* Find Frequency of all except for Bus0 and the bus which frequency |
---|
92 | * was reported at |
---|
93 | */ |
---|
94 | for (i=1; i<AHB_BUS_MAX; i++) { |
---|
95 | if (abus->ahbs[i].ioarea == 0) |
---|
96 | break; |
---|
97 | if (abus->ahbs[i].freq_hz != 0) |
---|
98 | continue; |
---|
99 | abus->ahbs[i].freq_hz = ambapp_freq_calc(abus, i, abus->ahbs[0].freq_hz, 0); |
---|
100 | } |
---|
101 | } |
---|
102 | |
---|
103 | /* Assign a AMBA Bus a frequency but reporting the frequency of a |
---|
104 | * particular AHB/APB device */ |
---|
105 | unsigned int ambapp_freq_get(struct ambapp_bus *abus, struct ambapp_dev *dev) |
---|
106 | { |
---|
107 | struct ambapp_common_info *info = DEV_TO_COMMON(dev); |
---|
108 | return abus->ahbs[info->ahbidx].freq_hz; |
---|
109 | } |
---|