enum mfb_index {
PLANE0 = 0, /* Plane 0, only one AOI that fills the screen */
PLANE1_AOI0, /* Plane 1, first AOI */
PLANE1_AOI1, /* Plane 1, second AOI */
PLANE2_AOI0, /* Plane 2, first AOI */
PLANE2_AOI1, /* Plane 2, second AOI */
};
struct mfb_info { enum mfb_index index; char *id; int registered; unsignedlong pseudo_palette[16]; struct diu_ad *ad; unsignedchar g_alpha; unsignedint count; int x_aoi_d; /* aoi display x offset to physical screen */ int y_aoi_d; /* aoi display y offset to physical screen */ struct fsl_diu_data *parent;
};
/** * struct fsl_diu_data - per-DIU data structure * @dma_addr: DMA address of this structure * @fsl_diu_info: fb_info objects, one per AOI * @dev_attr: sysfs structure * @irq: IRQ * @monitor_port: the monitor port this DIU is connected to * @diu_reg: pointer to the DIU hardware registers * @reg_lock: spinlock for register access * @dummy_aoi: video buffer for the 4x4 32-bit dummy AOI * dummy_ad: DIU Area Descriptor for the dummy AOI * @ad[]: Area Descriptors for each real AOI * @gamma: gamma color table * @cursor: hardware cursor data * @blank_cursor: blank cursor for hiding cursor * @next_cursor: scratch space to build load cursor * @edid_data: EDID information buffer * @has_edid: whether or not the EDID buffer is valid * * This data structure must be allocated with 32-byte alignment, so that the * internal fields can be aligned properly.
*/ struct fsl_diu_data {
dma_addr_t dma_addr; struct fb_info fsl_diu_info[NUM_AOIS]; struct mfb_info mfb[NUM_AOIS]; struct device_attribute dev_attr; unsignedint irq; enum fsl_diu_monitor_port monitor_port; struct diu __iomem *diu_reg;
spinlock_t reg_lock;
u8 dummy_aoi[4 * 4 * 4]; struct diu_ad dummy_ad __aligned(8); struct diu_ad ad[NUM_AOIS] __aligned(8);
u8 gamma[256 * 3] __aligned(32); /* It's easier to parse the cursor data as little-endian */
__le16 cursor[MAX_CURS * MAX_CURS] __aligned(32); /* Blank cursor data -- used to hide the cursor */
__le16 blank_cursor[MAX_CURS * MAX_CURS] __aligned(32); /* Scratch cursor data -- used to build new cursor */
__le16 next_cursor[MAX_CURS * MAX_CURS] __aligned(32);
uint8_t edid_data[EDID_LENGTH]; bool has_edid;
} __aligned(32);
/* Determine the DMA address of a member of the fsl_diu_data structure */ #define DMA_ADDR(p, f) ((p)->dma_addr + offsetof(struct fsl_diu_data, f))
/** * fsl_diu_name_to_port - convert a port name to a monitor port enum * * Takes the name of a monitor port ("dvi", "lvds", or "dlvds") and returns * the enum fsl_diu_monitor_port that corresponds to that string. * * For compatibility with older versions, a number ("0", "1", or "2") is also * supported. * * If the string is unknown, DVI is assumed. * * If the particular port is not supported by the platform, another port * (platform-specific) is chosen instead.
*/ staticenum fsl_diu_monitor_port fsl_diu_name_to_port(constchar *s)
{ enum fsl_diu_monitor_port port = FSL_DIU_PORT_DVI; unsignedlong val;
if (s) { if (!kstrtoul(s, 10, &val) && (val <= 2))
port = (enum fsl_diu_monitor_port) val; elseif (strncmp(s, "lvds", 4) == 0)
port = FSL_DIU_PORT_LVDS; elseif (strncmp(s, "dlvds", 5) == 0)
port = FSL_DIU_PORT_DLVDS;
}
if (diu_ops.valid_monitor_port)
port = diu_ops.valid_monitor_port(port);
return port;
}
/* * Workaround for failed writing desc register of planes. * Needed with MPC5121 DIU rev 2.0 silicon.
*/ staticvoid wr_reg_wa(u32 *reg, u32 val)
{ do {
out_be32(reg, val);
} while (in_be32(reg) != val);
}
switch (mfbi->index) { case PLANE0:
wr_reg_wa(&hw->desc[0], 0); break; case PLANE1_AOI0:
cmfbi = &data->mfb[2]; if (cmfbi->count > 0) /* AOI1 is open */
wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr); /* move AOI1 to the first */ else/* AOI1 was closed */
wr_reg_wa(&hw->desc[1], data->dummy_ad.paddr); /* close AOI 0 */ break; case PLANE2_AOI0:
cmfbi = &data->mfb[4]; if (cmfbi->count > 0) /* AOI1 is open */
wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr); /* move AOI1 to the first */ else/* AOI1 was closed */
wr_reg_wa(&hw->desc[2], data->dummy_ad.paddr); /* close AOI 0 */ break; case PLANE1_AOI1:
pmfbi = &data->mfb[1]; if (hw->desc[1] != ad->paddr) { /* AOI1 is not the first in the chain */ if (pmfbi->count > 0) /* AOI0 is open, must be the first */
pmfbi->ad->next_ad = 0;
} else/* AOI1 is the first in the chain */
wr_reg_wa(&hw->desc[1], data->dummy_ad.paddr); /* close AOI 1 */ break; case PLANE2_AOI1:
pmfbi = &data->mfb[3]; if (hw->desc[2] != ad->paddr) { /* AOI1 is not the first in the chain */ if (pmfbi->count > 0) /* AOI0 is open, must be the first */
pmfbi->ad->next_ad = 0;
} else/* AOI1 is the first in the chain */
wr_reg_wa(&hw->desc[2], data->dummy_ad.paddr); /* close AOI 1 */ break;
}
}
if (mfbi->x_aoi_d < 0)
mfbi->x_aoi_d = 0; if (mfbi->y_aoi_d < 0)
mfbi->y_aoi_d = 0; switch (index) { case PLANE0: if (mfbi->x_aoi_d != 0)
mfbi->x_aoi_d = 0; if (mfbi->y_aoi_d != 0)
mfbi->y_aoi_d = 0; break; case PLANE1_AOI0: case PLANE2_AOI0:
lower_aoi_mfbi = data->fsl_diu_info[index+1].par;
lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0; if (var->xres > base_plane_width)
var->xres = base_plane_width; if ((mfbi->x_aoi_d + var->xres) > base_plane_width)
mfbi->x_aoi_d = base_plane_width - var->xres;
if (lower_aoi_is_open)
available_height = lower_aoi_mfbi->y_aoi_d; else
available_height = base_plane_height; if (var->yres > available_height)
var->yres = available_height; if ((mfbi->y_aoi_d + var->yres) > available_height)
mfbi->y_aoi_d = available_height - var->yres; break; case PLANE1_AOI1: case PLANE2_AOI1:
upper_aoi_mfbi = data->fsl_diu_info[index-1].par;
upper_aoi_height = data->fsl_diu_info[index-1].var.yres;
upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height;
upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0; if (var->xres > base_plane_width)
var->xres = base_plane_width; if ((mfbi->x_aoi_d + var->xres) > base_plane_width)
mfbi->x_aoi_d = base_plane_width - var->xres; if (mfbi->y_aoi_d < 0)
mfbi->y_aoi_d = 0; if (upper_aoi_is_open) { if (mfbi->y_aoi_d < upper_aoi_bottom)
mfbi->y_aoi_d = upper_aoi_bottom;
available_height = base_plane_height
- upper_aoi_bottom;
} else
available_height = base_plane_height; if (var->yres > available_height)
var->yres = available_height; if ((mfbi->y_aoi_d + var->yres) > base_plane_height)
mfbi->y_aoi_d = base_plane_height - var->yres; break;
}
} /* * Checks to see if the hardware supports the state requested by var passed * in. This function does not alter the hardware state! If the var passed in * is slightly off by what the hardware can support then we alter the var * PASSED in to what we can do. If the hardware doesn't support mode change * a -EINVAL will be returned by the upper layers.
*/ staticint fsl_diu_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{ if (var->xres_virtual < var->xres)
var->xres_virtual = var->xres; if (var->yres_virtual < var->yres)
var->yres_virtual = var->yres;
#ifndef CONFIG_PPC_MPC512x /* * The PLUT register is defined differently on the MPC5121 than it * is on other SOCs. Unfortunately, there's no documentation that * explains how it's supposed to be programmed, so for now, we leave * it at the default value on the MPC5121. * * For other SOCs, program it for the highest priority, which will * reduce the chance of underrun. Technically, we should scale the * priority to match the screen resolution, but doing that properly * requires delicate fine-tuning for each use-case.
*/
out_be32(&hw->plut, 0x01F5F666); #endif
/* * Using the fb_var_screeninfo in fb_info we set the aoi of this * particular framebuffer. It is a light version of fsl_diu_set_par.
*/ staticint fsl_diu_set_aoi(struct fb_info *info)
{ struct fb_var_screeninfo *var = &info->var; struct mfb_info *mfbi = info->par; struct diu_ad *ad = mfbi->ad;
/* AOI should not be greater than display size */
ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset);
ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d); return 0;
}
/** * fsl_diu_get_pixel_format: return the pixel format for a given color depth * * The pixel format is a 32-bit value that determine which bits in each * pixel are to be used for each color. This is the default function used * if the platform does not define its own version.
*/ static u32 fsl_diu_get_pixel_format(unsignedint bits_per_pixel)
{ #define PF_BYTE_F 0x10000000 #define PF_ALPHA_C_MASK 0x0E000000 #define PF_ALPHA_C_SHIFT 25 #define PF_BLUE_C_MASK 0x01800000 #define PF_BLUE_C_SHIFT 23 #define PF_GREEN_C_MASK 0x00600000 #define PF_GREEN_C_SHIFT 21 #define PF_RED_C_MASK 0x00180000 #define PF_RED_C_SHIFT 19 #define PF_PALETTE 0x00040000 #define PF_PIXEL_S_MASK 0x00030000 #define PF_PIXEL_S_SHIFT 16 #define PF_COMP_3_MASK 0x0000F000 #define PF_COMP_3_SHIFT 12 #define PF_COMP_2_MASK 0x00000F00 #define PF_COMP_2_SHIFT 8 #define PF_COMP_1_MASK 0x000000F0 #define PF_COMP_1_SHIFT 4 #define PF_COMP_0_MASK 0x0000000F #define PF_COMP_0_SHIFT 0
/* * Copies a cursor image from user space to the proper place in driver * memory so that the hardware can display the cursor image. * * Cursor data is represented as a sequence of 'width' bits packed into bytes. * That is, the first 8 bits are in the first byte, the second 8 bits in the * second byte, and so on. Therefore, the each row of the cursor is (width + * 7) / 8 bytes of 'data' * * The DIU only supports cursors up to 32x32 (MAX_CURS). We reject cursors * larger than this, so we already know that 'width' <= 32. Therefore, we can * simplify our code by using a 32-bit big-endian integer ("line") to read in * a single line of pixels, and only look at the top 'width' bits of that * integer. * * This could result in an unaligned 32-bit read. For example, if the cursor * is 24x24, then the first three bytes of 'image' contain the pixel data for * the top line of the cursor. We do a 32-bit read of 'image', but we look * only at the top 24 bits. Then we increment 'image' by 3 bytes. The next * read is unaligned. The only problem is that we might read past the end of * 'image' by 1-3 bytes, but that should not cause any problems.
*/ staticvoid fsl_diu_load_cursor_image(struct fb_info *info, constvoid *image, uint16_t bg, uint16_t fg, unsignedint width, unsignedint height)
{ struct mfb_info *mfbi = info->par; struct fsl_diu_data *data = mfbi->parent;
__le16 *cursor = data->cursor;
__le16 _fg = cpu_to_le16(fg);
__le16 _bg = cpu_to_le16(bg); unsignedint h, w;
for (h = 0; h < height; h++) {
uint32_t mask = 1 << 31;
uint32_t line = be32_to_cpup(image);
for (w = 0; w < width; w++) {
cursor[w] = (line & mask) ? _fg : _bg;
mask >>= 1;
}
/* * Set a hardware cursor. The image data for the cursor is passed via the * fb_cursor object.
*/ staticint fsl_diu_cursor(struct fb_info *info, struct fb_cursor *cursor)
{ struct mfb_info *mfbi = info->par; struct fsl_diu_data *data = mfbi->parent; struct diu __iomem *hw = data->diu_reg;
if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS) return -EINVAL;
/* The cursor size has changed */ if (cursor->set & FB_CUR_SETSIZE) { /* * The DIU cursor is a fixed size, so when we get this * message, instead of resizing the cursor, we just clear * all the image data, in expectation of new data. However, * in tests this control does not appear to be normally * called.
*/
memset(data->cursor, 0, sizeof(data->cursor));
}
/* The cursor position has changed (cursor->image.dx|dy) */ if (cursor->set & FB_CUR_SETPOS) {
uint32_t xx, yy;
/* Use 32-bit operations on the data to improve performance */
image = (uint32_t *)data->next_cursor;
source = (uint32_t *)cursor->image.data;
mask = (uint32_t *)cursor->mask;
if (cursor->rop == ROP_XOR) for (i = 0; i < image_words; i++)
image[i] = source[i] ^ mask[i]; else for (i = 0; i < image_words; i++)
image[i] = source[i] & mask[i];
/* * Show or hide the cursor. The cursor data is always stored in the * 'cursor' memory block, and the actual cursor position is always in * the DIU's CURS_POS register. To hide the cursor, we redirect the * CURSOR register to a blank cursor. The show the cursor, we * redirect the CURSOR register to the real cursor data.
*/ if (cursor->enable)
out_be32(&hw->cursor, DMA_ADDR(data, cursor)); else
out_be32(&hw->cursor, DMA_ADDR(data, blank_cursor));
return 0;
}
/* * Using the fb_var_screeninfo in fb_info we set the resolution of this * particular framebuffer. This function alters the fb_fix_screeninfo stored * in fb_info. It does not alter var in fb_info since we are using that * data. This means we depend on the data in var inside fb_info to be * supported by the hardware. fsl_diu_check_var is always called before * fsl_diu_set_par to ensure this.
*/ staticint fsl_diu_set_par(struct fb_info *info)
{ unsignedlong len; struct fb_var_screeninfo *var = &info->var; struct mfb_info *mfbi = info->par; struct fsl_diu_data *data = mfbi->parent; struct diu_ad *ad = mfbi->ad; struct diu __iomem *hw;
hw = data->diu_reg;
set_fix(info);
len = info->var.yres_virtual * info->fix.line_length; /* Alloc & dealloc each time resolution/bpp change */ if (len != info->fix.smem_len) { if (info->fix.smem_start)
unmap_video_memory(info);
/* Memory allocation for framebuffer */ if (map_video_memory(info)) {
fb_err(info, "unable to allocate fb memory 1\n"); return -ENOMEM;
}
}
if (diu_ops.get_pixel_format)
ad->pix_fmt = diu_ops.get_pixel_format(data->monitor_port,
var->bits_per_pixel); else
ad->pix_fmt = fsl_diu_get_pixel_format(var->bits_per_pixel);
/* * Set a single color register. The values supplied have a 16 bit magnitude * which needs to be scaled in this function for the hardware. Things to take * into consideration are how many color registers, if any, are supported with * the current color visual. With truecolor mode no color palettes are * supported. Here a pseudo palette is created which we store the value in * pseudo_palette in struct fb_info. For pseudocolor mode we have a limited * color palette.
*/ staticint fsl_diu_setcolreg(unsignedint regno, unsignedint red, unsignedint green, unsignedint blue, unsignedint transp, struct fb_info *info)
{ int ret = 1;
/* * If greyscale is true, then we convert the RGB value * to greyscale no matter what visual we are using.
*/ if (info->var.grayscale)
red = green = blue = (19595 * red + 38470 * green +
7471 * blue) >> 16; switch (info->fix.visual) { case FB_VISUAL_TRUECOLOR: /* * 16-bit True Colour. We encode the RGB value * according to the RGB bitfield information.
*/ if (regno < 16) {
u32 *pal = info->pseudo_palette;
u32 v;
red = CNVT_TOHW(red, info->var.red.length);
green = CNVT_TOHW(green, info->var.green.length);
blue = CNVT_TOHW(blue, info->var.blue.length);
transp = CNVT_TOHW(transp, info->var.transp.length);
/* * Pan (or wrap, depending on the `vmode' field) the display using the * 'xoffset' and 'yoffset' fields of the 'var' structure. If the values * don't fit, return -EINVAL.
*/ staticint fsl_diu_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
{ if ((info->var.xoffset == var->xoffset) &&
(info->var.yoffset == var->yoffset)) return 0; /* No change, do nothing */
rc = fb_alloc_cmap(&info->cmap, 16, 0); if (rc) return rc;
if (mfbi->index == PLANE0) { if (data->has_edid) { /* Now build modedb from EDID */
fb_edid_to_monspecs(data->edid_data, &info->monspecs);
fb_videomode_to_modelist(info->monspecs.modedb,
info->monspecs.modedb_len,
&info->modelist);
db = info->monspecs.modedb;
dbsize = info->monspecs.modedb_len;
}
aoi_mode = fb_mode;
} else {
aoi_mode = init_aoi_mode;
}
rc = fb_find_mode(&info->var, info, aoi_mode, db, dbsize, NULL,
default_bpp); if (!rc) { /* * For plane 0 we continue and look into * driver's internal modedb.
*/ if ((mfbi->index == PLANE0) && data->has_edid)
has_default_mode = 0; else return -EINVAL;
}
if (!has_default_mode) {
rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
ARRAY_SIZE(fsl_diu_mode_db), NULL, default_bpp); if (rc)
has_default_mode = 1;
}
/* Still not found, use preferred mode from database if any */ if (!has_default_mode && info->monspecs.modedb) { struct fb_monspecs *specs = &info->monspecs; struct fb_videomode *modedb = &specs->modedb[0];
/* * Get preferred timing. If not found, * first mode in database will be used.
*/ if (specs->misc & FB_MISC_1ST_DETAIL) { int i;
for (i = 0; i < specs->modedb_len; i++) { if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
modedb = &specs->modedb[i]; break;
}
}
}
static irqreturn_t fsl_diu_isr(int irq, void *dev_id)
{ struct diu __iomem *hw = dev_id;
uint32_t status = in_be32(&hw->int_status);
if (status) { /* This is the workaround for underrun */ if (status & INT_UNDRUN) {
out_be32(&hw->diu_mode, 0);
udelay(1);
out_be32(&hw->diu_mode, 1);
} #ifdefined(CONFIG_NOT_COHERENT_CACHE) elseif (status & INT_VSYNC) { unsignedint i;
for (i = 0; i < coherence_data_size;
i += d_cache_line_size)
__asm__ __volatile__ ( "dcbz 0, %[input]"
::[input]"r"(&coherence_data[i]));
} #endif return IRQ_HANDLED;
} return IRQ_NONE;
}
#ifdef CONFIG_PM /* * Power management hooks. Note that we won't be called from IRQ context, * unlike the blank functions above, so we may sleep.
*/ staticint fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state)
{ struct fsl_diu_data *data;
data = dev_get_drvdata(&ofdev->dev);
disable_lcdc(data->fsl_diu_info);
fsl_diu_enable_interrupts(data);
update_lcdc(data->fsl_diu_info); for (i = 0; i < NUM_AOIS; i++) { if (data->mfb[i].count)
fsl_diu_enable_panel(&data->fsl_diu_info[i]);
}
if (old_monitor_port != data->monitor_port) { /* All AOIs need adjust pixel format * fsl_diu_set_par only change the pixsel format here
* unlikely to fail. */ unsignedint i;
for (i=0; i < NUM_AOIS; i++)
fsl_diu_set_par(&data->fsl_diu_info[i]);
} return count;
}
data = dmam_alloc_coherent(&pdev->dev, sizeof(struct fsl_diu_data),
&dma_addr, GFP_DMA | __GFP_ZERO); if (!data) return -ENOMEM;
data->dma_addr = dma_addr;
/* * dma_alloc_coherent() uses a page allocator, so the address is * always page-aligned. We need the memory to be 32-byte aligned, * so that's good. However, if one day the allocator changes, we * need to catch that. It's not worth the effort to handle unaligned * alloctions now because it's highly unlikely to ever be a problem.
*/ if ((unsignedlong)data & 31) {
dev_err(&pdev->dev, "misaligned allocation");
ret = -ENOMEM; goto error;
}
spin_lock_init(&data->reg_lock);
for (i = 0; i < NUM_AOIS; i++) { struct fb_info *info = &data->fsl_diu_info[i];
/* Get the EDID data from the device tree, if present */
prop = of_get_property(np, "edid", &ret); if (prop && ret == EDID_LENGTH) {
memcpy(data->edid_data, prop, EDID_LENGTH);
data->has_edid = true;
}
data->diu_reg = of_iomap(np, 0); if (!data->diu_reg) {
dev_err(&pdev->dev, "cannot map DIU registers\n");
ret = -EFAULT; goto error;
}
/* Get the IRQ of the DIU */
data->irq = irq_of_parse_and_map(np, 0);
if (!data->irq) {
dev_err(&pdev->dev, "could not get DIU IRQ\n");
ret = -EINVAL; goto error;
}
data->monitor_port = monitor_port;
/* * Let DIU continue to display splash screen if it was pre-initialized * by the bootloader; otherwise, clear the display.
*/ if (in_be32(&data->diu_reg->diu_mode) == MFB_MODE0)
out_be32(&data->diu_reg->desc[0], 0);
/* * Older versions of U-Boot leave interrupts enabled, so disable * all of them and clear the status register.
*/
out_be32(&data->diu_reg->int_mask, 0xffffffff);
in_be32(&data->diu_reg->int_status);
ret = request_irq(data->irq, fsl_diu_isr, 0, "fsl-diu-fb",
data->diu_reg); if (ret) {
dev_err(&pdev->dev, "could not claim irq\n"); goto error;
}
for (i = 0; i < NUM_AOIS; i++) {
ret = install_fb(&data->fsl_diu_info[i]); if (ret) {
dev_err(&pdev->dev, "could not register fb %d\n", i);
free_irq(data->irq, data->diu_reg); goto error;
}
}
sysfs_attr_init(&data->dev_attr.attr);
data->dev_attr.attr.name = "monitor";
data->dev_attr.attr.mode = S_IRUGO|S_IWUSR;
data->dev_attr.show = show_monitor;
data->dev_attr.store = store_monitor;
ret = device_create_file(&pdev->dev, &data->dev_attr); if (ret) {
dev_err(&pdev->dev, "could not create sysfs file %s\n",
data->dev_attr.attr.name);
}
dev_set_drvdata(&pdev->dev, data); return 0;
error: for (i = 0; i < NUM_AOIS; i++)
uninstall_fb(&data->fsl_diu_info[i]);
iounmap(data->diu_reg);
return ret;
}
staticvoid fsl_diu_remove(struct platform_device *pdev)
{ struct fsl_diu_data *data; int i;
data = dev_get_drvdata(&pdev->dev);
device_remove_file(&pdev->dev, &data->dev_attr);
disable_lcdc(&data->fsl_diu_info[0]);
free_irq(data->irq, data->diu_reg);
for (i = 0; i < NUM_AOIS; i++)
uninstall_fb(&data->fsl_diu_info[i]);
/* * For kernel boot options (in 'video=xxxfb:<options>' format)
*/ if (fb_get_options("fslfb", &option)) return -ENODEV;
fsl_diu_setup(option); #else
monitor_port = fsl_diu_name_to_port(monitor_string); #endif
/* * Must to verify set_pixel_clock. If not implement on platform, * then that means that there is no platform support for the DIU.
*/ if (!diu_ops.set_pixel_clock) return -ENODEV;
pr_info("Freescale Display Interface Unit (DIU) framebuffer driver\n");
MODULE_AUTHOR("York Sun ");
MODULE_DESCRIPTION("Freescale DIU framebuffer driver");
MODULE_LICENSE("GPL");
module_param_named(mode, fb_mode, charp, 0);
MODULE_PARM_DESC(mode, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
module_param_named(bpp, default_bpp, ulong, 0);
MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified in 'mode'");
module_param_named(monitor, monitor_string, charp, 0);
MODULE_PARM_DESC(monitor, "Specify the monitor port " "(\"dvi\", \"lvds\", or \"dlvds\") if supported by the platform");
Messung V0.5
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.