1 /* 10G controller driver for Samsung SoCs
2  *
3  * Copyright (C) 2013 Samsung Electronics Co., Ltd.
4  *		http://www.samsung.com
5  *
6  * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12 
13 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14 
15 #include <linux/io.h>
16 #include <linux/errno.h>
17 #include <linux/export.h>
18 #include <linux/jiffies.h>
19 
20 #include "sxgbe_mtl.h"
21 #include "sxgbe_reg.h"
22 
23 static void sxgbe_mtl_init(void __iomem *ioaddr, unsigned int etsalg,
24 			   unsigned int raa)
25 {
26 	u32 reg_val;
27 
28 	reg_val = readl(ioaddr + SXGBE_MTL_OP_MODE_REG);
29 	reg_val &= ETS_RST;
30 
31 	/* ETS Algorith */
32 	switch (etsalg & SXGBE_MTL_OPMODE_ESTMASK) {
33 	case ETS_WRR:
34 		reg_val &= ETS_WRR;
35 		break;
36 	case ETS_WFQ:
37 		reg_val |= ETS_WFQ;
38 		break;
39 	case ETS_DWRR:
40 		reg_val |= ETS_DWRR;
41 		break;
42 	}
43 	writel(reg_val, ioaddr + SXGBE_MTL_OP_MODE_REG);
44 
45 	switch (raa & SXGBE_MTL_OPMODE_RAAMASK) {
46 	case RAA_SP:
47 		reg_val &= RAA_SP;
48 		break;
49 	case RAA_WSP:
50 		reg_val |= RAA_WSP;
51 		break;
52 	}
53 	writel(reg_val, ioaddr + SXGBE_MTL_OP_MODE_REG);
54 }
55 
56 /* For Dynamic DMA channel mapping for Rx queue */
57 static void sxgbe_mtl_dma_dm_rxqueue(void __iomem *ioaddr)
58 {
59 	writel(RX_QUEUE_DYNAMIC, ioaddr + SXGBE_MTL_RXQ_DMAMAP0_REG);
60 	writel(RX_QUEUE_DYNAMIC, ioaddr + SXGBE_MTL_RXQ_DMAMAP1_REG);
61 	writel(RX_QUEUE_DYNAMIC, ioaddr + SXGBE_MTL_RXQ_DMAMAP2_REG);
62 }
63 
64 static void sxgbe_mtl_set_txfifosize(void __iomem *ioaddr, int queue_num,
65 				     int queue_fifo)
66 {
67 	u32 fifo_bits, reg_val;
68 
69 	/* 0 means 256 bytes */
70 	fifo_bits = (queue_fifo / SXGBE_MTL_TX_FIFO_DIV) - 1;
71 	reg_val = readl(ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
72 	reg_val |= (fifo_bits << SXGBE_MTL_FIFO_LSHIFT);
73 	writel(reg_val, ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
74 }
75 
76 static void sxgbe_mtl_set_rxfifosize(void __iomem *ioaddr, int queue_num,
77 				     int queue_fifo)
78 {
79 	u32 fifo_bits, reg_val;
80 
81 	/* 0 means 256 bytes */
82 	fifo_bits = (queue_fifo / SXGBE_MTL_RX_FIFO_DIV)-1;
83 	reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
84 	reg_val |= (fifo_bits << SXGBE_MTL_FIFO_LSHIFT);
85 	writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
86 }
87 
88 static void sxgbe_mtl_enable_txqueue(void __iomem *ioaddr, int queue_num)
89 {
90 	u32 reg_val;
91 
92 	reg_val = readl(ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
93 	reg_val |= SXGBE_MTL_ENABLE_QUEUE;
94 	writel(reg_val, ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
95 }
96 
97 static void sxgbe_mtl_disable_txqueue(void __iomem *ioaddr, int queue_num)
98 {
99 	u32 reg_val;
100 
101 	reg_val = readl(ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
102 	reg_val &= ~SXGBE_MTL_ENABLE_QUEUE;
103 	writel(reg_val, ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
104 }
105 
106 static void sxgbe_mtl_fc_active(void __iomem *ioaddr, int queue_num,
107 				int threshold)
108 {
109 	u32 reg_val;
110 
111 	reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
112 	reg_val &= ~(SXGBE_MTL_FCMASK << RX_FC_ACTIVE);
113 	reg_val |= (threshold << RX_FC_ACTIVE);
114 
115 	writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
116 }
117 
118 static void sxgbe_mtl_fc_enable(void __iomem *ioaddr, int queue_num)
119 {
120 	u32 reg_val;
121 
122 	reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
123 	reg_val |= SXGBE_MTL_ENABLE_FC;
124 	writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
125 }
126 
127 static void sxgbe_mtl_fc_deactive(void __iomem *ioaddr, int queue_num,
128 				  int threshold)
129 {
130 	u32 reg_val;
131 
132 	reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
133 	reg_val &= ~(SXGBE_MTL_FCMASK << RX_FC_DEACTIVE);
134 	reg_val |= (threshold << RX_FC_DEACTIVE);
135 
136 	writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
137 }
138 
139 static void sxgbe_mtl_fep_enable(void __iomem *ioaddr, int queue_num)
140 {
141 	u32 reg_val;
142 
143 	reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
144 	reg_val |= SXGBE_MTL_RXQ_OP_FEP;
145 
146 	writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
147 }
148 
149 static void sxgbe_mtl_fep_disable(void __iomem *ioaddr, int queue_num)
150 {
151 	u32 reg_val;
152 
153 	reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
154 	reg_val &= ~(SXGBE_MTL_RXQ_OP_FEP);
155 
156 	writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
157 }
158 
159 static void sxgbe_mtl_fup_enable(void __iomem *ioaddr, int queue_num)
160 {
161 	u32 reg_val;
162 
163 	reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
164 	reg_val |= SXGBE_MTL_RXQ_OP_FUP;
165 
166 	writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
167 }
168 
169 static void sxgbe_mtl_fup_disable(void __iomem *ioaddr, int queue_num)
170 {
171 	u32 reg_val;
172 
173 	reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
174 	reg_val &= ~(SXGBE_MTL_RXQ_OP_FUP);
175 
176 	writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
177 }
178 
179 
180 static void sxgbe_set_tx_mtl_mode(void __iomem *ioaddr, int queue_num,
181 				  int tx_mode)
182 {
183 	u32 reg_val;
184 
185 	reg_val = readl(ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
186 	/* TX specific MTL mode settings */
187 	if (tx_mode == SXGBE_MTL_SFMODE) {
188 		reg_val |= SXGBE_MTL_SFMODE;
189 	} else {
190 		/* set the TTC values */
191 		if (tx_mode <= 64)
192 			reg_val |= MTL_CONTROL_TTC_64;
193 		else if (tx_mode <= 96)
194 			reg_val |= MTL_CONTROL_TTC_96;
195 		else if (tx_mode <= 128)
196 			reg_val |= MTL_CONTROL_TTC_128;
197 		else if (tx_mode <= 192)
198 			reg_val |= MTL_CONTROL_TTC_192;
199 		else if (tx_mode <= 256)
200 			reg_val |= MTL_CONTROL_TTC_256;
201 		else if (tx_mode <= 384)
202 			reg_val |= MTL_CONTROL_TTC_384;
203 		else
204 			reg_val |= MTL_CONTROL_TTC_512;
205 	}
206 
207 	/* write into TXQ operation register */
208 	writel(reg_val, ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
209 }
210 
211 static void sxgbe_set_rx_mtl_mode(void __iomem *ioaddr, int queue_num,
212 				  int rx_mode)
213 {
214 	u32 reg_val;
215 
216 	reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
217 	/* RX specific MTL mode settings */
218 	if (rx_mode == SXGBE_RX_MTL_SFMODE) {
219 		reg_val |= SXGBE_RX_MTL_SFMODE;
220 	} else {
221 		if (rx_mode <= 64)
222 			reg_val |= MTL_CONTROL_RTC_64;
223 		else if (rx_mode <= 96)
224 			reg_val |= MTL_CONTROL_RTC_96;
225 		else if (rx_mode <= 128)
226 			reg_val |= MTL_CONTROL_RTC_128;
227 	}
228 
229 	/* write into RXQ operation register */
230 	writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
231 }
232 
233 static const struct sxgbe_mtl_ops mtl_ops = {
234 	.mtl_set_txfifosize		= sxgbe_mtl_set_txfifosize,
235 	.mtl_set_rxfifosize		= sxgbe_mtl_set_rxfifosize,
236 	.mtl_enable_txqueue		= sxgbe_mtl_enable_txqueue,
237 	.mtl_disable_txqueue		= sxgbe_mtl_disable_txqueue,
238 	.mtl_dynamic_dma_rxqueue	= sxgbe_mtl_dma_dm_rxqueue,
239 	.set_tx_mtl_mode		= sxgbe_set_tx_mtl_mode,
240 	.set_rx_mtl_mode		= sxgbe_set_rx_mtl_mode,
241 	.mtl_init			= sxgbe_mtl_init,
242 	.mtl_fc_active			= sxgbe_mtl_fc_active,
243 	.mtl_fc_deactive		= sxgbe_mtl_fc_deactive,
244 	.mtl_fc_enable			= sxgbe_mtl_fc_enable,
245 	.mtl_fep_enable			= sxgbe_mtl_fep_enable,
246 	.mtl_fep_disable		= sxgbe_mtl_fep_disable,
247 	.mtl_fup_enable			= sxgbe_mtl_fup_enable,
248 	.mtl_fup_disable		= sxgbe_mtl_fup_disable
249 };
250 
251 const struct sxgbe_mtl_ops *sxgbe_get_mtl_ops(void)
252 {
253 	return &mtl_ops;
254 }
255