Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:05

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  *  AMBA Plug & Play routines
0005  *
0006  *  COPYRIGHT (c) 2011
0007  *  Aeroflex Gaisler
0008  *
0009  * Redistribution and use in source and binary forms, with or without
0010  * modification, are permitted provided that the following conditions
0011  * are met:
0012  * 1. Redistributions of source code must retain the above copyright
0013  *    notice, this list of conditions and the following disclaimer.
0014  * 2. Redistributions in binary form must reproduce the above copyright
0015  *    notice, this list of conditions and the following disclaimer in the
0016  *    documentation and/or other materials provided with the distribution.
0017  *
0018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0028  * POSSIBILITY OF SUCH DAMAGE.
0029  */
0030 
0031 #include <grlib/ambapp.h>
0032 
0033 /* Calculate AHB Bus frequency of
0034  *   - Bus[0] (inverse=1), relative to the frequency of Bus[ahbidx]
0035  *     NOTE: set freq_hz to frequency of Bus[ahbidx].
0036  *   or
0037  *   - Bus[ahbidx] (inverse=0), relative to the frequency of Bus[0]
0038  *     NOTE: set freq_hz to frequency of Bus[0].
0039  *
0040  * If a unsupported bridge is found the invalid frequncy of 0Hz is
0041  * returned.
0042  */
0043 static unsigned int ambapp_freq_calc(
0044   struct ambapp_bus *abus,
0045   int ahbidx,
0046   unsigned int freq_hz,
0047   int inverse)
0048 {
0049   struct ambapp_ahb_info *ahb;
0050   struct ambapp_dev *bridge;
0051   unsigned char ffact;
0052   int dir;
0053 
0054   /* Found Bus0? */
0055   bridge = abus->ahbs[ahbidx].bridge;
0056   if (!bridge)
0057     return freq_hz;
0058 
0059   /* Find this bus frequency relative to freq_hz */
0060   if ((bridge->vendor == VENDOR_GAISLER) &&
0061       ((bridge->device == GAISLER_AHB2AHB) ||
0062       (bridge->device == GAISLER_L2CACHE))) {
0063     ahb = DEV_TO_AHB(bridge);
0064     ffact = (ahb->custom[0] & AMBAPP_FLAG_FFACT) >> 4;
0065     if (ffact != 0) {
0066       dir = ahb->custom[0] & AMBAPP_FLAG_FFACT_DIR;
0067 
0068       /* Calculate frequency by dividing or
0069        * multiplying system frequency
0070        */
0071       if ((dir && !inverse) || (!dir && inverse))
0072         freq_hz = freq_hz * ffact;
0073       else
0074         freq_hz = freq_hz / ffact;
0075     }
0076     return ambapp_freq_calc(abus, ahb->common.ahbidx, freq_hz, inverse);
0077   } else {
0078     /* Unknown bridge, impossible to calc frequency */
0079     return 0;
0080   }
0081 }
0082 
0083 /* Find the frequency of all AHB Buses from knowing the frequency of one
0084  * particular APB/AHB Device.
0085  */
0086 void ambapp_freq_init(
0087   struct ambapp_bus *abus,
0088   struct ambapp_dev *dev,
0089   unsigned int freq_hz)
0090 {
0091   struct ambapp_common_info *info;
0092   int i;
0093 
0094   for (i=0; i<AHB_BUS_MAX; i++)
0095     abus->ahbs[i].freq_hz = 0;
0096 
0097   /* Register Frequency at the AHB bus that the device the user gave us
0098    * is located at.
0099    */
0100   if (dev) {
0101     info = DEV_TO_COMMON(dev);
0102     abus->ahbs[info->ahbidx].freq_hz = freq_hz;
0103 
0104     /* Find Frequency of Bus 0 */
0105     abus->ahbs[0].freq_hz = ambapp_freq_calc(abus, info->ahbidx, freq_hz, 1);
0106   } else {
0107     abus->ahbs[0].freq_hz = freq_hz;
0108   }
0109 
0110   /* Find Frequency of all except for Bus0 and the bus which frequency
0111    * was reported at
0112    */
0113   for (i=1; i<AHB_BUS_MAX; i++) {
0114     if (abus->ahbs[i].ioarea == 0)
0115       break;
0116     if (abus->ahbs[i].freq_hz != 0)
0117       continue;
0118     abus->ahbs[i].freq_hz = ambapp_freq_calc(abus, i, abus->ahbs[0].freq_hz, 0);
0119   }
0120 }
0121 
0122 /* Assign a AMBA Bus a frequency but reporting the frequency of a
0123  * particular AHB/APB device */
0124 unsigned int ambapp_freq_get(struct ambapp_bus *abus, struct ambapp_dev *dev)
0125 {
0126   struct ambapp_common_info *info = DEV_TO_COMMON(dev);
0127   return abus->ahbs[info->ahbidx].freq_hz;
0128 }