1*a296f7bfSAkihiro Tsukada // SPDX-License-Identifier: GPL-2.0
2f5a98f37SAkihiro Tsukada /*
3f5a98f37SAkihiro Tsukada * Earthsoft PT3 driver
4f5a98f37SAkihiro Tsukada *
5f5a98f37SAkihiro Tsukada * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
6f5a98f37SAkihiro Tsukada */
7f5a98f37SAkihiro Tsukada #include <linux/dma-mapping.h>
8f5a98f37SAkihiro Tsukada #include <linux/kernel.h>
9f5a98f37SAkihiro Tsukada #include <linux/pci.h>
10f5a98f37SAkihiro Tsukada
11f5a98f37SAkihiro Tsukada #include "pt3.h"
12f5a98f37SAkihiro Tsukada
13f5a98f37SAkihiro Tsukada #define PT3_ACCESS_UNIT (TS_PACKET_SZ * 128)
14f5a98f37SAkihiro Tsukada #define PT3_BUF_CANARY (0x74)
15f5a98f37SAkihiro Tsukada
get_dma_base(int idx)16f5a98f37SAkihiro Tsukada static u32 get_dma_base(int idx)
17f5a98f37SAkihiro Tsukada {
18f5a98f37SAkihiro Tsukada int i;
19f5a98f37SAkihiro Tsukada
20f5a98f37SAkihiro Tsukada i = (idx == 1 || idx == 2) ? 3 - idx : idx;
21f5a98f37SAkihiro Tsukada return REG_DMA_BASE + 0x18 * i;
22f5a98f37SAkihiro Tsukada }
23f5a98f37SAkihiro Tsukada
pt3_stop_dma(struct pt3_adapter * adap)24f5a98f37SAkihiro Tsukada int pt3_stop_dma(struct pt3_adapter *adap)
25f5a98f37SAkihiro Tsukada {
26f5a98f37SAkihiro Tsukada struct pt3_board *pt3 = adap->dvb_adap.priv;
27f5a98f37SAkihiro Tsukada u32 base;
28f5a98f37SAkihiro Tsukada u32 stat;
29f5a98f37SAkihiro Tsukada int retry;
30f5a98f37SAkihiro Tsukada
31f5a98f37SAkihiro Tsukada base = get_dma_base(adap->adap_idx);
32f5a98f37SAkihiro Tsukada stat = ioread32(pt3->regs[0] + base + OFST_STATUS);
33f5a98f37SAkihiro Tsukada if (!(stat & 0x01))
34f5a98f37SAkihiro Tsukada return 0;
35f5a98f37SAkihiro Tsukada
36f5a98f37SAkihiro Tsukada iowrite32(0x02, pt3->regs[0] + base + OFST_DMA_CTL);
37f5a98f37SAkihiro Tsukada for (retry = 0; retry < 5; retry++) {
38f5a98f37SAkihiro Tsukada stat = ioread32(pt3->regs[0] + base + OFST_STATUS);
39f5a98f37SAkihiro Tsukada if (!(stat & 0x01))
40f5a98f37SAkihiro Tsukada return 0;
41f5a98f37SAkihiro Tsukada msleep(50);
42f5a98f37SAkihiro Tsukada }
43f5a98f37SAkihiro Tsukada return -EIO;
44f5a98f37SAkihiro Tsukada }
45f5a98f37SAkihiro Tsukada
pt3_start_dma(struct pt3_adapter * adap)46f5a98f37SAkihiro Tsukada int pt3_start_dma(struct pt3_adapter *adap)
47f5a98f37SAkihiro Tsukada {
48f5a98f37SAkihiro Tsukada struct pt3_board *pt3 = adap->dvb_adap.priv;
49f5a98f37SAkihiro Tsukada u32 base = get_dma_base(adap->adap_idx);
50f5a98f37SAkihiro Tsukada
51f5a98f37SAkihiro Tsukada iowrite32(0x02, pt3->regs[0] + base + OFST_DMA_CTL);
52f5a98f37SAkihiro Tsukada iowrite32(lower_32_bits(adap->desc_buf[0].b_addr),
53f5a98f37SAkihiro Tsukada pt3->regs[0] + base + OFST_DMA_DESC_L);
54f5a98f37SAkihiro Tsukada iowrite32(upper_32_bits(adap->desc_buf[0].b_addr),
55f5a98f37SAkihiro Tsukada pt3->regs[0] + base + OFST_DMA_DESC_H);
56f5a98f37SAkihiro Tsukada iowrite32(0x01, pt3->regs[0] + base + OFST_DMA_CTL);
57f5a98f37SAkihiro Tsukada return 0;
58f5a98f37SAkihiro Tsukada }
59f5a98f37SAkihiro Tsukada
60f5a98f37SAkihiro Tsukada
next_unit(struct pt3_adapter * adap,int * idx,int * ofs)61f5a98f37SAkihiro Tsukada static u8 *next_unit(struct pt3_adapter *adap, int *idx, int *ofs)
62f5a98f37SAkihiro Tsukada {
63f5a98f37SAkihiro Tsukada *ofs += PT3_ACCESS_UNIT;
64f5a98f37SAkihiro Tsukada if (*ofs >= DATA_BUF_SZ) {
65f5a98f37SAkihiro Tsukada *ofs -= DATA_BUF_SZ;
66f5a98f37SAkihiro Tsukada (*idx)++;
67f5a98f37SAkihiro Tsukada if (*idx == adap->num_bufs)
68f5a98f37SAkihiro Tsukada *idx = 0;
69f5a98f37SAkihiro Tsukada }
70f5a98f37SAkihiro Tsukada return &adap->buffer[*idx].data[*ofs];
71f5a98f37SAkihiro Tsukada }
72f5a98f37SAkihiro Tsukada
pt3_proc_dma(struct pt3_adapter * adap)73f5a98f37SAkihiro Tsukada int pt3_proc_dma(struct pt3_adapter *adap)
74f5a98f37SAkihiro Tsukada {
75f5a98f37SAkihiro Tsukada int idx, ofs;
76f5a98f37SAkihiro Tsukada
77f5a98f37SAkihiro Tsukada idx = adap->buf_idx;
78f5a98f37SAkihiro Tsukada ofs = adap->buf_ofs;
79f5a98f37SAkihiro Tsukada
80f5a98f37SAkihiro Tsukada if (adap->buffer[idx].data[ofs] == PT3_BUF_CANARY)
81f5a98f37SAkihiro Tsukada return 0;
82f5a98f37SAkihiro Tsukada
83f5a98f37SAkihiro Tsukada while (*next_unit(adap, &idx, &ofs) != PT3_BUF_CANARY) {
84f5a98f37SAkihiro Tsukada u8 *p;
85f5a98f37SAkihiro Tsukada
86f5a98f37SAkihiro Tsukada p = &adap->buffer[adap->buf_idx].data[adap->buf_ofs];
87f5a98f37SAkihiro Tsukada if (adap->num_discard > 0)
88f5a98f37SAkihiro Tsukada adap->num_discard--;
89f5a98f37SAkihiro Tsukada else if (adap->buf_ofs + PT3_ACCESS_UNIT > DATA_BUF_SZ) {
90f5a98f37SAkihiro Tsukada dvb_dmx_swfilter_packets(&adap->demux, p,
91f5a98f37SAkihiro Tsukada (DATA_BUF_SZ - adap->buf_ofs) / TS_PACKET_SZ);
92f5a98f37SAkihiro Tsukada dvb_dmx_swfilter_packets(&adap->demux,
93f5a98f37SAkihiro Tsukada adap->buffer[idx].data, ofs / TS_PACKET_SZ);
94f5a98f37SAkihiro Tsukada } else
95f5a98f37SAkihiro Tsukada dvb_dmx_swfilter_packets(&adap->demux, p,
96f5a98f37SAkihiro Tsukada PT3_ACCESS_UNIT / TS_PACKET_SZ);
97f5a98f37SAkihiro Tsukada
98f5a98f37SAkihiro Tsukada *p = PT3_BUF_CANARY;
99f5a98f37SAkihiro Tsukada adap->buf_idx = idx;
100f5a98f37SAkihiro Tsukada adap->buf_ofs = ofs;
101f5a98f37SAkihiro Tsukada }
102f5a98f37SAkihiro Tsukada return 0;
103f5a98f37SAkihiro Tsukada }
104f5a98f37SAkihiro Tsukada
pt3_init_dmabuf(struct pt3_adapter * adap)105f5a98f37SAkihiro Tsukada void pt3_init_dmabuf(struct pt3_adapter *adap)
106f5a98f37SAkihiro Tsukada {
107f5a98f37SAkihiro Tsukada int idx, ofs;
108f5a98f37SAkihiro Tsukada u8 *p;
109f5a98f37SAkihiro Tsukada
110f5a98f37SAkihiro Tsukada idx = 0;
111f5a98f37SAkihiro Tsukada ofs = 0;
112f5a98f37SAkihiro Tsukada p = adap->buffer[0].data;
113f5a98f37SAkihiro Tsukada /* mark the whole buffers as "not written yet" */
114f5a98f37SAkihiro Tsukada while (idx < adap->num_bufs) {
115f5a98f37SAkihiro Tsukada p[ofs] = PT3_BUF_CANARY;
116f5a98f37SAkihiro Tsukada ofs += PT3_ACCESS_UNIT;
117f5a98f37SAkihiro Tsukada if (ofs >= DATA_BUF_SZ) {
118f5a98f37SAkihiro Tsukada ofs -= DATA_BUF_SZ;
119f5a98f37SAkihiro Tsukada idx++;
120f5a98f37SAkihiro Tsukada p = adap->buffer[idx].data;
121f5a98f37SAkihiro Tsukada }
122f5a98f37SAkihiro Tsukada }
123f5a98f37SAkihiro Tsukada adap->buf_idx = 0;
124f5a98f37SAkihiro Tsukada adap->buf_ofs = 0;
125f5a98f37SAkihiro Tsukada }
126f5a98f37SAkihiro Tsukada
pt3_free_dmabuf(struct pt3_adapter * adap)127f5a98f37SAkihiro Tsukada void pt3_free_dmabuf(struct pt3_adapter *adap)
128f5a98f37SAkihiro Tsukada {
129f5a98f37SAkihiro Tsukada struct pt3_board *pt3;
130f5a98f37SAkihiro Tsukada int i;
131f5a98f37SAkihiro Tsukada
132f5a98f37SAkihiro Tsukada pt3 = adap->dvb_adap.priv;
133f5a98f37SAkihiro Tsukada for (i = 0; i < adap->num_bufs; i++)
134f5a98f37SAkihiro Tsukada dma_free_coherent(&pt3->pdev->dev, DATA_BUF_SZ,
135f5a98f37SAkihiro Tsukada adap->buffer[i].data, adap->buffer[i].b_addr);
136f5a98f37SAkihiro Tsukada adap->num_bufs = 0;
137f5a98f37SAkihiro Tsukada
138f5a98f37SAkihiro Tsukada for (i = 0; i < adap->num_desc_bufs; i++)
139f5a98f37SAkihiro Tsukada dma_free_coherent(&pt3->pdev->dev, PAGE_SIZE,
140f5a98f37SAkihiro Tsukada adap->desc_buf[i].descs, adap->desc_buf[i].b_addr);
141f5a98f37SAkihiro Tsukada adap->num_desc_bufs = 0;
142f5a98f37SAkihiro Tsukada }
143f5a98f37SAkihiro Tsukada
144f5a98f37SAkihiro Tsukada
pt3_alloc_dmabuf(struct pt3_adapter * adap)145f5a98f37SAkihiro Tsukada int pt3_alloc_dmabuf(struct pt3_adapter *adap)
146f5a98f37SAkihiro Tsukada {
147f5a98f37SAkihiro Tsukada struct pt3_board *pt3;
148f5a98f37SAkihiro Tsukada void *p;
149f5a98f37SAkihiro Tsukada int i, j;
150f5a98f37SAkihiro Tsukada int idx, ofs;
151f5a98f37SAkihiro Tsukada int num_desc_bufs;
152f5a98f37SAkihiro Tsukada dma_addr_t data_addr, desc_addr;
153f5a98f37SAkihiro Tsukada struct xfer_desc *d;
154f5a98f37SAkihiro Tsukada
155f5a98f37SAkihiro Tsukada pt3 = adap->dvb_adap.priv;
156f5a98f37SAkihiro Tsukada adap->num_bufs = 0;
157f5a98f37SAkihiro Tsukada adap->num_desc_bufs = 0;
158f5a98f37SAkihiro Tsukada for (i = 0; i < pt3->num_bufs; i++) {
159f5a98f37SAkihiro Tsukada p = dma_alloc_coherent(&pt3->pdev->dev, DATA_BUF_SZ,
160f5a98f37SAkihiro Tsukada &adap->buffer[i].b_addr, GFP_KERNEL);
161f5a98f37SAkihiro Tsukada if (p == NULL)
162f5a98f37SAkihiro Tsukada goto failed;
163f5a98f37SAkihiro Tsukada adap->buffer[i].data = p;
164f5a98f37SAkihiro Tsukada adap->num_bufs++;
165f5a98f37SAkihiro Tsukada }
166f5a98f37SAkihiro Tsukada pt3_init_dmabuf(adap);
167f5a98f37SAkihiro Tsukada
168f5a98f37SAkihiro Tsukada /* build circular-linked pointers (xfer_desc) to the data buffers*/
169f5a98f37SAkihiro Tsukada idx = 0;
170f5a98f37SAkihiro Tsukada ofs = 0;
171f5a98f37SAkihiro Tsukada num_desc_bufs =
172f5a98f37SAkihiro Tsukada DIV_ROUND_UP(adap->num_bufs * DATA_BUF_XFERS, DESCS_IN_PAGE);
173f5a98f37SAkihiro Tsukada for (i = 0; i < num_desc_bufs; i++) {
174f5a98f37SAkihiro Tsukada p = dma_alloc_coherent(&pt3->pdev->dev, PAGE_SIZE,
175f5a98f37SAkihiro Tsukada &desc_addr, GFP_KERNEL);
176f5a98f37SAkihiro Tsukada if (p == NULL)
177f5a98f37SAkihiro Tsukada goto failed;
178f5a98f37SAkihiro Tsukada adap->num_desc_bufs++;
179f5a98f37SAkihiro Tsukada adap->desc_buf[i].descs = p;
180f5a98f37SAkihiro Tsukada adap->desc_buf[i].b_addr = desc_addr;
181f5a98f37SAkihiro Tsukada
182f5a98f37SAkihiro Tsukada if (i > 0) {
183f5a98f37SAkihiro Tsukada d = &adap->desc_buf[i - 1].descs[DESCS_IN_PAGE - 1];
184f5a98f37SAkihiro Tsukada d->next_l = lower_32_bits(desc_addr);
185f5a98f37SAkihiro Tsukada d->next_h = upper_32_bits(desc_addr);
186f5a98f37SAkihiro Tsukada }
187f5a98f37SAkihiro Tsukada for (j = 0; j < DESCS_IN_PAGE; j++) {
188f5a98f37SAkihiro Tsukada data_addr = adap->buffer[idx].b_addr + ofs;
189f5a98f37SAkihiro Tsukada d = &adap->desc_buf[i].descs[j];
190f5a98f37SAkihiro Tsukada d->addr_l = lower_32_bits(data_addr);
191f5a98f37SAkihiro Tsukada d->addr_h = upper_32_bits(data_addr);
192f5a98f37SAkihiro Tsukada d->size = DATA_XFER_SZ;
193f5a98f37SAkihiro Tsukada
194f5a98f37SAkihiro Tsukada desc_addr += sizeof(struct xfer_desc);
195f5a98f37SAkihiro Tsukada d->next_l = lower_32_bits(desc_addr);
196f5a98f37SAkihiro Tsukada d->next_h = upper_32_bits(desc_addr);
197f5a98f37SAkihiro Tsukada
198f5a98f37SAkihiro Tsukada ofs += DATA_XFER_SZ;
199f5a98f37SAkihiro Tsukada if (ofs >= DATA_BUF_SZ) {
200f5a98f37SAkihiro Tsukada ofs -= DATA_BUF_SZ;
201f5a98f37SAkihiro Tsukada idx++;
202f5a98f37SAkihiro Tsukada if (idx >= adap->num_bufs) {
203f5a98f37SAkihiro Tsukada desc_addr = adap->desc_buf[0].b_addr;
204f5a98f37SAkihiro Tsukada d->next_l = lower_32_bits(desc_addr);
205f5a98f37SAkihiro Tsukada d->next_h = upper_32_bits(desc_addr);
206f5a98f37SAkihiro Tsukada return 0;
207f5a98f37SAkihiro Tsukada }
208f5a98f37SAkihiro Tsukada }
209f5a98f37SAkihiro Tsukada }
210f5a98f37SAkihiro Tsukada }
211f5a98f37SAkihiro Tsukada return 0;
212f5a98f37SAkihiro Tsukada
213f5a98f37SAkihiro Tsukada failed:
214f5a98f37SAkihiro Tsukada pt3_free_dmabuf(adap);
215f5a98f37SAkihiro Tsukada return -ENOMEM;
216f5a98f37SAkihiro Tsukada }
217