1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2019 NXP.
*/
#include <linux/device.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/seq_file.h>
#include "dcss-dev.h"
#define DCSS_WRSCL_CTRL_STATUS 0x00
#define WRSCL_ERR BIT(31)
#define WRSCL_ERR_EN BIT(30)
#define WRSCL_FRAME_COMP BIT(29)
#define WRSCL_FRAME_COMP_EN BIT(28)
#define WRSCL_FIFO_SIZE_POS 18
#define WRSCL_FIFO_SIZE_MASK GENMAK(24, 18)
#define WRSCL_P_FREQ_POS 10
#define WRSCL_P_FREQ_MASK GENMASK(17, 10)
#define WRSCL_P_SIZE_POS 7
#define WRSCL_P_SIZE_MASK GENMASK(9, 7)
#define WRSCL_T_SIZE_POS 5
#define WRSCL_T_SIZE_MASK GENMASK(6, 5)
#define WRSCL_BPP_POS 2
#define WRSCL_BPP_MASK GENMASK(4, 2)
#define WRSCL_REPEAT BIT(1)
#define WRSCL_ENABLE BIT(0)
#define DCSS_WRSCL_BASE_ADDR 0x10
#define DCSS_WRSCL_PITCH 0x14
struct dcss_wrscl {
struct device *dev;
void __iomem *base_reg;
u32 base_ofs;
struct dcss_ctxld *ctxld;
u32 ctx_id;
u32 buf_size;
u32 buf_addr;
void *buf_vaddr;
struct clk *bclk;
u32 ctrl_status;
};
static void dcss_wrscl_write(struct dcss_wrscl *wrscl, u32 val, u32 ofs)
{
dcss_ctxld_write(wrscl->ctxld, wrscl->ctx_id,
val, wrscl->base_ofs + ofs);
}
int dcss_wrscl_init(struct dcss_dev *dcss, unsigned long wrscl_base)
{
struct dcss_wrscl *wrscl;
wrscl = devm_kzalloc(dcss->dev, sizeof(*wrscl), GFP_KERNEL);
if (!wrscl)
return -ENOMEM;
wrscl->base_reg = devm_ioremap(dcss->dev, wrscl_base, SZ_4K);
if (!wrscl->base_reg) {
dev_err(dcss->dev, "wrscl: unable to remap base\n");
devm_kfree(dcss->dev, wrscl);
return -ENOMEM;
}
dcss->wrscl = wrscl;
wrscl->dev = dcss->dev;
wrscl->base_ofs = wrscl_base;
wrscl->ctxld = dcss->ctxld;
wrscl->ctx_id = CTX_SB_HP;
wrscl->bclk = dcss->axi_clk;
return 0;
}
void dcss_wrscl_exit(struct dcss_wrscl *wrscl)
{
devm_iounmap(wrscl->dev, wrscl->base_reg);
devm_kfree(wrscl->dev, wrscl);
}
static const u16 dcss_wrscl_psize_map[] = {64, 128, 256, 512, 1024, 2048, 4096};
u32 dcss_wrscl_setup(struct dcss_wrscl *wrscl, u32 pix_format, u32 vrefresh_hz,
u32 dst_xres, u32 dst_yres)
{
u32 pitch, p_size, p_freq, bpp;
dma_addr_t dma_handle;
u32 bclk_rate = clk_get_rate(wrscl->bclk);
/* we'd better release the old buffer */
if (wrscl->buf_addr)
dmam_free_coherent(wrscl->dev, wrscl->buf_size,
wrscl->buf_vaddr, wrscl->buf_addr);
p_size = PSIZE_256;
/* scaler output is YUV444 */
bpp = 4;
/* spread the load over the entire frame */
p_freq = ((u64)bclk_rate * dcss_wrscl_psize_map[p_size]) /
((u64)dst_xres * dst_yres * vrefresh_hz * bpp * 8);
/* choose a slightly smaller p_freq */
p_freq = p_freq - 3 > 255 ? 255 : p_freq - 3;
wrscl->ctrl_status = FIFO_512 << WRSCL_FIFO_SIZE_POS;
wrscl->ctrl_status |= p_size << WRSCL_P_SIZE_POS;
wrscl->ctrl_status |= TSIZE_256 << WRSCL_T_SIZE_POS;
wrscl->ctrl_status |= BPP_32_10BIT_OUTPUT << WRSCL_BPP_POS;
wrscl->ctrl_status |= p_freq << WRSCL_P_FREQ_POS;
wrscl->buf_size = dst_xres * dst_yres * bpp;
pitch = dst_xres * bpp;
wrscl->buf_vaddr = dmam_alloc_coherent(wrscl->dev, wrscl->buf_size,
&dma_handle, GFP_KERNEL);
if (!wrscl->buf_vaddr) {
dev_err(wrscl->dev, "wrscl: cannot alloc buf mem\n");
return 0;
}
wrscl->buf_addr = dma_handle;
dcss_wrscl_write(wrscl, wrscl->buf_addr, DCSS_WRSCL_BASE_ADDR);
dcss_wrscl_write(wrscl, pitch, DCSS_WRSCL_PITCH);
return wrscl->buf_addr;
}
void dcss_wrscl_enable(struct dcss_wrscl *wrscl)
{
wrscl->ctrl_status |= WRSCL_ENABLE | WRSCL_REPEAT;
dcss_wrscl_write(wrscl, wrscl->ctrl_status, DCSS_WRSCL_CTRL_STATUS);
}
void dcss_wrscl_disable(struct dcss_wrscl *wrscl)
{
wrscl->ctrl_status &= ~(WRSCL_ENABLE | WRSCL_REPEAT);
dcss_wrscl_write(wrscl, wrscl->ctrl_status, DCSS_WRSCL_CTRL_STATUS);
if (wrscl->buf_addr) {
dmam_free_coherent(wrscl->dev, wrscl->buf_size,
wrscl->buf_vaddr, wrscl->buf_addr);
wrscl->buf_addr = 0;
}
}
|