aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/video/mx2_camera.c260
1 files changed, 256 insertions, 4 deletions
diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c
index 03be36e87077..18afaeeadb7b 100644
--- a/drivers/media/video/mx2_camera.c
+++ b/drivers/media/video/mx2_camera.c
@@ -19,6 +19,7 @@
19#include <linux/dma-mapping.h> 19#include <linux/dma-mapping.h>
20#include <linux/errno.h> 20#include <linux/errno.h>
21#include <linux/fs.h> 21#include <linux/fs.h>
22#include <linux/gcd.h>
22#include <linux/interrupt.h> 23#include <linux/interrupt.h>
23#include <linux/kernel.h> 24#include <linux/kernel.h>
24#include <linux/mm.h> 25#include <linux/mm.h>
@@ -204,8 +205,23 @@
204#define PRP_INTR_LBOVF (1 << 7) 205#define PRP_INTR_LBOVF (1 << 7)
205#define PRP_INTR_CH2OVF (1 << 8) 206#define PRP_INTR_CH2OVF (1 << 8)
206 207
208/* Resizing registers */
209#define PRP_RZ_VALID_TBL_LEN(x) ((x) << 24)
210#define PRP_RZ_VALID_BILINEAR (1 << 31)
211
207#define MAX_VIDEO_MEM 16 212#define MAX_VIDEO_MEM 16
208 213
214#define RESIZE_NUM_MIN 1
215#define RESIZE_NUM_MAX 20
216#define BC_COEF 3
217#define SZ_COEF (1 << BC_COEF)
218
219#define RESIZE_DIR_H 0
220#define RESIZE_DIR_V 1
221
222#define RESIZE_ALGO_BILINEAR 0
223#define RESIZE_ALGO_AVERAGING 1
224
209struct mx2_prp_cfg { 225struct mx2_prp_cfg {
210 int channel; 226 int channel;
211 u32 in_fmt; 227 u32 in_fmt;
@@ -215,6 +231,13 @@ struct mx2_prp_cfg {
215 u32 irq_flags; 231 u32 irq_flags;
216}; 232};
217 233
234/* prp resizing parameters */
235struct emma_prp_resize {
236 int algo; /* type of algorithm used */
237 int len; /* number of coefficients */
238 unsigned char s[RESIZE_NUM_MAX]; /* table of coefficients */
239};
240
218/* prp configuration for a client-host fmt pair */ 241/* prp configuration for a client-host fmt pair */
219struct mx2_fmt_cfg { 242struct mx2_fmt_cfg {
220 enum v4l2_mbus_pixelcode in_fmt; 243 enum v4l2_mbus_pixelcode in_fmt;
@@ -274,6 +297,8 @@ struct mx2_camera_dev {
274 dma_addr_t discard_buffer_dma; 297 dma_addr_t discard_buffer_dma;
275 size_t discard_size; 298 size_t discard_size;
276 struct mx2_fmt_cfg *emma_prp; 299 struct mx2_fmt_cfg *emma_prp;
300 struct emma_prp_resize resizing[2];
301 unsigned int s_width, s_height;
277 u32 frame_count; 302 u32 frame_count;
278 struct vb2_alloc_ctx *alloc_ctx; 303 struct vb2_alloc_ctx *alloc_ctx;
279}; 304};
@@ -678,7 +703,7 @@ static void mx27_camera_emma_buf_init(struct soc_camera_device *icd,
678 struct mx2_camera_dev *pcdev = ici->priv; 703 struct mx2_camera_dev *pcdev = ici->priv;
679 struct mx2_fmt_cfg *prp = pcdev->emma_prp; 704 struct mx2_fmt_cfg *prp = pcdev->emma_prp;
680 705
681 writel((icd->user_width << 16) | icd->user_height, 706 writel((pcdev->s_width << 16) | pcdev->s_height,
682 pcdev->base_emma + PRP_SRC_FRAME_SIZE); 707 pcdev->base_emma + PRP_SRC_FRAME_SIZE);
683 writel(prp->cfg.src_pixel, 708 writel(prp->cfg.src_pixel,
684 pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); 709 pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL);
@@ -698,6 +723,74 @@ static void mx27_camera_emma_buf_init(struct soc_camera_device *icd,
698 writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL); 723 writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL);
699} 724}
700 725
726static void mx2_prp_resize_commit(struct mx2_camera_dev *pcdev)
727{
728 int dir;
729
730 for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) {
731 unsigned char *s = pcdev->resizing[dir].s;
732 int len = pcdev->resizing[dir].len;
733 unsigned int coeff[2] = {0, 0};
734 unsigned int valid = 0;
735 int i;
736
737 if (len == 0)
738 continue;
739
740 for (i = RESIZE_NUM_MAX - 1; i >= 0; i--) {
741 int j;
742
743 j = i > 9 ? 1 : 0;
744 coeff[j] = (coeff[j] << BC_COEF) |
745 (s[i] & (SZ_COEF - 1));
746
747 if (i == 5 || i == 15)
748 coeff[j] <<= 1;
749
750 valid = (valid << 1) | (s[i] >> BC_COEF);
751 }
752
753 valid |= PRP_RZ_VALID_TBL_LEN(len);
754
755 if (pcdev->resizing[dir].algo == RESIZE_ALGO_BILINEAR)
756 valid |= PRP_RZ_VALID_BILINEAR;
757
758 if (pcdev->emma_prp->cfg.channel == 1) {
759 if (dir == RESIZE_DIR_H) {
760 writel(coeff[0], pcdev->base_emma +
761 PRP_CH1_RZ_HORI_COEF1);
762 writel(coeff[1], pcdev->base_emma +
763 PRP_CH1_RZ_HORI_COEF2);
764 writel(valid, pcdev->base_emma +
765 PRP_CH1_RZ_HORI_VALID);
766 } else {
767 writel(coeff[0], pcdev->base_emma +
768 PRP_CH1_RZ_VERT_COEF1);
769 writel(coeff[1], pcdev->base_emma +
770 PRP_CH1_RZ_VERT_COEF2);
771 writel(valid, pcdev->base_emma +
772 PRP_CH1_RZ_VERT_VALID);
773 }
774 } else {
775 if (dir == RESIZE_DIR_H) {
776 writel(coeff[0], pcdev->base_emma +
777 PRP_CH2_RZ_HORI_COEF1);
778 writel(coeff[1], pcdev->base_emma +
779 PRP_CH2_RZ_HORI_COEF2);
780 writel(valid, pcdev->base_emma +
781 PRP_CH2_RZ_HORI_VALID);
782 } else {
783 writel(coeff[0], pcdev->base_emma +
784 PRP_CH2_RZ_VERT_COEF1);
785 writel(coeff[1], pcdev->base_emma +
786 PRP_CH2_RZ_VERT_COEF2);
787 writel(valid, pcdev->base_emma +
788 PRP_CH2_RZ_VERT_VALID);
789 }
790 }
791 }
792}
793
701static int mx2_start_streaming(struct vb2_queue *q, unsigned int count) 794static int mx2_start_streaming(struct vb2_queue *q, unsigned int count)
702{ 795{
703 struct soc_camera_device *icd = soc_camera_from_vb2q(q); 796 struct soc_camera_device *icd = soc_camera_from_vb2q(q);
@@ -764,6 +857,8 @@ static int mx2_start_streaming(struct vb2_queue *q, unsigned int count)
764 list_add_tail(&pcdev->buf_discard[1].queue, 857 list_add_tail(&pcdev->buf_discard[1].queue,
765 &pcdev->discard); 858 &pcdev->discard);
766 859
860 mx2_prp_resize_commit(pcdev);
861
767 mx27_camera_emma_buf_init(icd, bytesperline); 862 mx27_camera_emma_buf_init(icd, bytesperline);
768 863
769 if (prp->cfg.channel == 1) { 864 if (prp->cfg.channel == 1) {
@@ -1049,6 +1144,123 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd,
1049 return formats; 1144 return formats;
1050} 1145}
1051 1146
1147static int mx2_emmaprp_resize(struct mx2_camera_dev *pcdev,
1148 struct v4l2_mbus_framefmt *mf_in,
1149 struct v4l2_pix_format *pix_out, bool apply)
1150{
1151 int num, den;
1152 unsigned long m;
1153 int i, dir;
1154
1155 for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) {
1156 struct emma_prp_resize tmprsz;
1157 unsigned char *s = tmprsz.s;
1158 int len = 0;
1159 int in, out;
1160
1161 if (dir == RESIZE_DIR_H) {
1162 in = mf_in->width;
1163 out = pix_out->width;
1164 } else {
1165 in = mf_in->height;
1166 out = pix_out->height;
1167 }
1168
1169 if (in < out)
1170 return -EINVAL;
1171 else if (in == out)
1172 continue;
1173
1174 /* Calculate ratio */
1175 m = gcd(in, out);
1176 num = in / m;
1177 den = out / m;
1178 if (num > RESIZE_NUM_MAX)
1179 return -EINVAL;
1180
1181 if ((num >= 2 * den) && (den == 1) &&
1182 (num < 9) && (!(num & 0x01))) {
1183 int sum = 0;
1184 int j;
1185
1186 /* Average scaling for >= 2:1 ratios */
1187 /* Support can be added for num >=9 and odd values */
1188
1189 tmprsz.algo = RESIZE_ALGO_AVERAGING;
1190 len = num;
1191
1192 for (i = 0; i < (len / 2); i++)
1193 s[i] = 8;
1194
1195 do {
1196 for (i = 0; i < (len / 2); i++) {
1197 s[i] = s[i] >> 1;
1198 sum = 0;
1199 for (j = 0; j < (len / 2); j++)
1200 sum += s[j];
1201 if (sum == 4)
1202 break;
1203 }
1204 } while (sum != 4);
1205
1206 for (i = (len / 2); i < len; i++)
1207 s[i] = s[len - i - 1];
1208
1209 s[len - 1] |= SZ_COEF;
1210 } else {
1211 /* bilinear scaling for < 2:1 ratios */
1212 int v; /* overflow counter */
1213 int coeff, nxt; /* table output */
1214 int in_pos_inc = 2 * den;
1215 int out_pos = num;
1216 int out_pos_inc = 2 * num;
1217 int init_carry = num - den;
1218 int carry = init_carry;
1219
1220 tmprsz.algo = RESIZE_ALGO_BILINEAR;
1221 v = den + in_pos_inc;
1222 do {
1223 coeff = v - out_pos;
1224 out_pos += out_pos_inc;
1225 carry += out_pos_inc;
1226 for (nxt = 0; v < out_pos; nxt++) {
1227 v += in_pos_inc;
1228 carry -= in_pos_inc;
1229 }
1230
1231 if (len > RESIZE_NUM_MAX)
1232 return -EINVAL;
1233
1234 coeff = ((coeff << BC_COEF) +
1235 (in_pos_inc >> 1)) / in_pos_inc;
1236
1237 if (coeff >= (SZ_COEF - 1))
1238 coeff--;
1239
1240 coeff |= SZ_COEF;
1241 s[len] = (unsigned char)coeff;
1242 len++;
1243
1244 for (i = 1; i < nxt; i++) {
1245 if (len >= RESIZE_NUM_MAX)
1246 return -EINVAL;
1247 s[len] = 0;
1248 len++;
1249 }
1250 } while (carry != init_carry);
1251 }
1252 tmprsz.len = len;
1253 if (dir == RESIZE_DIR_H)
1254 mf_in->width = pix_out->width;
1255 else
1256 mf_in->height = pix_out->height;
1257
1258 if (apply)
1259 memcpy(&pcdev->resizing[dir], &tmprsz, sizeof(tmprsz));
1260 }
1261 return 0;
1262}
1263
1052static int mx2_camera_set_fmt(struct soc_camera_device *icd, 1264static int mx2_camera_set_fmt(struct soc_camera_device *icd,
1053 struct v4l2_format *f) 1265 struct v4l2_format *f)
1054{ 1266{
@@ -1060,6 +1272,9 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd,
1060 struct v4l2_mbus_framefmt mf; 1272 struct v4l2_mbus_framefmt mf;
1061 int ret; 1273 int ret;
1062 1274
1275 dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n",
1276 __func__, pix->width, pix->height);
1277
1063 xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); 1278 xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
1064 if (!xlate) { 1279 if (!xlate) {
1065 dev_warn(icd->parent, "Format %x not found\n", 1280 dev_warn(icd->parent, "Format %x not found\n",
@@ -1077,6 +1292,22 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd,
1077 if (ret < 0 && ret != -ENOIOCTLCMD) 1292 if (ret < 0 && ret != -ENOIOCTLCMD)
1078 return ret; 1293 return ret;
1079 1294
1295 /* Store width and height returned by the sensor for resizing */
1296 pcdev->s_width = mf.width;
1297 pcdev->s_height = mf.height;
1298 dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n",
1299 __func__, pcdev->s_width, pcdev->s_height);
1300
1301 pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code,
1302 xlate->host_fmt->fourcc);
1303
1304 memset(pcdev->resizing, 0, sizeof(pcdev->resizing));
1305 if ((mf.width != pix->width || mf.height != pix->height) &&
1306 pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) {
1307 if (mx2_emmaprp_resize(pcdev, &mf, pix, true) < 0)
1308 dev_dbg(icd->parent, "%s: can't resize\n", __func__);
1309 }
1310
1080 if (mf.code != xlate->code) 1311 if (mf.code != xlate->code)
1081 return -EINVAL; 1312 return -EINVAL;
1082 1313
@@ -1086,9 +1317,8 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd,
1086 pix->colorspace = mf.colorspace; 1317 pix->colorspace = mf.colorspace;
1087 icd->current_fmt = xlate; 1318 icd->current_fmt = xlate;
1088 1319
1089 if (cpu_is_mx27()) 1320 dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n",
1090 pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code, 1321 __func__, pix->width, pix->height);
1091 xlate->host_fmt->fourcc);
1092 1322
1093 return 0; 1323 return 0;
1094} 1324}
@@ -1101,9 +1331,14 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
1101 struct v4l2_pix_format *pix = &f->fmt.pix; 1331 struct v4l2_pix_format *pix = &f->fmt.pix;
1102 struct v4l2_mbus_framefmt mf; 1332 struct v4l2_mbus_framefmt mf;
1103 __u32 pixfmt = pix->pixelformat; 1333 __u32 pixfmt = pix->pixelformat;
1334 struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
1335 struct mx2_camera_dev *pcdev = ici->priv;
1104 unsigned int width_limit; 1336 unsigned int width_limit;
1105 int ret; 1337 int ret;
1106 1338
1339 dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n",
1340 __func__, pix->width, pix->height);
1341
1107 xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); 1342 xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
1108 if (pixfmt && !xlate) { 1343 if (pixfmt && !xlate) {
1109 dev_warn(icd->parent, "Format %x not found\n", pixfmt); 1344 dev_warn(icd->parent, "Format %x not found\n", pixfmt);
@@ -1153,6 +1388,20 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
1153 if (ret < 0) 1388 if (ret < 0)
1154 return ret; 1389 return ret;
1155 1390
1391 dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n",
1392 __func__, pcdev->s_width, pcdev->s_height);
1393
1394 /* If the sensor does not support image size try PrP resizing */
1395 pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code,
1396 xlate->host_fmt->fourcc);
1397
1398 memset(pcdev->resizing, 0, sizeof(pcdev->resizing));
1399 if ((mf.width != pix->width || mf.height != pix->height) &&
1400 pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) {
1401 if (mx2_emmaprp_resize(pcdev, &mf, pix, false) < 0)
1402 dev_dbg(icd->parent, "%s: can't resize\n", __func__);
1403 }
1404
1156 if (mf.field == V4L2_FIELD_ANY) 1405 if (mf.field == V4L2_FIELD_ANY)
1157 mf.field = V4L2_FIELD_NONE; 1406 mf.field = V4L2_FIELD_NONE;
1158 /* 1407 /*
@@ -1171,6 +1420,9 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
1171 pix->field = mf.field; 1420 pix->field = mf.field;
1172 pix->colorspace = mf.colorspace; 1421 pix->colorspace = mf.colorspace;
1173 1422
1423 dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n",
1424 __func__, pix->width, pix->height);
1425
1174 return 0; 1426 return 0;
1175} 1427}
1176 1428