123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- * arch/powerpc/sysdev/qe_lib/ucc.c
- *
- * QE UCC API Set - UCC specific routines implementations.
- *
- * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.
- *
- * Authors: Shlomi Gridish <[email protected]>
- * Li Yang <[email protected]>
- */
- #include <linux/kernel.h>
- #include <linux/errno.h>
- #include <linux/stddef.h>
- #include <linux/spinlock.h>
- #include <linux/export.h>
- #include <asm/io.h>
- #include <soc/fsl/qe/immap_qe.h>
- #include <soc/fsl/qe/qe.h>
- #include <soc/fsl/qe/ucc.h>
- #define UCC_TDM_NUM 8
- #define RX_SYNC_SHIFT_BASE 30
- #define TX_SYNC_SHIFT_BASE 14
- #define RX_CLK_SHIFT_BASE 28
- #define TX_CLK_SHIFT_BASE 12
- int ucc_set_qe_mux_mii_mng(unsigned int ucc_num)
- {
- unsigned long flags;
- if (ucc_num > UCC_MAX_NUM - 1)
- return -EINVAL;
- spin_lock_irqsave(&cmxgcr_lock, flags);
- qe_clrsetbits_be32(&qe_immr->qmx.cmxgcr, QE_CMXGCR_MII_ENET_MNG,
- ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT);
- spin_unlock_irqrestore(&cmxgcr_lock, flags);
- return 0;
- }
- EXPORT_SYMBOL(ucc_set_qe_mux_mii_mng);
- /* Configure the UCC to either Slow or Fast.
- *
- * A given UCC can be figured to support either "slow" devices (e.g. UART)
- * or "fast" devices (e.g. Ethernet).
- *
- * 'ucc_num' is the UCC number, from 0 - 7.
- *
- * This function also sets the UCC_GUEMR_SET_RESERVED3 bit because that bit
- * must always be set to 1.
- */
- int ucc_set_type(unsigned int ucc_num, enum ucc_speed_type speed)
- {
- u8 __iomem *guemr;
- /* The GUEMR register is at the same location for both slow and fast
- devices, so we just use uccX.slow.guemr. */
- switch (ucc_num) {
- case 0: guemr = &qe_immr->ucc1.slow.guemr;
- break;
- case 1: guemr = &qe_immr->ucc2.slow.guemr;
- break;
- case 2: guemr = &qe_immr->ucc3.slow.guemr;
- break;
- case 3: guemr = &qe_immr->ucc4.slow.guemr;
- break;
- case 4: guemr = &qe_immr->ucc5.slow.guemr;
- break;
- case 5: guemr = &qe_immr->ucc6.slow.guemr;
- break;
- case 6: guemr = &qe_immr->ucc7.slow.guemr;
- break;
- case 7: guemr = &qe_immr->ucc8.slow.guemr;
- break;
- default:
- return -EINVAL;
- }
- qe_clrsetbits_8(guemr, UCC_GUEMR_MODE_MASK,
- UCC_GUEMR_SET_RESERVED3 | speed);
- return 0;
- }
- static void get_cmxucr_reg(unsigned int ucc_num, __be32 __iomem **cmxucr,
- unsigned int *reg_num, unsigned int *shift)
- {
- unsigned int cmx = ((ucc_num & 1) << 1) + (ucc_num > 3);
- *reg_num = cmx + 1;
- *cmxucr = &qe_immr->qmx.cmxucr[cmx];
- *shift = 16 - 8 * (ucc_num & 2);
- }
- int ucc_mux_set_grant_tsa_bkpt(unsigned int ucc_num, int set, u32 mask)
- {
- __be32 __iomem *cmxucr;
- unsigned int reg_num;
- unsigned int shift;
- /* check if the UCC number is in range. */
- if (ucc_num > UCC_MAX_NUM - 1)
- return -EINVAL;
- get_cmxucr_reg(ucc_num, &cmxucr, ®_num, &shift);
- if (set)
- qe_setbits_be32(cmxucr, mask << shift);
- else
- qe_clrbits_be32(cmxucr, mask << shift);
- return 0;
- }
- int ucc_set_qe_mux_rxtx(unsigned int ucc_num, enum qe_clock clock,
- enum comm_dir mode)
- {
- __be32 __iomem *cmxucr;
- unsigned int reg_num;
- unsigned int shift;
- u32 clock_bits = 0;
- /* check if the UCC number is in range. */
- if (ucc_num > UCC_MAX_NUM - 1)
- return -EINVAL;
- /* The communications direction must be RX or TX */
- if (!((mode == COMM_DIR_RX) || (mode == COMM_DIR_TX)))
- return -EINVAL;
- get_cmxucr_reg(ucc_num, &cmxucr, ®_num, &shift);
- switch (reg_num) {
- case 1:
- switch (clock) {
- case QE_BRG1: clock_bits = 1; break;
- case QE_BRG2: clock_bits = 2; break;
- case QE_BRG7: clock_bits = 3; break;
- case QE_BRG8: clock_bits = 4; break;
- case QE_CLK9: clock_bits = 5; break;
- case QE_CLK10: clock_bits = 6; break;
- case QE_CLK11: clock_bits = 7; break;
- case QE_CLK12: clock_bits = 8; break;
- case QE_CLK15: clock_bits = 9; break;
- case QE_CLK16: clock_bits = 10; break;
- default: break;
- }
- break;
- case 2:
- switch (clock) {
- case QE_BRG5: clock_bits = 1; break;
- case QE_BRG6: clock_bits = 2; break;
- case QE_BRG7: clock_bits = 3; break;
- case QE_BRG8: clock_bits = 4; break;
- case QE_CLK13: clock_bits = 5; break;
- case QE_CLK14: clock_bits = 6; break;
- case QE_CLK19: clock_bits = 7; break;
- case QE_CLK20: clock_bits = 8; break;
- case QE_CLK15: clock_bits = 9; break;
- case QE_CLK16: clock_bits = 10; break;
- default: break;
- }
- break;
- case 3:
- switch (clock) {
- case QE_BRG9: clock_bits = 1; break;
- case QE_BRG10: clock_bits = 2; break;
- case QE_BRG15: clock_bits = 3; break;
- case QE_BRG16: clock_bits = 4; break;
- case QE_CLK3: clock_bits = 5; break;
- case QE_CLK4: clock_bits = 6; break;
- case QE_CLK17: clock_bits = 7; break;
- case QE_CLK18: clock_bits = 8; break;
- case QE_CLK7: clock_bits = 9; break;
- case QE_CLK8: clock_bits = 10; break;
- case QE_CLK16: clock_bits = 11; break;
- default: break;
- }
- break;
- case 4:
- switch (clock) {
- case QE_BRG13: clock_bits = 1; break;
- case QE_BRG14: clock_bits = 2; break;
- case QE_BRG15: clock_bits = 3; break;
- case QE_BRG16: clock_bits = 4; break;
- case QE_CLK5: clock_bits = 5; break;
- case QE_CLK6: clock_bits = 6; break;
- case QE_CLK21: clock_bits = 7; break;
- case QE_CLK22: clock_bits = 8; break;
- case QE_CLK7: clock_bits = 9; break;
- case QE_CLK8: clock_bits = 10; break;
- case QE_CLK16: clock_bits = 11; break;
- default: break;
- }
- break;
- default: break;
- }
- /* Check for invalid combination of clock and UCC number */
- if (!clock_bits)
- return -ENOENT;
- if (mode == COMM_DIR_RX)
- shift += 4;
- qe_clrsetbits_be32(cmxucr, QE_CMXUCR_TX_CLK_SRC_MASK << shift,
- clock_bits << shift);
- return 0;
- }
- static int ucc_get_tdm_common_clk(u32 tdm_num, enum qe_clock clock)
- {
- int clock_bits = -EINVAL;
- /*
- * for TDM[0, 1, 2, 3], TX and RX use common
- * clock source BRG3,4 and CLK1,2
- * for TDM[4, 5, 6, 7], TX and RX use common
- * clock source BRG12,13 and CLK23,24
- */
- switch (tdm_num) {
- case 0:
- case 1:
- case 2:
- case 3:
- switch (clock) {
- case QE_BRG3:
- clock_bits = 1;
- break;
- case QE_BRG4:
- clock_bits = 2;
- break;
- case QE_CLK1:
- clock_bits = 4;
- break;
- case QE_CLK2:
- clock_bits = 5;
- break;
- default:
- break;
- }
- break;
- case 4:
- case 5:
- case 6:
- case 7:
- switch (clock) {
- case QE_BRG12:
- clock_bits = 1;
- break;
- case QE_BRG13:
- clock_bits = 2;
- break;
- case QE_CLK23:
- clock_bits = 4;
- break;
- case QE_CLK24:
- clock_bits = 5;
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
- return clock_bits;
- }
- static int ucc_get_tdm_rx_clk(u32 tdm_num, enum qe_clock clock)
- {
- int clock_bits = -EINVAL;
- switch (tdm_num) {
- case 0:
- switch (clock) {
- case QE_CLK3:
- clock_bits = 6;
- break;
- case QE_CLK8:
- clock_bits = 7;
- break;
- default:
- break;
- }
- break;
- case 1:
- switch (clock) {
- case QE_CLK5:
- clock_bits = 6;
- break;
- case QE_CLK10:
- clock_bits = 7;
- break;
- default:
- break;
- }
- break;
- case 2:
- switch (clock) {
- case QE_CLK7:
- clock_bits = 6;
- break;
- case QE_CLK12:
- clock_bits = 7;
- break;
- default:
- break;
- }
- break;
- case 3:
- switch (clock) {
- case QE_CLK9:
- clock_bits = 6;
- break;
- case QE_CLK14:
- clock_bits = 7;
- break;
- default:
- break;
- }
- break;
- case 4:
- switch (clock) {
- case QE_CLK11:
- clock_bits = 6;
- break;
- case QE_CLK16:
- clock_bits = 7;
- break;
- default:
- break;
- }
- break;
- case 5:
- switch (clock) {
- case QE_CLK13:
- clock_bits = 6;
- break;
- case QE_CLK18:
- clock_bits = 7;
- break;
- default:
- break;
- }
- break;
- case 6:
- switch (clock) {
- case QE_CLK15:
- clock_bits = 6;
- break;
- case QE_CLK20:
- clock_bits = 7;
- break;
- default:
- break;
- }
- break;
- case 7:
- switch (clock) {
- case QE_CLK17:
- clock_bits = 6;
- break;
- case QE_CLK22:
- clock_bits = 7;
- break;
- default:
- break;
- }
- break;
- }
- return clock_bits;
- }
- static int ucc_get_tdm_tx_clk(u32 tdm_num, enum qe_clock clock)
- {
- int clock_bits = -EINVAL;
- switch (tdm_num) {
- case 0:
- switch (clock) {
- case QE_CLK4:
- clock_bits = 6;
- break;
- case QE_CLK9:
- clock_bits = 7;
- break;
- default:
- break;
- }
- break;
- case 1:
- switch (clock) {
- case QE_CLK6:
- clock_bits = 6;
- break;
- case QE_CLK11:
- clock_bits = 7;
- break;
- default:
- break;
- }
- break;
- case 2:
- switch (clock) {
- case QE_CLK8:
- clock_bits = 6;
- break;
- case QE_CLK13:
- clock_bits = 7;
- break;
- default:
- break;
- }
- break;
- case 3:
- switch (clock) {
- case QE_CLK10:
- clock_bits = 6;
- break;
- case QE_CLK15:
- clock_bits = 7;
- break;
- default:
- break;
- }
- break;
- case 4:
- switch (clock) {
- case QE_CLK12:
- clock_bits = 6;
- break;
- case QE_CLK17:
- clock_bits = 7;
- break;
- default:
- break;
- }
- break;
- case 5:
- switch (clock) {
- case QE_CLK14:
- clock_bits = 6;
- break;
- case QE_CLK19:
- clock_bits = 7;
- break;
- default:
- break;
- }
- break;
- case 6:
- switch (clock) {
- case QE_CLK16:
- clock_bits = 6;
- break;
- case QE_CLK21:
- clock_bits = 7;
- break;
- default:
- break;
- }
- break;
- case 7:
- switch (clock) {
- case QE_CLK18:
- clock_bits = 6;
- break;
- case QE_CLK3:
- clock_bits = 7;
- break;
- default:
- break;
- }
- break;
- }
- return clock_bits;
- }
- /* tdm_num: TDM A-H port num is 0-7 */
- static int ucc_get_tdm_rxtx_clk(enum comm_dir mode, u32 tdm_num,
- enum qe_clock clock)
- {
- int clock_bits;
- clock_bits = ucc_get_tdm_common_clk(tdm_num, clock);
- if (clock_bits > 0)
- return clock_bits;
- if (mode == COMM_DIR_RX)
- clock_bits = ucc_get_tdm_rx_clk(tdm_num, clock);
- if (mode == COMM_DIR_TX)
- clock_bits = ucc_get_tdm_tx_clk(tdm_num, clock);
- return clock_bits;
- }
- static u32 ucc_get_tdm_clk_shift(enum comm_dir mode, u32 tdm_num)
- {
- u32 shift;
- shift = (mode == COMM_DIR_RX) ? RX_CLK_SHIFT_BASE : TX_CLK_SHIFT_BASE;
- if (tdm_num < 4)
- shift -= tdm_num * 4;
- else
- shift -= (tdm_num - 4) * 4;
- return shift;
- }
- int ucc_set_tdm_rxtx_clk(u32 tdm_num, enum qe_clock clock,
- enum comm_dir mode)
- {
- int clock_bits;
- u32 shift;
- struct qe_mux __iomem *qe_mux_reg;
- __be32 __iomem *cmxs1cr;
- qe_mux_reg = &qe_immr->qmx;
- if (tdm_num > 7)
- return -EINVAL;
- /* The communications direction must be RX or TX */
- if (mode != COMM_DIR_RX && mode != COMM_DIR_TX)
- return -EINVAL;
- clock_bits = ucc_get_tdm_rxtx_clk(mode, tdm_num, clock);
- if (clock_bits < 0)
- return -EINVAL;
- shift = ucc_get_tdm_clk_shift(mode, tdm_num);
- cmxs1cr = (tdm_num < 4) ? &qe_mux_reg->cmxsi1cr_l :
- &qe_mux_reg->cmxsi1cr_h;
- qe_clrsetbits_be32(cmxs1cr, QE_CMXUCR_TX_CLK_SRC_MASK << shift,
- clock_bits << shift);
- return 0;
- }
- static int ucc_get_tdm_sync_source(u32 tdm_num, enum qe_clock clock,
- enum comm_dir mode)
- {
- int source = -EINVAL;
- if (mode == COMM_DIR_RX && clock == QE_RSYNC_PIN) {
- source = 0;
- return source;
- }
- if (mode == COMM_DIR_TX && clock == QE_TSYNC_PIN) {
- source = 0;
- return source;
- }
- switch (tdm_num) {
- case 0:
- case 1:
- switch (clock) {
- case QE_BRG9:
- source = 1;
- break;
- case QE_BRG10:
- source = 2;
- break;
- default:
- break;
- }
- break;
- case 2:
- case 3:
- switch (clock) {
- case QE_BRG9:
- source = 1;
- break;
- case QE_BRG11:
- source = 2;
- break;
- default:
- break;
- }
- break;
- case 4:
- case 5:
- switch (clock) {
- case QE_BRG13:
- source = 1;
- break;
- case QE_BRG14:
- source = 2;
- break;
- default:
- break;
- }
- break;
- case 6:
- case 7:
- switch (clock) {
- case QE_BRG13:
- source = 1;
- break;
- case QE_BRG15:
- source = 2;
- break;
- default:
- break;
- }
- break;
- }
- return source;
- }
- static u32 ucc_get_tdm_sync_shift(enum comm_dir mode, u32 tdm_num)
- {
- u32 shift;
- shift = (mode == COMM_DIR_RX) ? RX_SYNC_SHIFT_BASE : TX_SYNC_SHIFT_BASE;
- shift -= tdm_num * 2;
- return shift;
- }
- int ucc_set_tdm_rxtx_sync(u32 tdm_num, enum qe_clock clock,
- enum comm_dir mode)
- {
- int source;
- u32 shift;
- struct qe_mux __iomem *qe_mux_reg;
- qe_mux_reg = &qe_immr->qmx;
- if (tdm_num >= UCC_TDM_NUM)
- return -EINVAL;
- /* The communications direction must be RX or TX */
- if (mode != COMM_DIR_RX && mode != COMM_DIR_TX)
- return -EINVAL;
- source = ucc_get_tdm_sync_source(tdm_num, clock, mode);
- if (source < 0)
- return -EINVAL;
- shift = ucc_get_tdm_sync_shift(mode, tdm_num);
- qe_clrsetbits_be32(&qe_mux_reg->cmxsi1syr,
- QE_CMXUCR_TX_CLK_SRC_MASK << shift,
- source << shift);
- return 0;
- }
|