struct tsa { struct device *dev; void __iomem *si_regs; void __iomem *si_ram;
resource_size_t si_ram_sz;
spinlock_t lock; /* Lock for read/modify/write sequence */ enum tsa_version version; int tdms; /* TSA_TDMx ORed */ #if IS_ENABLED(CONFIG_QUICC_ENGINE) struct tsa_tdm tdm[4]; /* TDMa, TDMb, TDMc and TDMd */ #else struct tsa_tdm tdm[2]; /* TDMa and TDMb */ #endif /* Same number of serials for CPM1 and QE: * CPM1: NU, 3 SCCs and 2 SMCs * QE: NU and 5 UCCs
*/ struct tsa_serial { unsignedint id; struct tsa_serial_info info;
} serials[6];
};
staticinlinestruct tsa *tsa_serial_get_tsa(struct tsa_serial *tsa_serial)
{ /* The serials table is indexed by the serial id */ return container_of(tsa_serial, struct tsa, serials[tsa_serial->id]);
}
switch (tsa_serial->id) { case FSL_QE_TSA_UCC1: return 0; case FSL_QE_TSA_UCC2: return 1; case FSL_QE_TSA_UCC3: return 2; case FSL_QE_TSA_UCC4: return 3; case FSL_QE_TSA_UCC5: return 4; default: break;
}
dev_err(tsa->dev, "Unsupported serial id %u\n", tsa_serial->id); return -EINVAL;
}
int tsa_serial_get_num(struct tsa_serial *tsa_serial)
{ struct tsa *tsa = tsa_serial_get_tsa(tsa_serial);
/* * There is no need to get the serial num out of the TSA driver in the * CPM case. * Further more, in CPM, we can have 2 types of serial SCCs and FCCs. * What kind of numbering to use that can be global to both SCCs and * FCCs ?
*/ return tsa_is_qe(tsa) ? tsa_qe_serial_get_num(tsa_serial) : -EOPNOTSUPP;
}
EXPORT_SYMBOL(tsa_serial_get_num);
switch (tsa_serial->id) { case FSL_CPM_TSA_SCC2:
clear = TSA_CPM1_SICR_SCC2(TSA_CPM1_SICR_SCC_MASK);
set = TSA_CPM1_SICR_SCC2(TSA_CPM1_SICR_SCC_SCX_TSA); break; case FSL_CPM_TSA_SCC3:
clear = TSA_CPM1_SICR_SCC3(TSA_CPM1_SICR_SCC_MASK);
set = TSA_CPM1_SICR_SCC3(TSA_CPM1_SICR_SCC_SCX_TSA); break; case FSL_CPM_TSA_SCC4:
clear = TSA_CPM1_SICR_SCC4(TSA_CPM1_SICR_SCC_MASK);
set = TSA_CPM1_SICR_SCC4(TSA_CPM1_SICR_SCC_SCX_TSA); break; default:
dev_err(tsa->dev, "Unsupported serial id %u\n", tsa_serial->id); return -EINVAL;
}
/* * One half of the SI RAM used for Tx, the other one for Rx. * In each half, 1/4 of the area is assigned to each TDM.
*/ if (is_rx) { /* Rx: Second half of si_ram */
area->entries_start = tsa->si_ram + half + (eighth * tdm_id);
area->entries_next = area->entries_start + eighth;
area->last_entry = NULL;
} else { /* Tx: First half of si_ram */
area->entries_start = tsa->si_ram + (eighth * tdm_id);
area->entries_next = area->entries_start + eighth;
area->last_entry = NULL;
}
}
len = of_property_count_u32_elems(tdm_np, route_name); if (len < 0) {
dev_err(tsa->dev, "%pOF: failed to read %s\n", tdm_np, route_name); return len;
} if (len % 2 != 0) {
dev_err(tsa->dev, "%pOF: wrong %s format\n", tdm_np, route_name); return -EINVAL;
}
tsa_init_entries_area(tsa, &area, tdms, tdm_id, is_rx);
ts = 0; for (i = 0; i < len; i += 2) {
of_property_read_u32_index(tdm_np, route_name, i, &count);
of_property_read_u32_index(tdm_np, route_name, i + 1, &serial_id);
if (serial_id >= ARRAY_SIZE(tsa->serials)) {
dev_err(tsa->dev, "%pOF: invalid serial id (%u)\n",
tdm_np, serial_id); return -EINVAL;
}
serial_name = tsa_serial_id2name(tsa, serial_id); if (!serial_name) {
dev_err(tsa->dev, "%pOF: unsupported serial id (%u)\n",
tdm_np, serial_id); return -EINVAL;
}
val = 0;
ret = of_property_read_u32(tdm_np, "fsl,rx-frame-sync-delay-bits",
&val); if (ret && ret != -EINVAL) {
dev_err(tsa->dev, "%pOF: failed to read fsl,rx-frame-sync-delay-bits\n",
tdm_np); return ret;
} if (val > 3) {
dev_err(tsa->dev, "%pOF: Invalid fsl,rx-frame-sync-delay-bits (%u)\n",
tdm_np, val); return -EINVAL;
}
tdm->simode_tdm |= TSA_SIMODE_TDM_RFSD(val);
val = 0;
ret = of_property_read_u32(tdm_np, "fsl,tx-frame-sync-delay-bits",
&val); if (ret && ret != -EINVAL) {
dev_err(tsa->dev, "%pOF: failed to read fsl,tx-frame-sync-delay-bits\n",
tdm_np); return ret;
} if (val > 3) {
dev_err(tsa->dev, "%pOF: Invalid fsl,tx-frame-sync-delay-bits (%u)\n",
tdm_np, val); return -EINVAL;
}
tdm->simode_tdm |= TSA_SIMODE_TDM_TFSD(val);
if (of_property_read_bool(tdm_np, "fsl,common-rxtx-pins"))
tdm->simode_tdm |= TSA_SIMODE_TDM_CRT;
if (of_property_read_bool(tdm_np, "fsl,clock-falling-edge"))
tdm->simode_tdm |= TSA_SIMODE_TDM_CE;
if (of_property_read_bool(tdm_np, "fsl,fsync-rising-edge"))
tdm->simode_tdm |= TSA_SIMODE_TDM_FE;
if (tsa_is_qe(tsa) &&
of_property_read_bool(tdm_np, "fsl,fsync-active-low"))
tdm->simode_tdm |= TSA_QE_SIMODE_TDM_SL;
if (of_property_read_bool(tdm_np, "fsl,double-speed-clock"))
tdm->simode_tdm |= TSA_SIMODE_TDM_DSC;
clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "rsync" : "l1rsync"); if (IS_ERR(clk)) {
ret = PTR_ERR(clk); goto err;
}
ret = clk_prepare_enable(clk); if (ret) {
clk_put(clk); goto err;
}
tdm->l1rsync_clk = clk;
clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "rclk" : "l1rclk"); if (IS_ERR(clk)) {
ret = PTR_ERR(clk); goto err;
}
ret = clk_prepare_enable(clk); if (ret) {
clk_put(clk); goto err;
}
tdm->l1rclk_clk = clk;
if (!(tdm->simode_tdm & TSA_SIMODE_TDM_CRT)) {
clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "tsync" : "l1tsync"); if (IS_ERR(clk)) {
ret = PTR_ERR(clk); goto err;
}
ret = clk_prepare_enable(clk); if (ret) {
clk_put(clk); goto err;
}
tdm->l1tsync_clk = clk;
clk = of_clk_get_by_name(tdm_np, tsa_is_qe(tsa) ? "tclk" : "l1tclk"); if (IS_ERR(clk)) {
ret = PTR_ERR(clk); goto err;
}
ret = clk_prepare_enable(clk); if (ret) {
clk_put(clk); goto err;
}
tdm->l1tclk_clk = clk;
}
if (tsa_is_qe(tsa)) { /* * The starting address for TSA table must be set. * 512 entries for Tx and 512 entries for Rx are * available for 4 TDMs. * We assign entries equally -> 128 Rx/Tx entries per * TDM. In other words, 4 blocks of 32 entries per TDM.
*/
tdm->simode_tdm |= TSA_QE_SIMODE_TDM_SAD(4 * tdm_id);
}
ret = tsa_of_parse_tdm_rx_route(tsa, tdm_np, tsa->tdms, tdm_id); if (ret) goto err;
ret = tsa_of_parse_tdm_tx_route(tsa, tdm_np, tsa->tdms, tdm_id); if (ret) goto err;
tdm->is_enable = true;
} return 0;
err: for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++) { if (tsa->tdm[i].l1rsync_clk) {
clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
clk_put(tsa->tdm[i].l1rsync_clk);
} if (tsa->tdm[i].l1rclk_clk) {
clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
clk_put(tsa->tdm[i].l1rclk_clk);
} if (tsa->tdm[i].l1tsync_clk) {
clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
clk_put(tsa->tdm[i].l1rsync_clk);
} if (tsa->tdm[i].l1tclk_clk) {
clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
clk_put(tsa->tdm[i].l1rclk_clk);
}
} return ret;
}
/* Fill all entries as the last one */ if (tsa_is_qe(tsa)) { for (i = 0; i < tsa->si_ram_sz; i += 2)
tsa_write16(tsa->si_ram + i, TSA_QE_SIRAM_ENTRY_LAST);
} else { for (i = 0; i < tsa->si_ram_sz; i += 4)
tsa_write32(tsa->si_ram + i, TSA_CPM1_SIRAM_ENTRY_LAST);
}
}
/* Set SIMODE */
val = 0; if (tsa->tdm[0].is_enable)
val |= TSA_CPM1_SIMODE_TDMA(tsa->tdm[0].simode_tdm); if (tsa->tdm[1].is_enable)
val |= TSA_CPM1_SIMODE_TDMB(tsa->tdm[1].simode_tdm);
for (i = 0; i < ARRAY_SIZE(tsa->tdm); i++) { if (tsa->tdm[i].l1rsync_clk) {
clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
clk_put(tsa->tdm[i].l1rsync_clk);
} if (tsa->tdm[i].l1rclk_clk) {
clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
clk_put(tsa->tdm[i].l1rclk_clk);
} if (tsa->tdm[i].l1tsync_clk) {
clk_disable_unprepare(tsa->tdm[i].l1rsync_clk);
clk_put(tsa->tdm[i].l1rsync_clk);
} if (tsa->tdm[i].l1tclk_clk) {
clk_disable_unprepare(tsa->tdm[i].l1rclk_clk);
clk_put(tsa->tdm[i].l1rclk_clk);
}
}
}
ret = of_parse_phandle_with_fixed_args(np, phandle_name, 1, 0, &out_args); if (ret < 0) return ERR_PTR(ret);
if (!of_match_node(tsa_driver.driver.of_match_table, out_args.np)) {
of_node_put(out_args.np); return ERR_PTR(-EINVAL);
}
pdev = of_find_device_by_node(out_args.np);
of_node_put(out_args.np); if (!pdev) return ERR_PTR(-ENODEV);
tsa = platform_get_drvdata(pdev); if (!tsa) {
platform_device_put(pdev); return ERR_PTR(-EPROBE_DEFER);
}
if (out_args.args_count != 1) {
platform_device_put(pdev); return ERR_PTR(-EINVAL);
}
if (out_args.args[0] >= ARRAY_SIZE(tsa->serials)) {
platform_device_put(pdev); return ERR_PTR(-EINVAL);
}
tsa_serial = &tsa->serials[out_args.args[0]];
/* * Be sure that the serial id matches the phandle arg. * The tsa_serials table is indexed by serial ids. The serial id is set * during the probe() call and needs to be coherent.
*/ if (WARN_ON(tsa_serial->id != out_args.args[0])) {
platform_device_put(pdev); return ERR_PTR(-EINVAL);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.