@@ -625,6 +625,111 @@ static int of_parse_ppe_qm(struct ppe_device *ppe_dev,
return ret;
}
+static int of_parse_ppe_tdm(struct ppe_device *ppe_dev,
+ struct device_node *ppe_node)
+{
+ struct device_node *tdm_node;
+ u32 *cfg, reg_val;
+ int ret, cnt;
+
+ tdm_node = of_get_child_by_name(ppe_node, "tdm-config");
+ if (!tdm_node)
+ return dev_err_probe(ppe_dev->dev, -ENODEV,
+ "tdm-config is not defined\n");
+
+ cnt = of_property_count_u32_elems(tdm_node, "qcom,tdm-bm-config");
+ if (cnt < 0)
+ return dev_err_probe(ppe_dev->dev, -EINVAL,
+ "Fail to get qcom,tdm-bm-config\n");
+
+ cfg = kmalloc_array(cnt, sizeof(*cfg), GFP_KERNEL | __GFP_ZERO);
+ if (!cfg)
+ return -ENOMEM;
+
+ ret = of_property_read_u32_array(tdm_node, "qcom,tdm-bm-config", cfg, cnt);
+ if (ret) {
+ dev_err(ppe_dev->dev, "Fail to get qcom,tdm-bm-config\n");
+ goto parse_tdm_err;
+ }
+
+ /* Parse TDM BM configuration,
+ * the dts property:
+ * qcom,tdm-bm-config = <valid dir port second_valid second_port>;
+ *
+ * This config decides the number ticks available for physical port
+ * to utilize buffer for receiving and transmiting packet.
+ */
+ reg_val = FIELD_PREP(PPE_BM_TDM_CTRL_TDM_DEPTH, cnt / 5) |
+ FIELD_PREP(PPE_BM_TDM_CTRL_TDM_OFFSET, 0) |
+ FIELD_PREP(PPE_BM_TDM_CTRL_TDM_EN, 1);
+ ret = ppe_write(ppe_dev, PPE_BM_TDM_CTRL, reg_val);
+ if (ret)
+ return ret;
+
+ ret = 0;
+ while ((cnt - ret) / 5) {
+ reg_val = FIELD_PREP(PPE_BM_TDM_CFG_TBL_VALID, cfg[ret]) |
+ FIELD_PREP(PPE_BM_TDM_CFG_TBL_DIR, cfg[ret + 1]) |
+ FIELD_PREP(PPE_BM_TDM_CFG_TBL_PORT_NUM, cfg[ret + 2]) |
+ FIELD_PREP(PPE_BM_TDM_CFG_TBL_SECOND_PORT_VALID, cfg[ret + 3]) |
+ FIELD_PREP(PPE_BM_TDM_CFG_TBL_SECOND_PORT, cfg[ret + 4]);
+
+ ppe_write(ppe_dev,
+ PPE_BM_TDM_CFG_TBL + (ret / 5) * PPE_BM_TDM_CFG_TBL_INC,
+ reg_val);
+ ret += 5;
+ }
+
+ cnt = of_property_count_u32_elems(tdm_node, "qcom,tdm-port-scheduler-config");
+ if (cnt < 0) {
+ dev_err(ppe_dev->dev, "Fail to get qcom,tdm-port-scheduler-config\n");
+ goto parse_tdm_err;
+ }
+
+ cfg = krealloc_array(cfg, cnt, sizeof(*cfg), GFP_KERNEL | __GFP_ZERO);
+ if (!cfg) {
+ ret = -ENOMEM;
+ goto parse_tdm_err;
+ }
+
+ ret = of_property_read_u32_array(tdm_node, "qcom,tdm-port-scheduler-config",
+ cfg, cnt);
+ if (ret) {
+ dev_err(ppe_dev->dev, "Fail to get qcom,tdm-port-scheduler-config\n");
+ goto parse_tdm_err;
+ }
+
+ /* Parse TDM scheduler configuration,
+ * the dts property:
+ * qcom,tdm-port-scheduler-config = <ensch_bmp ensch_port desch_port
+ * desch_second_valid desch_second_port>;
+ *
+ * This config decides the ticks number available for packet enqueue
+ * and dequeue on the physical port.
+ */
+ reg_val = FIELD_PREP(PPE_PSCH_TDM_DEPTH_CFG_TDM_DEPTH, cnt / 5);
+ ppe_write(ppe_dev, PPE_PSCH_TDM_DEPTH_CFG, reg_val);
+
+ ret = 0;
+ while ((cnt - ret) / 5) {
+ reg_val = FIELD_PREP(PPE_PSCH_TDM_CFG_TBL_ENS_PORT_BITMAP, cfg[ret]) |
+ FIELD_PREP(PPE_PSCH_TDM_CFG_TBL_ENS_PORT, cfg[ret + 1]) |
+ FIELD_PREP(PPE_PSCH_TDM_CFG_TBL_DES_PORT, cfg[ret + 2]) |
+ FIELD_PREP(PPE_PSCH_TDM_CFG_TBL_DES_SECOND_PORT_EN, cfg[ret + 3]) |
+ FIELD_PREP(PPE_PSCH_TDM_CFG_TBL_DES_SECOND_PORT, cfg[ret + 4]);
+
+ ppe_write(ppe_dev,
+ PPE_PSCH_TDM_CFG_TBL + (ret / 5) * PPE_PSCH_TDM_CFG_TBL_INC,
+ reg_val);
+ ret += 5;
+ }
+
+ ret = 0;
+parse_tdm_err:
+ kfree(cfg);
+ return ret;
+};
+
static int of_parse_ppe_config(struct ppe_device *ppe_dev,
struct device_node *ppe_node)
{
@@ -634,7 +739,11 @@ static int of_parse_ppe_config(struct ppe_device *ppe_dev,
if (ret)
return ret;
- return of_parse_ppe_qm(ppe_dev, ppe_node);
+ ret = of_parse_ppe_qm(ppe_dev, ppe_node);
+ if (ret)
+ return ret;
+
+ return of_parse_ppe_tdm(ppe_dev, ppe_node);
}
static int qcom_ppe_probe(struct platform_device *pdev)
@@ -7,14 +7,44 @@
#ifndef __PPE_REGS_H__
#define __PPE_REGS_H__
+#define PPE_BM_TDM_CTRL 0xb000
+#define PPE_BM_TDM_CTRL_NUM 1
+#define PPE_BM_TDM_CTRL_INC 4
+#define PPE_BM_TDM_CTRL_TDM_DEPTH GENMASK(7, 0)
+#define PPE_BM_TDM_CTRL_TDM_OFFSET GENMASK(14, 8)
+#define PPE_BM_TDM_CTRL_TDM_EN BIT(31)
+
+#define PPE_BM_TDM_CFG_TBL 0xc000
+#define PPE_BM_TDM_CFG_TBL_NUM 128
+#define PPE_BM_TDM_CFG_TBL_INC 0x10
+#define PPE_BM_TDM_CFG_TBL_PORT_NUM GENMASK(3, 0)
+#define PPE_BM_TDM_CFG_TBL_DIR BIT(4)
+#define PPE_BM_TDM_CFG_TBL_VALID BIT(5)
+#define PPE_BM_TDM_CFG_TBL_SECOND_PORT_VALID BIT(6)
+#define PPE_BM_TDM_CFG_TBL_SECOND_PORT GENMASK(11, 8)
+
#define PPE_EG_BRIDGE_CONFIG 0x20044
#define PPE_EG_BRIDGE_CONFIG_QUEUE_CNT_EN BIT(2)
+#define PPE_PSCH_TDM_DEPTH_CFG 0x400000
+#define PPE_PSCH_TDM_DEPTH_CFG_NUM 1
+#define PPE_PSCH_TDM_DEPTH_CFG_INC 4
+#define PPE_PSCH_TDM_DEPTH_CFG_TDM_DEPTH GENMASK(7, 0)
+
#define PPE_DEQ_OPR_TBL 0x430000
#define PPE_DEQ_OPR_TBL_NUM 300
#define PPE_DEQ_OPR_TBL_INC 0x10
#define PPE_ENQ_OPR_TBL_DEQ_DISABLE BIT(0)
+#define PPE_PSCH_TDM_CFG_TBL 0x47a000
+#define PPE_PSCH_TDM_CFG_TBL_NUM 128
+#define PPE_PSCH_TDM_CFG_TBL_INC 0x10
+#define PPE_PSCH_TDM_CFG_TBL_DES_PORT GENMASK(3, 0)
+#define PPE_PSCH_TDM_CFG_TBL_ENS_PORT GENMASK(7, 4)
+#define PPE_PSCH_TDM_CFG_TBL_ENS_PORT_BITMAP GENMASK(15, 8)
+#define PPE_PSCH_TDM_CFG_TBL_DES_SECOND_PORT_EN BIT(16)
+#define PPE_PSCH_TDM_CFG_TBL_DES_SECOND_PORT GENMASK(20, 17)
+
#define PPE_BM_PORT_FC_MODE 0x600100
#define PPE_BM_PORT_FC_MODE_NUM 15
#define PPE_BM_PORT_FC_MODE_INC 4
TDM(Time Division Multiplex) config controls the performance of the PPE ports, which assigns the clock tickets for the PPE port to receive and transmit packet. Signed-off-by: Luo Jie <quic_luoj@quicinc.com> --- drivers/net/ethernet/qualcomm/ppe/ppe.c | 111 ++++++++++++++++++- drivers/net/ethernet/qualcomm/ppe/ppe_regs.h | 30 +++++ 2 files changed, 140 insertions(+), 1 deletion(-)