Skip to content

Commit

Permalink
video: mxc-hdmi: add fractional modes, adapt pixclock.
Browse files Browse the repository at this point in the history
  • Loading branch information
mk01 committed Dec 2, 2015
1 parent 25e8a8a commit 9b71359
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 23 deletions.
4 changes: 2 additions & 2 deletions drivers/mfd/mxc-hdmi-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -538,11 +538,11 @@ void hdmi_init_clk_regenerator(void)
}
EXPORT_SYMBOL(hdmi_init_clk_regenerator);

void hdmi_clk_regenerator_update_pixel_clock(u32 pixclock, u32 vmode)
void hdmi_clk_regenerator_update_pixel_clock(u32 pixclock, struct fb_info *fbi)
{

/* Translate pixel clock in ps (pico seconds) to Hz */
pixel_clk_rate = mxcPICOS2KHZ(pixclock, vmode) * 1000UL;
pixel_clk_rate = mxcPICOS2KHZ(pixclock, fbi) * 1000UL;
hdmi_set_clk_regenerator();
}
EXPORT_SYMBOL(hdmi_clk_regenerator_update_pixel_clock);
Expand Down
28 changes: 28 additions & 0 deletions drivers/video/fbsysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,33 @@ static ssize_t show_blank(struct device *device,
return 0;
}

static ssize_t store_ntsc(struct device *device,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct fb_info *fb_info = dev_get_drvdata(device);
char *last = NULL;
int ntsc_mode = simple_strtoul(buf, &last, 0);

if (ntsc_mode)
fb_info->flags |= FBINFO_TIMING_NTSC;
else
fb_info->flags &= ~FBINFO_TIMING_NTSC;

return count;
}

static ssize_t show_ntsc(struct device *device,
struct device_attribute *attr, char *buf)
{
struct fb_info *fb_info = dev_get_drvdata(device);

if (fb_info->flags & FBINFO_TIMING_NTSC)
return snprintf(buf, PAGE_SIZE, "ntsc timings active\n");

return snprintf(buf, PAGE_SIZE, "ntsc timings disabled\n");
}

static ssize_t store_console(struct device *device,
struct device_attribute *attr,
const char *buf, size_t count)
Expand Down Expand Up @@ -510,6 +537,7 @@ static struct device_attribute device_attrs[] = {
__ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console),
__ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor),
__ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode),
__ATTR(ntsc_mode, S_IRUGO|S_IWUSR, show_ntsc, store_ntsc),
__ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes),
__ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan),
__ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual),
Expand Down
2 changes: 1 addition & 1 deletion drivers/video/mxc/mxc_edid.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ const struct fb_videomode mxc_cea_mode[64] = {
};

#define FB_VMODE_MASK_SIMPLE (FB_VMODE_NONINTERLACED | FB_VMODE_INTERLACED | \
FB_VMODE_FRACTIONAL | FB_VMODE_ASPECT_MASK)
FB_VMODE_ASPECT_MASK)

int mxc_fb_mode_is_equal_res(const struct fb_videomode *mode1,
const struct fb_videomode *mode2)
Expand Down
35 changes: 21 additions & 14 deletions drivers/video/mxc/mxc_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,18 +253,25 @@ static inline int cpu_is_imx6dl(struct mxc_hdmi *hdmi)
{
return hdmi->cpu_type == IMX6DL_HDMI;
}
#ifdef DEBUG
static void dump_fb_videomode(struct fb_videomode *m)

static inline void get_refresh_str(struct fb_videomode *m, char *refresh, bool ntsc_mode)
{
snprintf(refresh, 10, "%u.%uHz", m->refresh - (int)ntsc_mode,
m->refresh * (int)(ntsc_mode ? 999 : 1000) % 1000);
}

static void dump_fb_videomode(struct fb_videomode *m, struct mxc_hdmi *hdmi)
{
pr_debug("fb_videomode = %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
m->refresh, m->xres, m->yres, m->pixclock, m->left_margin,
char refresh[10];
bool ntsc = hdmi->fbi && (hdmi->fbi->flags & FBINFO_TIMING_NTSC) && try_ntsc(hdmi->fbi->mode);

get_refresh_str(m, refresh, ntsc);
pr_debug("fb_videomode = %ux%u%c-%s (%ups/%lukHz) %u %u %u %u %u %u %u %u %u\n",
m->xres, m->yres, m->vmode & FB_VMODE_INTERLACED ? 'i' : 'p',
refresh, m->pixclock, mxcPICOS2KHZ(m->pixclock, hdmi->fbi), m->left_margin,
m->right_margin, m->upper_margin, m->lower_margin,
m->hsync_len, m->vsync_len, m->sync, m->vmode, m->flag);
}
#else
static void dump_fb_videomode(struct fb_videomode *m)
{}
#endif

static ssize_t mxc_hdmi_show_name(struct device *dev,
struct device_attribute *attr, char *buf)
Expand Down Expand Up @@ -1557,7 +1564,7 @@ static void hdmi_av_composer(struct mxc_hdmi *hdmi)
vmode->mHSyncPolarity = ((fb_mode.sync & FB_SYNC_HOR_HIGH_ACT) != 0);
vmode->mVSyncPolarity = ((fb_mode.sync & FB_SYNC_VERT_HIGH_ACT) != 0);
vmode->mInterlaced = ((fb_mode.vmode & FB_VMODE_INTERLACED) != 0);
vmode->mPixelClock = (u32) (mxcPICOS2KHZ(fb_mode.pixclock, fb_mode.vmode) * 1000UL);
vmode->mPixelClock = (u32) (mxcPICOS2KHZ(fb_mode.pixclock, fbi) * 1000UL);

dev_dbg(&hdmi->pdev->dev, "final pixclk = %d\n", vmode->mPixelClock);

Expand All @@ -1574,7 +1581,7 @@ static void hdmi_av_composer(struct mxc_hdmi *hdmi)
HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH :
HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW);

if (hdmi->vic == 39)
if (fbi->flags & FBINFO_TIMING_NTSC)
inv_val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH;
else
inv_val |= (vmode->mInterlaced ?
Expand Down Expand Up @@ -2043,7 +2050,7 @@ static void mxc_hdmi_set_mode(struct mxc_hdmi *hdmi, int edid_status)
}

fb_var_to_videomode(&m, &var);
dump_fb_videomode(&m);
dump_fb_videomode(&m, hdmi);
mode = mxc_fb_find_nearest_mode(&m, &hdmi->fbi->modelist, false);

if (mode) {
Expand Down Expand Up @@ -2143,7 +2150,7 @@ static int mxc_hdmi_power_on(struct mxc_dispdrv_handle *disp,
{
struct mxc_hdmi *hdmi = mxc_dispdrv_getdata(disp);
mxc_hdmi_phy_init(hdmi);
hdmi_clk_regenerator_update_pixel_clock(fbi->var.pixclock, fbi->var.vmode);
hdmi_clk_regenerator_update_pixel_clock(fbi->var.pixclock, fbi);
return 0;
}

Expand Down Expand Up @@ -2334,7 +2341,7 @@ static void mxc_hdmi_setup(struct mxc_hdmi *hdmi, unsigned long event)
dev_dbg(&hdmi->pdev->dev, "%s\n", __func__);

fb_var_to_videomode(&m, &hdmi->fbi->var);
dump_fb_videomode(&m);
dump_fb_videomode(&m, hdmi);

dev_dbg(&hdmi->pdev->dev, "%s - video mode changed\n", __func__);

Expand Down Expand Up @@ -2817,7 +2824,7 @@ static int mxc_hdmi_disp_init(struct mxc_dispdrv_handle *disp,
pr_err("%s: could not find mode in modelist\n", __func__);
return -1;
}
dump_fb_videomode((struct fb_videomode *)mode);
dump_fb_videomode((struct fb_videomode *)mode, hdmi);
/* Save default video mode */
memcpy(&hdmi->default_mode, mode, sizeof(struct fb_videomode));

Expand Down
5 changes: 3 additions & 2 deletions drivers/video/mxc/mxc_ipuv3_fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#include <linux/uaccess.h>

#include "mxc_dispdrv.h"
#include <video/mxc_edid.h>

/*
* Driver name
Expand Down Expand Up @@ -644,10 +645,10 @@ static int mxcfb_set_par(struct fb_info *fbi)
sig_cfg.clkidle_en = true;

dev_dbg(fbi->device, "pixclock = %ul Hz\n",
(u32) (PICOS2KHZ(fbi->var.pixclock) * 1000UL));
(u32) (mxcPICOS2KHZ(fbi->var.pixclock, fbi) * 1000UL));

if (ipu_init_sync_panel(mxc_fbi->ipu, mxc_fbi->ipu_di,
(PICOS2KHZ(fbi->var.pixclock)) * 1000UL,
(mxcPICOS2KHZ(fbi->var.pixclock, fbi)) * 1000UL,
fbi->var.xres, fbi->var.yres,
out_pixel_fmt,
fbi->var.left_margin,
Expand Down
1 change: 1 addition & 0 deletions include/linux/fb.h
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ struct fb_tile_ops {
#define FBINFO_MISC_USEREVENT 0x10000 /* event request
from userspace */
#define FBINFO_MISC_TILEBLITTING 0x20000 /* use tile blitting */
#define FBINFO_TIMING_NTSC 0x40000 /* use NTSC timings */

/* A driver may set this flag to indicate that it does want a set_par to be
* called every time when fbcon_switch is executed. The advantage is that with
Expand Down
2 changes: 1 addition & 1 deletion include/linux/mfd/mxc-hdmi-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ unsigned int hdmi_irq_disable(int irq);
void hdmi_set_sample_rate(unsigned int rate);
void hdmi_set_dma_mode(unsigned int dma_running);
void hdmi_init_clk_regenerator(void);
void hdmi_clk_regenerator_update_pixel_clock(u32 pixclock, u32 vmode);
void hdmi_clk_regenerator_update_pixel_clock(u32 pixclock, struct fb_info *fbi);

void hdmi_set_edid_cfg(int edid_status, struct mxc_edid_cfg *cfg);
int hdmi_get_edid_cfg(struct mxc_edid_cfg *cfg);
Expand Down
1 change: 0 additions & 1 deletion include/uapi/linux/fb.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,6 @@ struct fb_bitfield {
#define FB_VMODE_INTERLACED 1 /* interlaced */
#define FB_VMODE_DOUBLE 2 /* double scan */
#define FB_VMODE_ODD_FLD_FIRST 4 /* interlaced: top line first */
#define FB_VMODE_FRACTIONAL 8
#define FB_VMODE_MASK 255

#define FB_VMODE_YWRAP 256 /* ywrap instead of panning */
Expand Down
21 changes: 19 additions & 2 deletions include/video/mxc_edid.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,25 @@ struct mxc_edid_cfg {
u8 speaker_alloc;
};

static inline unsigned long mxcPICOS2KHZ(u32 pixclock, u32 vmode) {
u32 x = (1000000000UL / (pixclock) * 1000 / ((vmode & FB_VMODE_FRACTIONAL) ? 1001 : 1000));
static inline bool try_ntsc(const struct fb_videomode *mode)
{
if (!mode)
return false;

switch (mode->refresh) {
case 24:
case 30:
case 60:
return true;
default:
return false;
}
}

static inline unsigned long mxcPICOS2KHZ(u32 pixclock, struct fb_info *fbi) {
bool ntsc = fbi && (fbi->flags & FBINFO_TIMING_NTSC) && try_ntsc(fbi->mode);

u32 x = (1000000000UL / (pixclock) * 1000 / (ntsc ? 1001 : 1000));
return x + ((1000000000UL % x) > (x / 2) ? 1 : 0);
}

Expand Down

0 comments on commit 9b71359

Please sign in to comment.