summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/shared/amba/ambapp_freq.c
diff options
context:
space:
mode:
authorDaniel Hellstrom <daniel@gaisler.com>2012-04-17 16:25:38 +0200
committerGedare Bloom <gedare@rtems.org>2012-04-17 22:01:46 -0400
commit9ea65119f400d5ad9acc3c52bdfd978fb96b930c (patch)
tree7b1175a757256e3772f9c8afb3f366591a5c093c /c/src/lib/libbsp/sparc/shared/amba/ambapp_freq.c
parentno_cpu: replace no_cpu_isr with rtems_isr (diff)
downloadrtems-9ea65119f400d5ad9acc3c52bdfd978fb96b930c.tar.bz2
LEON: updated AMBA PnP API
The old layer had some limitations/problems for multiple AHB buses since the data structure containing all AMBA devices were allocated before scanning. The new layer create devices as they are found and memory is allocated using malloc() or bsp_early_malloc() during booting. The old 8 functions for finding a specific AHB-Slave or APB-Slave device has been replaced with one function, ambapp_for_each(), which iterates over all devices matching the specified search options and calls a user provided function. The new way lowers the footprint and makes searching more flexible. The frequency information is now supported, if the frequency of one device is reported by the user. More AHB-to-AHB bridges are supported. The API has been split into several parts in order to lower the footprint. The API also introduces the AMBAPP CORE concept, where one ambapp_core can be created from one AHB Master, AHB Slave and one APB Slave, at least one device is required for creating a core. Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
Diffstat (limited to '')
-rw-r--r--c/src/lib/libbsp/sparc/shared/amba/ambapp_freq.c109
1 files changed, 109 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/amba/ambapp_freq.c b/c/src/lib/libbsp/sparc/shared/amba/ambapp_freq.c
new file mode 100644
index 0000000000..03c0f68303
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/amba/ambapp_freq.c
@@ -0,0 +1,109 @@
+/*
+ * AMBA Plug & Play routines
+ *
+ * COPYRIGHT (c) 2011
+ * Aeroflex Gaisler
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <ambapp.h>
+
+/* Calculate AHB Bus frequency of
+ * - Bus[0] (inverse=1), relative to the frequency of Bus[ahbidx]
+ * NOTE: set freq_hz to frequency of Bus[ahbidx].
+ * or
+ * - Bus[ahbidx] (inverse=0), relative to the frequency of Bus[0]
+ * NOTE: set freq_hz to frequency of Bus[0].
+ *
+ * If a unsupported bridge is found the invalid frequncy of 0Hz is
+ * returned.
+ */
+unsigned int ambapp_freq_calc(
+ struct ambapp_bus *abus,
+ int ahbidx,
+ unsigned int freq_hz,
+ int inverse)
+{
+ struct ambapp_ahb_info *ahb;
+ struct ambapp_dev *bridge;
+ unsigned char ffact;
+ int dir;
+
+ /* Found Bus0? */
+ bridge = abus->ahbs[ahbidx].bridge;
+ if (!bridge)
+ return freq_hz;
+
+ /* Find this bus frequency relative to freq_hz */
+ if ((bridge->vendor == VENDOR_GAISLER) &&
+ ((bridge->device == GAISLER_AHB2AHB) ||
+ (bridge->device == GAISLER_L2CACHE))) {
+ ahb = DEV_TO_AHB(bridge);
+ ffact = (ahb->custom[0] & AMBAPP_FLAG_FFACT) >> 4;
+ if (ffact != 0) {
+ dir = ahb->custom[0] & AMBAPP_FLAG_FFACT_DIR;
+
+ /* Calculate frequency by dividing or
+ * multiplying system frequency
+ */
+ if ((dir && !inverse) || (!dir && inverse))
+ freq_hz = freq_hz * ffact;
+ else
+ freq_hz = freq_hz / ffact;
+ }
+ return ambapp_freq_calc(abus, ahb->ahbidx, freq_hz, inverse);
+ } else {
+ /* Unknown bridge, impossible to calc frequency */
+ return 0;
+ }
+}
+
+/* Find the frequency of all AHB Buses from knowing the frequency of one
+ * particular APB/AHB Device.
+ */
+void ambapp_freq_init(
+ struct ambapp_bus *abus,
+ struct ambapp_dev *dev,
+ unsigned int freq_hz)
+{
+ struct ambapp_common_info *info;
+ int i;
+
+ for (i=0; i<AHB_BUS_MAX; i++)
+ abus->ahbs[i].freq_hz = 0;
+
+ /* Register Frequency at the AHB bus that the device the user gave us
+ * is located at.
+ */
+ if (dev) {
+ info = DEV_TO_COMMON(dev);
+ abus->ahbs[info->ahbidx].freq_hz = freq_hz;
+
+ /* Find Frequency of Bus 0 */
+ abus->ahbs[0].freq_hz = ambapp_freq_calc(abus, info->ahbidx, freq_hz, 1);
+ } else {
+ abus->ahbs[0].freq_hz = freq_hz;
+ }
+
+ /* Find Frequency of all except for Bus0 and the bus which frequency
+ * was reported at
+ */
+ for (i=1; i<AHB_BUS_MAX; i++) {
+ if (abus->ahbs[i].ioarea == 0)
+ break;
+ if (abus->ahbs[i].freq_hz != 0)
+ continue;
+ abus->ahbs[i].freq_hz = ambapp_freq_calc(abus, i, abus->ahbs[0].freq_hz, 0);
+ }
+}
+
+/* Assign a AMBA Bus a frequency but reporting the frequency of a
+ * particular AHB/APB device */
+unsigned int ambapp_freq_get(struct ambapp_bus *abus, struct ambapp_dev *dev)
+{
+ struct ambapp_common_info *info = DEV_TO_COMMON(dev);
+ return abus->ahbs[info->ahbidx].freq_hz;
+}