Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:39

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsARMTMS570
0007  *
0008  * @brief This source file contains the I/O Multiplexing Module (IOMM) support
0009  *   implementation.
0010  */
0011 
0012 /*
0013  * Copyright (C) 2015 Premysl Houdek <kom541000@gmail.com>
0014  *
0015  * Google Summer of Code 2014 at
0016  * Czech Technical University in Prague
0017  * Zikova 1903/4
0018  * 166 36 Praha 6
0019  * Czech Republic
0020  *
0021  * Redistribution and use in source and binary forms, with or without
0022  * modification, are permitted provided that the following conditions
0023  * are met:
0024  * 1. Redistributions of source code must retain the above copyright
0025  *    notice, this list of conditions and the following disclaimer.
0026  * 2. Redistributions in binary form must reproduce the above copyright
0027  *    notice, this list of conditions and the following disclaimer in the
0028  *    documentation and/or other materials provided with the distribution.
0029  *
0030  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0031  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0032  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0033  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0034  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0035  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0036  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0037  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0038  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0039  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0040  * POSSIBILITY OF SUCH DAMAGE.
0041  */
0042 
0043 #include <bsp/tms570.h>
0044 #include <bsp/tms570-pinmux.h>
0045 #include <bsp/irq.h>
0046 
0047 RTEMS_STATIC_ASSERT(
0048   TMS570_PIN_CLEAR_RQ_MASK == TMS570_PIN_FNC_CLEAR << TMS570_PIN_FNC_SHIFT,
0049   TMS570_PIN_CONFIG
0050 );
0051 
0052 static inline void
0053 tms570_bsp_pin_to_pinmmrx(volatile uint32_t **pinmmrx, uint32_t *pin_shift,
0054                           uint32_t config)
0055 {
0056   uint32_t pin_num = (config & TMS570_PIN_NUM_MASK) >> TMS570_PIN_NUM_SHIFT;
0057   *pinmmrx = TMS570_PINMUX + (pin_num >> 2);
0058   *pin_shift = (pin_num & 0x3)*8;
0059 }
0060 
0061 /**
0062  * @brief select desired function of pin/ball
0063  *
0064  * The function setups multiplexer to interconnect pin with
0065  * specified function/peripheral. Pin number is index into pinmux
0066  * entries array. Predefined values for pins are in a format
0067  * TMS570_BALL_ \c column \c row (for example \c TMS570_BALL_N19).
0068  * The multiplexer allows to interconnect one pin to multiple
0069  * signal sources/sinks in the theory but it is usually bad choice.
0070  * The function sets only specified function and clears all other
0071  * connections.
0072  *
0073  * @param[in] pin_num  pin/ball identifier (index into pinmux array),
0074  * @param[in] pin_fnc  function number 0 .. 7, if value \c TMS570_PIN_FNC_AUTO
0075  *                     is specified then pin function is extracted from
0076  *                     pin_num argument
0077  * @retval Void
0078  */
0079 void
0080 tms570_bsp_pin_set_function(int pin_num, int pin_fnc)
0081 {
0082   unsigned int pin_shift;
0083   volatile uint32_t *pinmmrx;
0084 
0085   if ( pin_fnc == TMS570_PIN_FNC_AUTO ) {
0086     pin_fnc = (pin_num & TMS570_PIN_FNC_MASK) >> TMS570_PIN_FNC_SHIFT;
0087   }
0088   tms570_bsp_pin_to_pinmmrx(&pinmmrx, &pin_shift, pin_num);
0089   *pinmmrx = (*pinmmrx & ~(0xff << pin_shift)) | (1 << (pin_fnc + pin_shift));
0090 }
0091 
0092 /**
0093  * @brief clear connection between pin and specified peripherals/function
0094  *
0095  * This function switches off given connection and leaves rest
0096  * of multiplexer setup intact.
0097  *
0098  * @param[in] pin_num  pin/ball identifier (index into pinmux array)
0099  * @param[in] pin_fnc  function number 0 .. 7, if value \c TMS570_PIN_FNC_AUTO
0100  *                     is specified then pin function is extracted from
0101  *                     pin_num argument
0102  * @retval Void
0103  */
0104 void
0105 tms570_bsp_pin_clear_function(int pin_num, int pin_fnc)
0106 {
0107   unsigned int pin_shift;
0108   volatile uint32_t *pinmmrx;
0109 
0110   if ( pin_fnc == TMS570_PIN_FNC_AUTO ) {
0111     pin_fnc = (pin_num & TMS570_PIN_FNC_MASK) >> TMS570_PIN_FNC_SHIFT;
0112   }
0113   tms570_bsp_pin_to_pinmmrx(&pinmmrx, &pin_shift, pin_num);
0114   *pinmmrx = *pinmmrx & ~(1 << (pin_fnc+pin_shift));
0115 }
0116 
0117 /**
0118  * @brief configure one pin according to its function specification
0119  *
0120  * The function setups multiplexer to interconnect pin with
0121  * specified function/peripheral. Predefined values for pins combined with
0122  * function are in a format TMS570_BALL_ \c column \c row \c function
0123  * (for example \c TMS570_BALL_W3_SCIRX).
0124  * If the function can be connected to more pins then specification
0125  * includes infomation which allows to disconnect alternative pin to peripheral
0126  * input connection or switch input multiplexer to right pin.
0127  *
0128  * @param[in] pin_num_and_fnc pin function descriptor is build by macro
0129  *               \c TMS570_PIN_AND_FNC which takes pin/pinmmr specification
0130  *               build by \c TMS570_BALL_WITH_MMR and function index in output
0131  *               multiplexer. If the peripheral can be connected to other input
0132  *               alternative then actual pin description and alternative to
0133  *               disconnected/reconnect are combined together by
0134  *               \c TMS570_PIN_WITH_IN_ALT macro. If clear of alternative
0135  *               connection is required then flag \c TMS570_PIN_CLEAR_RQ_MASK
0136  *               is ored to alternative description.
0137  *
0138  * @retval Void
0139  */
0140 void
0141 tms570_bsp_pin_config_one(uint32_t pin_num_and_fnc)
0142 {
0143   rtems_interrupt_level intlev;
0144 
0145   rtems_interrupt_disable(intlev);
0146   tms570_pin_config_prepare();
0147   tms570_pin_config_apply(pin_num_and_fnc);
0148   tms570_pin_config_complete();
0149   rtems_interrupt_enable(intlev);
0150 }
0151 
0152 /**
0153  * @brief configure block or whole pin multiplexer
0154  *
0155  * Function change multiplexer content. It is intended for initial
0156  * chip setup and does not use locking. If complete reconfiguration
0157  * is required at runtime then it is application responsibility
0158  * to protect and serialize change with peripherals drivers
0159  * and parallel calls
0160  *
0161  * @param[in] pinmmr_values pointer to array with required multiplexer setup
0162  * @param[in] reg_start starting register, this allows to configure non-consecutive
0163  *                      registers groups found on some MCU family members
0164  * @param[in] reg_count number of words in initialization array to set
0165  *                      to corresponding registers
0166  *
0167  * @retval Void
0168  */
0169 void
0170 tms570_bsp_pinmmr_config(const uint32_t *pinmmr_values, int reg_start, int reg_count)
0171 {
0172   volatile uint32_t *pinmmrx;
0173   const uint32_t *pval;
0174   int cnt;
0175 
0176   if ( reg_count <= 0)
0177     return;
0178 
0179   tms570_pin_config_prepare();
0180 
0181   pinmmrx = TMS570_PINMUX + reg_start;
0182   pval = pinmmr_values;
0183   cnt = reg_count;
0184 
0185   do {
0186     *pinmmrx = *pval;
0187     pinmmrx++;
0188     pval++;
0189   } while( --cnt );
0190 
0191   tms570_pin_config_complete();
0192 }
0193 
0194 void tms570_pin_config_prepare(void)
0195 {
0196   TMS570_IOMM.KICK_REG0 = 0x83E70B13U;
0197   TMS570_IOMM.KICK_REG1 = 0x95A4F1E0U;
0198 }
0199 
0200 static void
0201 tms570_pin_set_function(uint32_t config)
0202 {
0203   volatile uint32_t *pinmmrx;
0204   uint32_t pin_shift;
0205   uint32_t pin_fnc;
0206   uint32_t bit;
0207   uint32_t val;
0208 
0209   tms570_bsp_pin_to_pinmmrx(&pinmmrx, &pin_shift, config);
0210   pin_fnc = (config & TMS570_PIN_FNC_MASK) >> TMS570_PIN_FNC_SHIFT;
0211   bit = 1U << (pin_fnc + pin_shift);
0212   val = *pinmmrx;
0213   val &= ~(0xffU << pin_shift);
0214 
0215   if ((config & TMS570_PIN_CLEAR_RQ_MASK) == 0) {
0216     val |= bit;
0217   }
0218 
0219   *pinmmrx = val;
0220 }
0221 
0222 void tms570_pin_config_apply(uint32_t config)
0223 {
0224   uint32_t pin_in_alt;
0225   uint32_t pin_num_and_fnc;
0226 
0227   pin_in_alt = config & TMS570_PIN_IN_ALT_MASK;
0228   if (pin_in_alt != 0) {
0229     pin_in_alt >>= TMS570_PIN_IN_ALT_SHIFT;
0230     tms570_pin_set_function(pin_in_alt);
0231   }
0232 
0233   pin_num_and_fnc = config & TMS570_PIN_NUM_FNC_MASK;
0234   tms570_pin_set_function(pin_num_and_fnc);
0235 }
0236 
0237 void tms570_pin_config_array_apply(const uint32_t *config, size_t count)
0238 {
0239   size_t i;
0240 
0241   for (i = 0; i < count; ++i) {
0242     tms570_pin_config_apply(config[i]);
0243   }
0244 }
0245 
0246 void tms570_pin_config_complete(void)
0247 {
0248   TMS570_IOMM.KICK_REG0 = 0;
0249   TMS570_IOMM.KICK_REG1 = 0;
0250 }