]>
Commit | Line | Data |
---|---|---|
1c4b5f49 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
26e0ca22 LP |
2 | /* |
3 | * vsp1_lif.c -- R-Car VSP1 LCD Controller Interface | |
4 | * | |
8a1edc55 | 5 | * Copyright (C) 2013-2014 Renesas Electronics Corporation |
26e0ca22 LP |
6 | * |
7 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | |
26e0ca22 LP |
8 | */ |
9 | ||
10 | #include <linux/device.h> | |
11 | #include <linux/gfp.h> | |
12 | ||
13 | #include <media/v4l2-subdev.h> | |
14 | ||
15 | #include "vsp1.h" | |
5e8dbbf3 | 16 | #include "vsp1_dl.h" |
26e0ca22 LP |
17 | #include "vsp1_lif.h" |
18 | ||
19 | #define LIF_MIN_SIZE 2U | |
0d268dcc | 20 | #define LIF_MAX_SIZE 8190U |
26e0ca22 LP |
21 | |
22 | /* ----------------------------------------------------------------------------- | |
23 | * Device Access | |
24 | */ | |
25 | ||
12832dd9 KB |
26 | static inline void vsp1_lif_write(struct vsp1_lif *lif, |
27 | struct vsp1_dl_body *dlb, u32 reg, u32 data) | |
26e0ca22 | 28 | { |
12832dd9 KB |
29 | vsp1_dl_body_write(dlb, reg + lif->entity.index * VI6_LIF_OFFSET, |
30 | data); | |
26e0ca22 LP |
31 | } |
32 | ||
33 | /* ----------------------------------------------------------------------------- | |
7b905f05 | 34 | * V4L2 Subdevice Operations |
26e0ca22 LP |
35 | */ |
36 | ||
b4ccae10 LP |
37 | static const unsigned int lif_codes[] = { |
38 | MEDIA_BUS_FMT_ARGB8888_1X32, | |
39 | MEDIA_BUS_FMT_AYUV8_1X32, | |
40 | }; | |
41 | ||
26e0ca22 | 42 | static int lif_enum_mbus_code(struct v4l2_subdev *subdev, |
f7234138 | 43 | struct v4l2_subdev_pad_config *cfg, |
26e0ca22 LP |
44 | struct v4l2_subdev_mbus_code_enum *code) |
45 | { | |
b4ccae10 LP |
46 | return vsp1_subdev_enum_mbus_code(subdev, cfg, code, lif_codes, |
47 | ARRAY_SIZE(lif_codes)); | |
26e0ca22 LP |
48 | } |
49 | ||
50 | static int lif_enum_frame_size(struct v4l2_subdev *subdev, | |
f7234138 | 51 | struct v4l2_subdev_pad_config *cfg, |
26e0ca22 LP |
52 | struct v4l2_subdev_frame_size_enum *fse) |
53 | { | |
076e834f LP |
54 | return vsp1_subdev_enum_frame_size(subdev, cfg, fse, LIF_MIN_SIZE, |
55 | LIF_MIN_SIZE, LIF_MAX_SIZE, | |
56 | LIF_MAX_SIZE); | |
26e0ca22 LP |
57 | } |
58 | ||
1bd0a1bd LP |
59 | static int lif_set_format(struct v4l2_subdev *subdev, |
60 | struct v4l2_subdev_pad_config *cfg, | |
26e0ca22 LP |
61 | struct v4l2_subdev_format *fmt) |
62 | { | |
b4ccae10 LP |
63 | return vsp1_subdev_set_pad_format(subdev, cfg, fmt, lif_codes, |
64 | ARRAY_SIZE(lif_codes), | |
65 | LIF_MIN_SIZE, LIF_MIN_SIZE, | |
66 | LIF_MAX_SIZE, LIF_MAX_SIZE); | |
26e0ca22 LP |
67 | } |
68 | ||
eb9163d3 | 69 | static const struct v4l2_subdev_pad_ops lif_pad_ops = { |
0efdf0f5 | 70 | .init_cfg = vsp1_entity_init_cfg, |
26e0ca22 LP |
71 | .enum_mbus_code = lif_enum_mbus_code, |
72 | .enum_frame_size = lif_enum_frame_size, | |
3f557220 | 73 | .get_fmt = vsp1_subdev_get_pad_format, |
26e0ca22 LP |
74 | .set_fmt = lif_set_format, |
75 | }; | |
76 | ||
eb9163d3 | 77 | static const struct v4l2_subdev_ops lif_ops = { |
26e0ca22 LP |
78 | .pad = &lif_pad_ops, |
79 | }; | |
80 | ||
7b905f05 LP |
81 | /* ----------------------------------------------------------------------------- |
82 | * VSP1 Entity Operations | |
83 | */ | |
84 | ||
46ce3639 KB |
85 | static void lif_configure_stream(struct vsp1_entity *entity, |
86 | struct vsp1_pipeline *pipe, | |
b36c6049 | 87 | struct vsp1_dl_list *dl, |
12832dd9 | 88 | struct vsp1_dl_body *dlb) |
7b905f05 LP |
89 | { |
90 | const struct v4l2_mbus_framefmt *format; | |
91 | struct vsp1_lif *lif = to_lif(&entity->subdev); | |
de2bc45c LP |
92 | unsigned int hbth; |
93 | unsigned int obth; | |
94 | unsigned int lbth; | |
7b905f05 LP |
95 | |
96 | format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config, | |
97 | LIF_PAD_SOURCE); | |
98 | ||
230bce55 | 99 | switch (entity->vsp1->version & VI6_IP_VERSION_MODEL_MASK) { |
de2bc45c LP |
100 | case VI6_IP_VERSION_MODEL_VSPD_GEN2: |
101 | case VI6_IP_VERSION_MODEL_VSPD_V2H: | |
102 | hbth = 1536; | |
103 | obth = min(128U, (format->width + 1) / 2 * format->height - 4); | |
104 | lbth = 1520; | |
105 | break; | |
106 | ||
107 | case VI6_IP_VERSION_MODEL_VSPDL_GEN3: | |
108 | case VI6_IP_VERSION_MODEL_VSPD_V3: | |
109 | hbth = 0; | |
110 | obth = 1500; | |
111 | lbth = 0; | |
112 | break; | |
113 | ||
114 | case VI6_IP_VERSION_MODEL_VSPD_GEN3: | |
115 | default: | |
116 | hbth = 0; | |
117 | obth = 3000; | |
118 | lbth = 0; | |
119 | break; | |
120 | } | |
7b905f05 | 121 | |
12832dd9 | 122 | vsp1_lif_write(lif, dlb, VI6_LIF_CSBTH, |
7b905f05 LP |
123 | (hbth << VI6_LIF_CSBTH_HBTH_SHIFT) | |
124 | (lbth << VI6_LIF_CSBTH_LBTH_SHIFT)); | |
125 | ||
12832dd9 | 126 | vsp1_lif_write(lif, dlb, VI6_LIF_CTRL, |
7b905f05 LP |
127 | (obth << VI6_LIF_CTRL_OBTH_SHIFT) | |
128 | (format->code == 0 ? VI6_LIF_CTRL_CFMT : 0) | | |
129 | VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN); | |
7f43ff95 SS |
130 | |
131 | /* | |
132 | * On R-Car V3M the LIF0 buffer attribute register has to be set to a | |
133 | * non-default value to guarantee proper operation (otherwise artifacts | |
134 | * may appear on the output). The value required by the manual is not | |
135 | * explained but is likely a buffer size or threshold. | |
136 | */ | |
137 | if ((entity->vsp1->version & VI6_IP_VERSION_MASK) == | |
138 | (VI6_IP_VERSION_MODEL_VSPD_V3 | VI6_IP_VERSION_SOC_V3M)) | |
12832dd9 | 139 | vsp1_lif_write(lif, dlb, VI6_LIF_LBA, |
7f43ff95 SS |
140 | VI6_LIF_LBA_LBA0 | |
141 | (1536 << VI6_LIF_LBA_LBA1_SHIFT)); | |
7b905f05 LP |
142 | } |
143 | ||
144 | static const struct vsp1_entity_operations lif_entity_ops = { | |
46ce3639 | 145 | .configure_stream = lif_configure_stream, |
7b905f05 LP |
146 | }; |
147 | ||
26e0ca22 LP |
148 | /* ----------------------------------------------------------------------------- |
149 | * Initialization and Cleanup | |
150 | */ | |
151 | ||
3be0bf97 | 152 | struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1, unsigned int index) |
26e0ca22 | 153 | { |
26e0ca22 LP |
154 | struct vsp1_lif *lif; |
155 | int ret; | |
156 | ||
157 | lif = devm_kzalloc(vsp1->dev, sizeof(*lif), GFP_KERNEL); | |
158 | if (lif == NULL) | |
159 | return ERR_PTR(-ENOMEM); | |
160 | ||
7b905f05 | 161 | lif->entity.ops = &lif_entity_ops; |
26e0ca22 | 162 | lif->entity.type = VSP1_ENTITY_LIF; |
3be0bf97 | 163 | lif->entity.index = index; |
26e0ca22 | 164 | |
9dbed95b LP |
165 | /* |
166 | * The LIF is never exposed to userspace, but media entity registration | |
6a8e07b2 LP |
167 | * requires a function to be set. Use PROC_VIDEO_PIXEL_FORMATTER just to |
168 | * avoid triggering a WARN_ON(), the value won't be seen anywhere. | |
169 | */ | |
170 | ret = vsp1_entity_init(vsp1, &lif->entity, "lif", 2, &lif_ops, | |
171 | MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER); | |
26e0ca22 LP |
172 | if (ret < 0) |
173 | return ERR_PTR(ret); | |
174 | ||
26e0ca22 LP |
175 | return lif; |
176 | } |