Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  PS3 AV backend support.
0004  *
0005  *  Copyright (C) 2007 Sony Computer Entertainment Inc.
0006  *  Copyright 2007 Sony Corp.
0007  */
0008 
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/delay.h>
0012 #include <linux/notifier.h>
0013 #include <linux/ioctl.h>
0014 #include <linux/fb.h>
0015 #include <linux/slab.h>
0016 
0017 #include <asm/firmware.h>
0018 #include <asm/ps3av.h>
0019 #include <asm/ps3.h>
0020 
0021 #include "vuart.h"
0022 
0023 #define BUFSIZE          4096   /* vuart buf size */
0024 #define PS3AV_BUF_SIZE   512    /* max packet size */
0025 
0026 static int safe_mode;
0027 
0028 static int timeout = 5000;  /* in msec ( 5 sec ) */
0029 module_param(timeout, int, 0644);
0030 
0031 static struct ps3av {
0032     struct mutex mutex;
0033     struct work_struct work;
0034     struct completion done;
0035     int open_count;
0036     struct ps3_system_bus_device *dev;
0037 
0038     int region;
0039     struct ps3av_pkt_av_get_hw_conf av_hw_conf;
0040     u32 av_port[PS3AV_AV_PORT_MAX + PS3AV_OPT_PORT_MAX];
0041     u32 opt_port[PS3AV_OPT_PORT_MAX];
0042     u32 head[PS3AV_HEAD_MAX];
0043     u32 audio_port;
0044     int ps3av_mode;
0045     int ps3av_mode_old;
0046     union {
0047         struct ps3av_reply_hdr reply_hdr;
0048         u8 raw[PS3AV_BUF_SIZE];
0049     } recv_buf;
0050 } *ps3av;
0051 
0052 /* color space */
0053 #define YUV444 PS3AV_CMD_VIDEO_CS_YUV444_8
0054 #define RGB8   PS3AV_CMD_VIDEO_CS_RGB_8
0055 /* format */
0056 #define XRGB   PS3AV_CMD_VIDEO_FMT_X8R8G8B8
0057 /* aspect */
0058 #define A_N    PS3AV_CMD_AV_ASPECT_4_3
0059 #define A_W    PS3AV_CMD_AV_ASPECT_16_9
0060 static const struct avset_video_mode {
0061     u32 cs;
0062     u32 fmt;
0063     u32 vid;
0064     u32 aspect;
0065     u32 x;
0066     u32 y;
0067 } video_mode_table[] = {
0068     {     0, }, /* auto */
0069     {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I,       A_N,  720,  480},
0070     {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P,       A_N,  720,  480},
0071     {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ,  A_W, 1280,  720},
0072     {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080},
0073     {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080},
0074     {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I,       A_N,  720,  576},
0075     {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P,       A_N,  720,  576},
0076     {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ,  A_W, 1280,  720},
0077     {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080},
0078     {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080},
0079     {  RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA,       A_W, 1280,  768},
0080     {  RGB8, XRGB, PS3AV_CMD_VIDEO_VID_SXGA,       A_N, 1280, 1024},
0081     {  RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WUXGA,      A_W, 1920, 1200},
0082 };
0083 
0084 /* supported CIDs */
0085 static u32 cmd_table[] = {
0086     /* init */
0087     PS3AV_CID_AV_INIT,
0088     PS3AV_CID_AV_FIN,
0089     PS3AV_CID_VIDEO_INIT,
0090     PS3AV_CID_AUDIO_INIT,
0091 
0092     /* set */
0093     PS3AV_CID_AV_ENABLE_EVENT,
0094     PS3AV_CID_AV_DISABLE_EVENT,
0095 
0096     PS3AV_CID_AV_VIDEO_CS,
0097     PS3AV_CID_AV_VIDEO_MUTE,
0098     PS3AV_CID_AV_VIDEO_DISABLE_SIG,
0099     PS3AV_CID_AV_AUDIO_PARAM,
0100     PS3AV_CID_AV_AUDIO_MUTE,
0101     PS3AV_CID_AV_HDMI_MODE,
0102     PS3AV_CID_AV_TV_MUTE,
0103 
0104     PS3AV_CID_VIDEO_MODE,
0105     PS3AV_CID_VIDEO_FORMAT,
0106     PS3AV_CID_VIDEO_PITCH,
0107 
0108     PS3AV_CID_AUDIO_MODE,
0109     PS3AV_CID_AUDIO_MUTE,
0110     PS3AV_CID_AUDIO_ACTIVE,
0111     PS3AV_CID_AUDIO_INACTIVE,
0112     PS3AV_CID_AVB_PARAM,
0113 
0114     /* get */
0115     PS3AV_CID_AV_GET_HW_CONF,
0116     PS3AV_CID_AV_GET_MONITOR_INFO,
0117 
0118     /* event */
0119     PS3AV_CID_EVENT_UNPLUGGED,
0120     PS3AV_CID_EVENT_PLUGGED,
0121     PS3AV_CID_EVENT_HDCP_DONE,
0122     PS3AV_CID_EVENT_HDCP_FAIL,
0123     PS3AV_CID_EVENT_HDCP_AUTH,
0124     PS3AV_CID_EVENT_HDCP_ERROR,
0125 
0126     0
0127 };
0128 
0129 #define PS3AV_EVENT_CMD_MASK           0x10000000
0130 #define PS3AV_EVENT_ID_MASK            0x0000ffff
0131 #define PS3AV_CID_MASK                 0xffffffff
0132 #define PS3AV_REPLY_BIT                0x80000000
0133 
0134 #define ps3av_event_get_port_id(cid)   ((cid >> 16) & 0xff)
0135 
0136 static u32 *ps3av_search_cmd_table(u32 cid, u32 mask)
0137 {
0138     u32 *table;
0139     int i;
0140 
0141     table = cmd_table;
0142     for (i = 0;; table++, i++) {
0143         if ((*table & mask) == (cid & mask))
0144             break;
0145         if (*table == 0)
0146             return NULL;
0147     }
0148     return table;
0149 }
0150 
0151 static int ps3av_parse_event_packet(const struct ps3av_reply_hdr *hdr)
0152 {
0153     u32 *table;
0154 
0155     if (hdr->cid & PS3AV_EVENT_CMD_MASK) {
0156         table = ps3av_search_cmd_table(hdr->cid, PS3AV_EVENT_CMD_MASK);
0157         if (table)
0158             dev_dbg(&ps3av->dev->core,
0159                 "recv event packet cid:%08x port:0x%x size:%d\n",
0160                 hdr->cid, ps3av_event_get_port_id(hdr->cid),
0161                 hdr->size);
0162         else
0163             printk(KERN_ERR
0164                    "%s: failed event packet, cid:%08x size:%d\n",
0165                    __func__, hdr->cid, hdr->size);
0166         return 1;   /* receive event packet */
0167     }
0168     return 0;
0169 }
0170 
0171 
0172 #define POLLING_INTERVAL  25    /* in msec */
0173 
0174 static int ps3av_vuart_write(struct ps3_system_bus_device *dev,
0175                  const void *buf, unsigned long size)
0176 {
0177     int error;
0178     dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
0179     error = ps3_vuart_write(dev, buf, size);
0180     dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
0181     return error ? error : size;
0182 }
0183 
0184 static int ps3av_vuart_read(struct ps3_system_bus_device *dev, void *buf,
0185                 unsigned long size, int timeout)
0186 {
0187     int error;
0188     int loopcnt = 0;
0189 
0190     dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
0191     timeout = (timeout + POLLING_INTERVAL - 1) / POLLING_INTERVAL;
0192     while (loopcnt++ <= timeout) {
0193         error = ps3_vuart_read(dev, buf, size);
0194         if (!error)
0195             return size;
0196         if (error != -EAGAIN) {
0197             printk(KERN_ERR "%s: ps3_vuart_read failed %d\n",
0198                    __func__, error);
0199             return error;
0200         }
0201         msleep(POLLING_INTERVAL);
0202     }
0203     return -EWOULDBLOCK;
0204 }
0205 
0206 static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf,
0207                   struct ps3av_reply_hdr *recv_buf, int write_len,
0208                   int read_len)
0209 {
0210     int res;
0211     u32 cmd;
0212     int event;
0213 
0214     if (!ps3av)
0215         return -ENODEV;
0216 
0217     /* send pkt */
0218     res = ps3av_vuart_write(ps3av->dev, send_buf, write_len);
0219     if (res < 0) {
0220         dev_warn(&ps3av->dev->core,
0221             "%s:%d: ps3av_vuart_write() failed: %s\n", __func__,
0222             __LINE__, ps3_result(res));
0223         return res;
0224     }
0225 
0226     /* recv pkt */
0227     cmd = send_buf->cid;
0228     do {
0229         /* read header */
0230         res = ps3av_vuart_read(ps3av->dev, recv_buf, PS3AV_HDR_SIZE,
0231                        timeout);
0232         if (res != PS3AV_HDR_SIZE) {
0233             dev_warn(&ps3av->dev->core,
0234                 "%s:%d: ps3av_vuart_read() failed: %s\n", __func__,
0235                 __LINE__, ps3_result(res));
0236             return res;
0237         }
0238 
0239         /* read body */
0240         res = ps3av_vuart_read(ps3av->dev, &recv_buf->cid,
0241                        recv_buf->size, timeout);
0242         if (res < 0) {
0243             dev_warn(&ps3av->dev->core,
0244                 "%s:%d: ps3av_vuart_read() failed: %s\n", __func__,
0245                 __LINE__, ps3_result(res));
0246             return res;
0247         }
0248         res += PS3AV_HDR_SIZE;  /* total len */
0249         event = ps3av_parse_event_packet(recv_buf);
0250         /* ret > 0 event packet */
0251     } while (event);
0252 
0253     if ((cmd | PS3AV_REPLY_BIT) != recv_buf->cid) {
0254         dev_warn(&ps3av->dev->core, "%s:%d: reply err: %x\n", __func__,
0255             __LINE__, recv_buf->cid);
0256         return -EINVAL;
0257     }
0258 
0259     return 0;
0260 }
0261 
0262 static int ps3av_process_reply_packet(struct ps3av_send_hdr *cmd_buf,
0263                       const struct ps3av_reply_hdr *recv_buf,
0264                       int user_buf_size)
0265 {
0266     int return_len;
0267 
0268     if (recv_buf->version != PS3AV_VERSION) {
0269         dev_dbg(&ps3av->dev->core, "reply_packet invalid version:%x\n",
0270             recv_buf->version);
0271         return -EFAULT;
0272     }
0273     return_len = recv_buf->size + PS3AV_HDR_SIZE;
0274     if (return_len > user_buf_size)
0275         return_len = user_buf_size;
0276     memcpy(cmd_buf, recv_buf, return_len);
0277     return 0;       /* success */
0278 }
0279 
0280 void ps3av_set_hdr(u32 cid, u16 size, struct ps3av_send_hdr *hdr)
0281 {
0282     hdr->version = PS3AV_VERSION;
0283     hdr->size = size - PS3AV_HDR_SIZE;
0284     hdr->cid = cid;
0285 }
0286 
0287 int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size,
0288          struct ps3av_send_hdr *buf)
0289 {
0290     int res = 0;
0291     u32 *table;
0292 
0293     BUG_ON(!ps3av);
0294 
0295     mutex_lock(&ps3av->mutex);
0296 
0297     table = ps3av_search_cmd_table(cid, PS3AV_CID_MASK);
0298     BUG_ON(!table);
0299     BUG_ON(send_len < PS3AV_HDR_SIZE);
0300     BUG_ON(usr_buf_size < send_len);
0301     BUG_ON(usr_buf_size > PS3AV_BUF_SIZE);
0302 
0303     /* create header */
0304     ps3av_set_hdr(cid, send_len, buf);
0305 
0306     /* send packet via vuart */
0307     res = ps3av_send_cmd_pkt(buf, &ps3av->recv_buf.reply_hdr, send_len,
0308                  usr_buf_size);
0309     if (res < 0) {
0310         printk(KERN_ERR
0311                "%s: ps3av_send_cmd_pkt() failed (result=%d)\n",
0312                __func__, res);
0313         goto err;
0314     }
0315 
0316     /* process reply packet */
0317     res = ps3av_process_reply_packet(buf, &ps3av->recv_buf.reply_hdr,
0318                      usr_buf_size);
0319     if (res < 0) {
0320         printk(KERN_ERR "%s: put_return_status() failed (result=%d)\n",
0321                __func__, res);
0322         goto err;
0323     }
0324 
0325     mutex_unlock(&ps3av->mutex);
0326     return 0;
0327 
0328 err:
0329     mutex_unlock(&ps3av->mutex);
0330     printk(KERN_ERR "%s: failed cid:%x res:%d\n", __func__, cid, res);
0331     return res;
0332 }
0333 
0334 static int ps3av_set_av_video_mute(u32 mute)
0335 {
0336     int i, num_of_av_port, res;
0337 
0338     num_of_av_port = ps3av->av_hw_conf.num_of_hdmi +
0339              ps3av->av_hw_conf.num_of_avmulti;
0340     /* video mute on */
0341     for (i = 0; i < num_of_av_port; i++) {
0342         res = ps3av_cmd_av_video_mute(1, &ps3av->av_port[i], mute);
0343         if (res < 0)
0344             return -1;
0345     }
0346 
0347     return 0;
0348 }
0349 
0350 static int ps3av_set_video_disable_sig(void)
0351 {
0352     int i, num_of_hdmi_port, num_of_av_port, res;
0353 
0354     num_of_hdmi_port = ps3av->av_hw_conf.num_of_hdmi;
0355     num_of_av_port = ps3av->av_hw_conf.num_of_hdmi +
0356              ps3av->av_hw_conf.num_of_avmulti;
0357 
0358     /* tv mute */
0359     for (i = 0; i < num_of_hdmi_port; i++) {
0360         res = ps3av_cmd_av_tv_mute(ps3av->av_port[i],
0361                        PS3AV_CMD_MUTE_ON);
0362         if (res < 0)
0363             return -1;
0364     }
0365     msleep(100);
0366 
0367     /* video mute on */
0368     for (i = 0; i < num_of_av_port; i++) {
0369         res = ps3av_cmd_av_video_disable_sig(ps3av->av_port[i]);
0370         if (res < 0)
0371             return -1;
0372         if (i < num_of_hdmi_port) {
0373             res = ps3av_cmd_av_tv_mute(ps3av->av_port[i],
0374                            PS3AV_CMD_MUTE_OFF);
0375             if (res < 0)
0376                 return -1;
0377         }
0378     }
0379     msleep(300);
0380 
0381     return 0;
0382 }
0383 
0384 static int ps3av_set_audio_mute(u32 mute)
0385 {
0386     int i, num_of_av_port, num_of_opt_port, res;
0387 
0388     num_of_av_port = ps3av->av_hw_conf.num_of_hdmi +
0389              ps3av->av_hw_conf.num_of_avmulti;
0390     num_of_opt_port = ps3av->av_hw_conf.num_of_spdif;
0391 
0392     for (i = 0; i < num_of_av_port; i++) {
0393         res = ps3av_cmd_av_audio_mute(1, &ps3av->av_port[i], mute);
0394         if (res < 0)
0395             return -1;
0396     }
0397     for (i = 0; i < num_of_opt_port; i++) {
0398         res = ps3av_cmd_audio_mute(1, &ps3av->opt_port[i], mute);
0399         if (res < 0)
0400             return -1;
0401     }
0402 
0403     return 0;
0404 }
0405 
0406 int ps3av_set_audio_mode(u32 ch, u32 fs, u32 word_bits, u32 format, u32 source)
0407 {
0408     struct ps3av_pkt_avb_param avb_param;
0409     int i, num_of_audio, vid, res;
0410     struct ps3av_pkt_audio_mode audio_mode;
0411     u32 len = 0;
0412 
0413     num_of_audio = ps3av->av_hw_conf.num_of_hdmi +
0414                ps3av->av_hw_conf.num_of_avmulti +
0415                ps3av->av_hw_conf.num_of_spdif;
0416 
0417     avb_param.num_of_video_pkt = 0;
0418     avb_param.num_of_audio_pkt = PS3AV_AVB_NUM_AUDIO;   /* always 0 */
0419     avb_param.num_of_av_video_pkt = 0;
0420     avb_param.num_of_av_audio_pkt = ps3av->av_hw_conf.num_of_hdmi;
0421 
0422     vid = video_mode_table[ps3av->ps3av_mode].vid;
0423 
0424     /* audio mute */
0425     ps3av_set_audio_mute(PS3AV_CMD_MUTE_ON);
0426 
0427     /* audio inactive */
0428     res = ps3av_cmd_audio_active(0, ps3av->audio_port);
0429     if (res < 0)
0430         dev_dbg(&ps3av->dev->core,
0431             "ps3av_cmd_audio_active OFF failed\n");
0432 
0433     /* audio_pkt */
0434     for (i = 0; i < num_of_audio; i++) {
0435         ps3av_cmd_set_audio_mode(&audio_mode, ps3av->av_port[i], ch,
0436                      fs, word_bits, format, source);
0437         if (i < ps3av->av_hw_conf.num_of_hdmi) {
0438             /* hdmi only */
0439             len += ps3av_cmd_set_av_audio_param(&avb_param.buf[len],
0440                                 ps3av->av_port[i],
0441                                 &audio_mode, vid);
0442         }
0443         /* audio_mode pkt should be sent separately */
0444         res = ps3av_cmd_audio_mode(&audio_mode);
0445         if (res < 0)
0446             dev_dbg(&ps3av->dev->core,
0447                 "ps3av_cmd_audio_mode failed, port:%x\n", i);
0448     }
0449 
0450     /* send command using avb pkt */
0451     len += offsetof(struct ps3av_pkt_avb_param, buf);
0452     res = ps3av_cmd_avb_param(&avb_param, len);
0453     if (res < 0)
0454         dev_dbg(&ps3av->dev->core, "ps3av_cmd_avb_param failed\n");
0455 
0456     /* audio mute */
0457     ps3av_set_audio_mute(PS3AV_CMD_MUTE_OFF);
0458 
0459     /* audio active */
0460     res = ps3av_cmd_audio_active(1, ps3av->audio_port);
0461     if (res < 0)
0462         dev_dbg(&ps3av->dev->core,
0463             "ps3av_cmd_audio_active ON failed\n");
0464 
0465     return 0;
0466 }
0467 EXPORT_SYMBOL_GPL(ps3av_set_audio_mode);
0468 
0469 static int ps3av_set_videomode(void)
0470 {
0471     /* av video mute */
0472     ps3av_set_av_video_mute(PS3AV_CMD_MUTE_ON);
0473 
0474     /* wake up ps3avd to do the actual video mode setting */
0475     schedule_work(&ps3av->work);
0476 
0477     return 0;
0478 }
0479 
0480 static void ps3av_set_videomode_packet(u32 id)
0481 {
0482     struct ps3av_pkt_avb_param avb_param;
0483     unsigned int i;
0484     u32 len = 0, av_video_cs;
0485     const struct avset_video_mode *video_mode;
0486     int res;
0487 
0488     video_mode = &video_mode_table[id & PS3AV_MODE_MASK];
0489 
0490     avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO; /* num of head */
0491     avb_param.num_of_audio_pkt = 0;
0492     avb_param.num_of_av_video_pkt = ps3av->av_hw_conf.num_of_hdmi +
0493                     ps3av->av_hw_conf.num_of_avmulti;
0494     avb_param.num_of_av_audio_pkt = 0;
0495 
0496     /* video_pkt */
0497     for (i = 0; i < avb_param.num_of_video_pkt; i++)
0498         len += ps3av_cmd_set_video_mode(&avb_param.buf[len],
0499                         ps3av->head[i], video_mode->vid,
0500                         video_mode->fmt, id);
0501     /* av_video_pkt */
0502     for (i = 0; i < avb_param.num_of_av_video_pkt; i++) {
0503         if (id & PS3AV_MODE_DVI || id & PS3AV_MODE_RGB)
0504             av_video_cs = RGB8;
0505         else
0506             av_video_cs = video_mode->cs;
0507 #ifndef PS3AV_HDMI_YUV
0508         if (ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_0 ||
0509             ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_1)
0510             av_video_cs = RGB8; /* use RGB for HDMI */
0511 #endif
0512         len += ps3av_cmd_set_av_video_cs(&avb_param.buf[len],
0513                          ps3av->av_port[i],
0514                          video_mode->vid, av_video_cs,
0515                          video_mode->aspect, id);
0516     }
0517     /* send command using avb pkt */
0518     len += offsetof(struct ps3av_pkt_avb_param, buf);
0519     res = ps3av_cmd_avb_param(&avb_param, len);
0520     if (res == PS3AV_STATUS_NO_SYNC_HEAD)
0521         printk(KERN_WARNING
0522                "%s: Command failed. Please try your request again.\n",
0523                __func__);
0524     else if (res)
0525         dev_dbg(&ps3av->dev->core, "ps3av_cmd_avb_param failed\n");
0526 }
0527 
0528 static void ps3av_set_videomode_cont(u32 id, u32 old_id)
0529 {
0530     static int vesa;
0531     int res;
0532 
0533     /* video signal off */
0534     ps3av_set_video_disable_sig();
0535 
0536     /*
0537      * AV backend needs non-VESA mode setting at least one time
0538      * when VESA mode is used.
0539      */
0540     if (vesa == 0 && (id & PS3AV_MODE_MASK) >= PS3AV_MODE_WXGA) {
0541         /* vesa mode */
0542         ps3av_set_videomode_packet(PS3AV_MODE_480P);
0543     }
0544     vesa = 1;
0545 
0546     /* Retail PS3 product doesn't support this */
0547     if (id & PS3AV_MODE_HDCP_OFF) {
0548         res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_HDCP_OFF);
0549         if (res == PS3AV_STATUS_UNSUPPORTED_HDMI_MODE)
0550             dev_dbg(&ps3av->dev->core, "Not supported\n");
0551         else if (res)
0552             dev_dbg(&ps3av->dev->core,
0553                 "ps3av_cmd_av_hdmi_mode failed\n");
0554     } else if (old_id & PS3AV_MODE_HDCP_OFF) {
0555         res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_MODE_NORMAL);
0556         if (res < 0 && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE)
0557             dev_dbg(&ps3av->dev->core,
0558                 "ps3av_cmd_av_hdmi_mode failed\n");
0559     }
0560 
0561     ps3av_set_videomode_packet(id);
0562 
0563     msleep(1500);
0564     /* av video mute */
0565     ps3av_set_av_video_mute(PS3AV_CMD_MUTE_OFF);
0566 }
0567 
0568 static void ps3avd(struct work_struct *work)
0569 {
0570     ps3av_set_videomode_cont(ps3av->ps3av_mode, ps3av->ps3av_mode_old);
0571     complete(&ps3av->done);
0572 }
0573 
0574 #define SHIFT_50    0
0575 #define SHIFT_60    4
0576 #define SHIFT_VESA  8
0577 
0578 static const struct {
0579     unsigned mask:19;
0580     unsigned id:4;
0581 } ps3av_preferred_modes[] = {
0582     { PS3AV_RESBIT_WUXGA      << SHIFT_VESA, PS3AV_MODE_WUXGA   },
0583     { PS3AV_RESBIT_1920x1080P << SHIFT_60,   PS3AV_MODE_1080P60 },
0584     { PS3AV_RESBIT_1920x1080P << SHIFT_50,   PS3AV_MODE_1080P50 },
0585     { PS3AV_RESBIT_1920x1080I << SHIFT_60,   PS3AV_MODE_1080I60 },
0586     { PS3AV_RESBIT_1920x1080I << SHIFT_50,   PS3AV_MODE_1080I50 },
0587     { PS3AV_RESBIT_SXGA       << SHIFT_VESA, PS3AV_MODE_SXGA    },
0588     { PS3AV_RESBIT_WXGA       << SHIFT_VESA, PS3AV_MODE_WXGA    },
0589     { PS3AV_RESBIT_1280x720P  << SHIFT_60,   PS3AV_MODE_720P60  },
0590     { PS3AV_RESBIT_1280x720P  << SHIFT_50,   PS3AV_MODE_720P50  },
0591     { PS3AV_RESBIT_720x480P   << SHIFT_60,   PS3AV_MODE_480P    },
0592     { PS3AV_RESBIT_720x576P   << SHIFT_50,   PS3AV_MODE_576P    },
0593 };
0594 
0595 static enum ps3av_mode_num ps3av_resbit2id(u32 res_50, u32 res_60,
0596                        u32 res_vesa)
0597 {
0598     unsigned int i;
0599     u32 res_all;
0600 
0601     /*
0602      * We mask off the resolution bits we care about and combine the
0603      * results in one bitfield, so make sure there's no overlap
0604      */
0605     BUILD_BUG_ON(PS3AV_RES_MASK_50 << SHIFT_50 &
0606              PS3AV_RES_MASK_60 << SHIFT_60);
0607     BUILD_BUG_ON(PS3AV_RES_MASK_50 << SHIFT_50 &
0608              PS3AV_RES_MASK_VESA << SHIFT_VESA);
0609     BUILD_BUG_ON(PS3AV_RES_MASK_60 << SHIFT_60 &
0610              PS3AV_RES_MASK_VESA << SHIFT_VESA);
0611     res_all = (res_50 & PS3AV_RES_MASK_50) << SHIFT_50 |
0612           (res_60 & PS3AV_RES_MASK_60) << SHIFT_60 |
0613           (res_vesa & PS3AV_RES_MASK_VESA) << SHIFT_VESA;
0614 
0615     if (!res_all)
0616         return 0;
0617 
0618     for (i = 0; i < ARRAY_SIZE(ps3av_preferred_modes); i++)
0619         if (res_all & ps3av_preferred_modes[i].mask)
0620             return ps3av_preferred_modes[i].id;
0621 
0622     return 0;
0623 }
0624 
0625 static enum ps3av_mode_num ps3av_hdmi_get_id(struct ps3av_info_monitor *info)
0626 {
0627     enum ps3av_mode_num id;
0628 
0629     if (safe_mode)
0630         return PS3AV_DEFAULT_HDMI_MODE_ID_REG_60;
0631 
0632     /* check native resolution */
0633     id = ps3av_resbit2id(info->res_50.native, info->res_60.native,
0634                  info->res_vesa.native);
0635     if (id) {
0636         pr_debug("%s: Using native mode %d\n", __func__, id);
0637         return id;
0638     }
0639 
0640     /* check supported resolutions */
0641     id = ps3av_resbit2id(info->res_50.res_bits, info->res_60.res_bits,
0642                  info->res_vesa.res_bits);
0643     if (id) {
0644         pr_debug("%s: Using supported mode %d\n", __func__, id);
0645         return id;
0646     }
0647 
0648     if (ps3av->region & PS3AV_REGION_60)
0649         id = PS3AV_DEFAULT_HDMI_MODE_ID_REG_60;
0650     else
0651         id = PS3AV_DEFAULT_HDMI_MODE_ID_REG_50;
0652     pr_debug("%s: Using default mode %d\n", __func__, id);
0653     return id;
0654 }
0655 
0656 static void ps3av_monitor_info_dump(
0657     const struct ps3av_pkt_av_get_monitor_info *monitor_info)
0658 {
0659     const struct ps3av_info_monitor *info = &monitor_info->info;
0660     const struct ps3av_info_audio *audio = info->audio;
0661     char id[sizeof(info->monitor_id)*3+1];
0662     int i;
0663 
0664     pr_debug("Monitor Info: size %u\n", monitor_info->send_hdr.size);
0665 
0666     pr_debug("avport: %02x\n", info->avport);
0667     for (i = 0; i < sizeof(info->monitor_id); i++)
0668         sprintf(&id[i*3], " %02x", info->monitor_id[i]);
0669     pr_debug("monitor_id: %s\n", id);
0670     pr_debug("monitor_type: %02x\n", info->monitor_type);
0671     pr_debug("monitor_name: %.*s\n", (int)sizeof(info->monitor_name),
0672          info->monitor_name);
0673 
0674     /* resolution */
0675     pr_debug("resolution_60: bits: %08x native: %08x\n",
0676          info->res_60.res_bits, info->res_60.native);
0677     pr_debug("resolution_50: bits: %08x native: %08x\n",
0678          info->res_50.res_bits, info->res_50.native);
0679     pr_debug("resolution_other: bits: %08x native: %08x\n",
0680          info->res_other.res_bits, info->res_other.native);
0681     pr_debug("resolution_vesa: bits: %08x native: %08x\n",
0682          info->res_vesa.res_bits, info->res_vesa.native);
0683 
0684     /* color space */
0685     pr_debug("color space    rgb: %02x\n", info->cs.rgb);
0686     pr_debug("color space yuv444: %02x\n", info->cs.yuv444);
0687     pr_debug("color space yuv422: %02x\n", info->cs.yuv422);
0688 
0689     /* color info */
0690     pr_debug("color info   red: X %04x Y %04x\n", info->color.red_x,
0691          info->color.red_y);
0692     pr_debug("color info green: X %04x Y %04x\n", info->color.green_x,
0693          info->color.green_y);
0694     pr_debug("color info  blue: X %04x Y %04x\n", info->color.blue_x,
0695          info->color.blue_y);
0696     pr_debug("color info white: X %04x Y %04x\n", info->color.white_x,
0697          info->color.white_y);
0698     pr_debug("color info gamma:  %08x\n", info->color.gamma);
0699 
0700     /* other info */
0701     pr_debug("supported_AI: %02x\n", info->supported_ai);
0702     pr_debug("speaker_info: %02x\n", info->speaker_info);
0703     pr_debug("num of audio: %02x\n", info->num_of_audio_block);
0704 
0705     /* audio block */
0706     for (i = 0; i < info->num_of_audio_block; i++) {
0707         pr_debug(
0708             "audio[%d] type: %02x max_ch: %02x fs: %02x sbit: %02x\n",
0709              i, audio->type, audio->max_num_of_ch, audio->fs,
0710              audio->sbit);
0711         audio++;
0712     }
0713 }
0714 
0715 static const struct ps3av_monitor_quirk {
0716     const char *monitor_name;
0717     u32 clear_60;
0718 } ps3av_monitor_quirks[] = {
0719     {
0720         .monitor_name   = "DELL 2007WFP",
0721         .clear_60   = PS3AV_RESBIT_1920x1080I
0722     }, {
0723         .monitor_name   = "L226WTQ",
0724         .clear_60   = PS3AV_RESBIT_1920x1080I |
0725                   PS3AV_RESBIT_1920x1080P
0726     }, {
0727         .monitor_name   = "SyncMaster",
0728         .clear_60   = PS3AV_RESBIT_1920x1080I
0729     }
0730 };
0731 
0732 static void ps3av_fixup_monitor_info(struct ps3av_info_monitor *info)
0733 {
0734     unsigned int i;
0735     const struct ps3av_monitor_quirk *quirk;
0736 
0737     for (i = 0; i < ARRAY_SIZE(ps3av_monitor_quirks); i++) {
0738         quirk = &ps3av_monitor_quirks[i];
0739         if (!strncmp(info->monitor_name, quirk->monitor_name,
0740                  sizeof(info->monitor_name))) {
0741             pr_info("%s: Applying quirk for %s\n", __func__,
0742                 quirk->monitor_name);
0743             info->res_60.res_bits &= ~quirk->clear_60;
0744             info->res_60.native &= ~quirk->clear_60;
0745             break;
0746         }
0747     }
0748 }
0749 
0750 static int ps3av_auto_videomode(struct ps3av_pkt_av_get_hw_conf *av_hw_conf)
0751 {
0752     int i, res, id = 0, dvi = 0, rgb = 0;
0753     struct ps3av_pkt_av_get_monitor_info monitor_info;
0754     struct ps3av_info_monitor *info;
0755 
0756     /* get mode id for hdmi */
0757     for (i = 0; i < av_hw_conf->num_of_hdmi && !id; i++) {
0758         res = ps3av_cmd_video_get_monitor_info(&monitor_info,
0759                                PS3AV_CMD_AVPORT_HDMI_0 +
0760                                i);
0761         if (res < 0)
0762             return -1;
0763 
0764         ps3av_monitor_info_dump(&monitor_info);
0765 
0766         info = &monitor_info.info;
0767         ps3av_fixup_monitor_info(info);
0768 
0769         switch (info->monitor_type) {
0770         case PS3AV_MONITOR_TYPE_DVI:
0771             dvi = PS3AV_MODE_DVI;
0772             fallthrough;
0773         case PS3AV_MONITOR_TYPE_HDMI:
0774             id = ps3av_hdmi_get_id(info);
0775             break;
0776         }
0777     }
0778 
0779     if (!id) {
0780         /* no HDMI interface or HDMI is off */
0781         if (ps3av->region & PS3AV_REGION_60)
0782             id = PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_60;
0783         else
0784             id = PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_50;
0785         if (ps3av->region & PS3AV_REGION_RGB)
0786             rgb = PS3AV_MODE_RGB;
0787         pr_debug("%s: Using avmulti mode %d\n", __func__, id);
0788     }
0789 
0790     return id | dvi | rgb;
0791 }
0792 
0793 static int ps3av_get_hw_conf(struct ps3av *ps3av)
0794 {
0795     int i, j, k, res;
0796     const struct ps3av_pkt_av_get_hw_conf *hw_conf;
0797 
0798     /* get av_hw_conf */
0799     res = ps3av_cmd_av_get_hw_conf(&ps3av->av_hw_conf);
0800     if (res < 0)
0801         return -1;
0802 
0803     hw_conf = &ps3av->av_hw_conf;
0804     pr_debug("av_h_conf: num of hdmi: %u\n", hw_conf->num_of_hdmi);
0805     pr_debug("av_h_conf: num of avmulti: %u\n", hw_conf->num_of_avmulti);
0806     pr_debug("av_h_conf: num of spdif: %u\n", hw_conf->num_of_spdif);
0807 
0808     for (i = 0; i < PS3AV_HEAD_MAX; i++)
0809         ps3av->head[i] = PS3AV_CMD_VIDEO_HEAD_A + i;
0810     for (i = 0; i < PS3AV_OPT_PORT_MAX; i++)
0811         ps3av->opt_port[i] = PS3AV_CMD_AVPORT_SPDIF_0 + i;
0812     for (i = 0; i < hw_conf->num_of_hdmi; i++)
0813         ps3av->av_port[i] = PS3AV_CMD_AVPORT_HDMI_0 + i;
0814     for (j = 0; j < hw_conf->num_of_avmulti; j++)
0815         ps3av->av_port[i + j] = PS3AV_CMD_AVPORT_AVMULTI_0 + j;
0816     for (k = 0; k < hw_conf->num_of_spdif; k++)
0817         ps3av->av_port[i + j + k] = PS3AV_CMD_AVPORT_SPDIF_0 + k;
0818 
0819     /* set all audio port */
0820     ps3av->audio_port = PS3AV_CMD_AUDIO_PORT_HDMI_0
0821         | PS3AV_CMD_AUDIO_PORT_HDMI_1
0822         | PS3AV_CMD_AUDIO_PORT_AVMULTI_0
0823         | PS3AV_CMD_AUDIO_PORT_SPDIF_0 | PS3AV_CMD_AUDIO_PORT_SPDIF_1;
0824 
0825     return 0;
0826 }
0827 
0828 /* set mode using id */
0829 int ps3av_set_video_mode(int id)
0830 {
0831     int size;
0832     u32 option;
0833 
0834     size = ARRAY_SIZE(video_mode_table);
0835     if ((id & PS3AV_MODE_MASK) > size - 1 || id < 0) {
0836         dev_dbg(&ps3av->dev->core, "%s: error id :%d\n", __func__, id);
0837         return -EINVAL;
0838     }
0839 
0840     /* auto mode */
0841     option = id & ~PS3AV_MODE_MASK;
0842     if ((id & PS3AV_MODE_MASK) == PS3AV_MODE_AUTO) {
0843         id = ps3av_auto_videomode(&ps3av->av_hw_conf);
0844         if (id < 1) {
0845             printk(KERN_ERR "%s: invalid id :%d\n", __func__, id);
0846             return -EINVAL;
0847         }
0848         id |= option;
0849     }
0850 
0851     /* set videomode */
0852     wait_for_completion(&ps3av->done);
0853     ps3av->ps3av_mode_old = ps3av->ps3av_mode;
0854     ps3av->ps3av_mode = id;
0855     if (ps3av_set_videomode())
0856         ps3av->ps3av_mode = ps3av->ps3av_mode_old;
0857 
0858     return 0;
0859 }
0860 EXPORT_SYMBOL_GPL(ps3av_set_video_mode);
0861 
0862 int ps3av_get_auto_mode(void)
0863 {
0864     return ps3av_auto_videomode(&ps3av->av_hw_conf);
0865 }
0866 EXPORT_SYMBOL_GPL(ps3av_get_auto_mode);
0867 
0868 int ps3av_get_mode(void)
0869 {
0870     return ps3av ? ps3av->ps3av_mode : 0;
0871 }
0872 EXPORT_SYMBOL_GPL(ps3av_get_mode);
0873 
0874 /* get resolution by video_mode */
0875 int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres)
0876 {
0877     int size;
0878 
0879     id = id & PS3AV_MODE_MASK;
0880     size = ARRAY_SIZE(video_mode_table);
0881     if (id > size - 1 || id < 0) {
0882         printk(KERN_ERR "%s: invalid mode %d\n", __func__, id);
0883         return -EINVAL;
0884     }
0885     *xres = video_mode_table[id].x;
0886     *yres = video_mode_table[id].y;
0887     return 0;
0888 }
0889 EXPORT_SYMBOL_GPL(ps3av_video_mode2res);
0890 
0891 /* mute */
0892 int ps3av_video_mute(int mute)
0893 {
0894     return ps3av_set_av_video_mute(mute ? PS3AV_CMD_MUTE_ON
0895                         : PS3AV_CMD_MUTE_OFF);
0896 }
0897 EXPORT_SYMBOL_GPL(ps3av_video_mute);
0898 
0899 /* mute analog output only */
0900 int ps3av_audio_mute_analog(int mute)
0901 {
0902     int i, res;
0903 
0904     for (i = 0; i < ps3av->av_hw_conf.num_of_avmulti; i++) {
0905         res = ps3av_cmd_av_audio_mute(1,
0906             &ps3av->av_port[i + ps3av->av_hw_conf.num_of_hdmi],
0907             mute);
0908         if (res < 0)
0909             return -1;
0910     }
0911     return 0;
0912 }
0913 EXPORT_SYMBOL_GPL(ps3av_audio_mute_analog);
0914 
0915 int ps3av_audio_mute(int mute)
0916 {
0917     return ps3av_set_audio_mute(mute ? PS3AV_CMD_MUTE_ON
0918                      : PS3AV_CMD_MUTE_OFF);
0919 }
0920 EXPORT_SYMBOL_GPL(ps3av_audio_mute);
0921 
0922 static int ps3av_probe(struct ps3_system_bus_device *dev)
0923 {
0924     int res;
0925     int id;
0926 
0927     dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
0928     dev_dbg(&dev->core, "  timeout=%d\n", timeout);
0929 
0930     if (ps3av) {
0931         dev_err(&dev->core, "Only one ps3av device is supported\n");
0932         return -EBUSY;
0933     }
0934 
0935     ps3av = kzalloc(sizeof(*ps3av), GFP_KERNEL);
0936     if (!ps3av)
0937         return -ENOMEM;
0938 
0939     mutex_init(&ps3av->mutex);
0940     ps3av->ps3av_mode = PS3AV_MODE_AUTO;
0941     ps3av->dev = dev;
0942 
0943     INIT_WORK(&ps3av->work, ps3avd);
0944     init_completion(&ps3av->done);
0945     complete(&ps3av->done);
0946 
0947     switch (ps3_os_area_get_av_multi_out()) {
0948     case PS3_PARAM_AV_MULTI_OUT_NTSC:
0949         ps3av->region = PS3AV_REGION_60;
0950         break;
0951     case PS3_PARAM_AV_MULTI_OUT_PAL_YCBCR:
0952     case PS3_PARAM_AV_MULTI_OUT_SECAM:
0953         ps3av->region = PS3AV_REGION_50;
0954         break;
0955     case PS3_PARAM_AV_MULTI_OUT_PAL_RGB:
0956         ps3av->region = PS3AV_REGION_50 | PS3AV_REGION_RGB;
0957         break;
0958     default:
0959         ps3av->region = PS3AV_REGION_60;
0960         break;
0961     }
0962 
0963     /* init avsetting modules */
0964     res = ps3av_cmd_init();
0965     if (res < 0)
0966         printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __func__,
0967                res);
0968 
0969     ps3av_get_hw_conf(ps3av);
0970 
0971 #ifdef CONFIG_FB
0972     if (fb_mode_option && !strcmp(fb_mode_option, "safe"))
0973         safe_mode = 1;
0974 #endif /* CONFIG_FB */
0975     id = ps3av_auto_videomode(&ps3av->av_hw_conf);
0976     if (id < 0) {
0977         printk(KERN_ERR "%s: invalid id :%d\n", __func__, id);
0978         res = -EINVAL;
0979         goto fail;
0980     }
0981 
0982     safe_mode = 0;
0983 
0984     mutex_lock(&ps3av->mutex);
0985     ps3av->ps3av_mode = id;
0986     mutex_unlock(&ps3av->mutex);
0987 
0988     dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
0989 
0990     return 0;
0991 
0992 fail:
0993     kfree(ps3av);
0994     ps3av = NULL;
0995     return res;
0996 }
0997 
0998 static int ps3av_remove(struct ps3_system_bus_device *dev)
0999 {
1000     dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
1001     if (ps3av) {
1002         ps3av_cmd_fin();
1003         flush_work(&ps3av->work);
1004         kfree(ps3av);
1005         ps3av = NULL;
1006     }
1007 
1008     dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
1009     return 0;
1010 }
1011 
1012 static void ps3av_shutdown(struct ps3_system_bus_device *dev)
1013 {
1014     dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
1015     ps3av_remove(dev);
1016     dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
1017 }
1018 
1019 static struct ps3_vuart_port_driver ps3av_driver = {
1020     .core.match_id = PS3_MATCH_ID_AV_SETTINGS,
1021     .core.core.name = "ps3_av",
1022     .probe = ps3av_probe,
1023     .remove = ps3av_remove,
1024     .shutdown = ps3av_shutdown,
1025 };
1026 
1027 static int __init ps3av_module_init(void)
1028 {
1029     int error;
1030 
1031     if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
1032         return -ENODEV;
1033 
1034     pr_debug(" -> %s:%d\n", __func__, __LINE__);
1035 
1036     error = ps3_vuart_port_driver_register(&ps3av_driver);
1037     if (error) {
1038         printk(KERN_ERR
1039                "%s: ps3_vuart_port_driver_register failed %d\n",
1040                __func__, error);
1041         return error;
1042     }
1043 
1044     pr_debug(" <- %s:%d\n", __func__, __LINE__);
1045     return error;
1046 }
1047 
1048 static void __exit ps3av_module_exit(void)
1049 {
1050     pr_debug(" -> %s:%d\n", __func__, __LINE__);
1051     ps3_vuart_port_driver_unregister(&ps3av_driver);
1052     pr_debug(" <- %s:%d\n", __func__, __LINE__);
1053 }
1054 
1055 subsys_initcall(ps3av_module_init);
1056 module_exit(ps3av_module_exit);
1057 
1058 MODULE_LICENSE("GPL v2");
1059 MODULE_DESCRIPTION("PS3 AV Settings Driver");
1060 MODULE_AUTHOR("Sony Computer Entertainment Inc.");
1061 MODULE_ALIAS(PS3_MODULE_ALIAS_AV_SETTINGS);