From patchwork Tue Nov 3 13:54:58 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rongrong Zou X-Patchwork-Id: 7542551 Return-Path: X-Original-To: patchwork-linux-fbdev@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id D80D6BEEA4 for ; Tue, 3 Nov 2015 13:55:40 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D04F020695 for ; Tue, 3 Nov 2015 13:55:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 715B0206D5 for ; Tue, 3 Nov 2015 13:55:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754235AbbKCNzc (ORCPT ); Tue, 3 Nov 2015 08:55:32 -0500 Received: from blu004-omc3s28.hotmail.com ([65.55.116.103]:60875 "EHLO BLU004-OMC3S28.hotmail.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753915AbbKCNzb (ORCPT ); Tue, 3 Nov 2015 08:55:31 -0500 Received: from BLU437-SMTP24 ([65.55.116.74]) by BLU004-OMC3S28.hotmail.com over TLS secured channel with Microsoft SMTPSVC(7.5.7601.23008); Tue, 3 Nov 2015 05:55:30 -0800 X-TMN: [cbDXesz6r/hees9bmKOIEBIh6Zv+zwFE] X-Originating-Email: [rongrongchau@outlook.com] Message-ID: From: Rongrong Zou To: linux-fbdev@vger.kernel.org CC: linuxarm@huawei.com Subject: [PATCH 3/3] Hisilicon graphic driver: add 2d acceleration to hisilicon hi1710 graphic chip Date: Tue, 3 Nov 2015 21:54:58 +0800 X-Mailer: git-send-email 1.9.1 In-Reply-To: <1446558898-52857-1-git-send-email-rongrongchau@outlook.com> References: <1446558898-52857-1-git-send-email-rongrongchau@outlook.com> X-OriginalArrivalTime: 03 Nov 2015 13:55:30.0279 (UTC) FILETIME=[4D1A8770:01D1163F] MIME-Version: 1.0 Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00,FREEMAIL_FROM, RCVD_IN_DNSWL_HI,T_RP_MATCHES_RCVD,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Rongrong Zou This patch implements 2d acceleration. Signed-off-by: Rongrong Zou --- drivers/video/fbdev/hisilicon/Makefile | 2 +- drivers/video/fbdev/hisilicon/hisi_accel.c | 382 +++++++++++++++++++++++++++++ drivers/video/fbdev/hisilicon/hisi_accel.h | 62 +++++ drivers/video/fbdev/hisilicon/hisi_drv.c | 122 ++++++++- drivers/video/fbdev/hisilicon/hisi_hw.c | 23 +- 5 files changed, 588 insertions(+), 3 deletions(-) create mode 100644 drivers/video/fbdev/hisilicon/hisi_accel.c create mode 100644 drivers/video/fbdev/hisilicon/hisi_accel.h diff --git a/drivers/video/fbdev/hisilicon/Makefile b/drivers/video/fbdev/hisilicon/Makefile index 5f478ed..1675edb 100644 --- a/drivers/video/fbdev/hisilicon/Makefile +++ b/drivers/video/fbdev/hisilicon/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_FB_HISILICON) += hisiliconfb.o -hisiliconfb-y := hisi_drv.o hisi_hw.o hisi_cursor.o hisi_chip.o +hisiliconfb-y := hisi_drv.o hisi_hw.o hisi_accel.o hisi_cursor.o hisi_chip.o hisiliconfb-y += hisi_mode.o hisi_power.o hisiliconfb-objs := $(hisiliconfb-y) diff --git a/drivers/video/fbdev/hisilicon/hisi_accel.c b/drivers/video/fbdev/hisilicon/hisi_accel.c new file mode 100644 index 0000000..3666995 --- /dev/null +++ b/drivers/video/fbdev/hisilicon/hisi_accel.c @@ -0,0 +1,382 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hisi_drv.h" +#include "hisi_accel.h" +#include "hisi_help.h" +#include "hisi_reg.h" + +static inline void write_dpr(struct hisi_accel *accel, int offset, u32 value) +{ + writel(value, accel->dpr_base + offset); +} + +static inline u32 read_dpr(struct hisi_accel *accel, int offset) +{ + return readl(accel->dpr_base + offset); +} + +static inline void write_dpport(struct hisi_accel *accel, u32 data) +{ + writel(data, accel->dp_port_base); +} + +int hw_de_init(struct hisi_accel *accel) +{ + /* setup 2d engine registers */ + u32 reg; + u32 clr; + + write_dpr(accel, DE_MASKS, 0xFFFFFFFF); + /* dpr1c */ + reg = FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY, NORMAL) | + FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_Y, 0) | + FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X, 0) | + FIELD_SET(0, DE_STRETCH_FORMAT, ADDRESSING, XY) | + FIELD_VALUE(0, DE_STRETCH_FORMAT, SOURCE_HEIGHT, 3); + + clr = FIELD_CLEAR(DE_STRETCH_FORMAT, PATTERN_XY) & + FIELD_CLEAR(DE_STRETCH_FORMAT, PATTERN_Y) & + FIELD_CLEAR(DE_STRETCH_FORMAT, PATTERN_X) & + FIELD_CLEAR(DE_STRETCH_FORMAT, ADDRESSING) & + FIELD_CLEAR(DE_STRETCH_FORMAT, SOURCE_HEIGHT); + + /* DE_STRETCH bpp format need be initilized in setMode routine */ + write_dpr(accel, DE_STRETCH_FORMAT, + (read_dpr(accel, DE_STRETCH_FORMAT) & clr) | reg); + + /* disable clipping and transparent */ + write_dpr(accel, DE_CLIP_TL, 0);/*dpr2c*/ + write_dpr(accel, DE_CLIP_BR, 0);/*dpr30*/ + + write_dpr(accel, DE_COLOR_COMPARE_MASK, 0);/*dpr24*/ + write_dpr(accel, DE_COLOR_COMPARE, 0); + + reg = FIELD_SET(0, DE_CONTROL, TRANSPARENCY, DISABLE) | + FIELD_SET(0, DE_CONTROL, TRANSPARENCY_MATCH, OPAQUE) | + FIELD_SET(0, DE_CONTROL, TRANSPARENCY_SELECT, SOURCE); + + clr = FIELD_CLEAR(DE_CONTROL, TRANSPARENCY) & + FIELD_CLEAR(DE_CONTROL, TRANSPARENCY_MATCH) & + FIELD_CLEAR(DE_CONTROL, TRANSPARENCY_SELECT); + + /* dpr0c */ + write_dpr(accel, DE_CONTROL, (read_dpr(accel, DE_CONTROL) & clr) | reg); + + return 0; +} + +/* set2dformat only be called from setmode functions + * but if you need dual framebuffer driver,need call set2dformat + * every time you use 2d function + */ +void hw_set_2dformat(struct hisi_accel *accel, int fmt) +{ + u32 reg; + /* fmt=0,1,2 for 8,16,32 */ + reg = read_dpr(accel, DE_STRETCH_FORMAT); + reg = FIELD_VALUE(reg, DE_STRETCH_FORMAT, PIXEL_FORMAT, fmt); + write_dpr(accel, DE_STRETCH_FORMAT, reg); +} + +int hw_fillrect( + struct hisi_accel *accel, u32 base, + u32 pitch, u32 Bpp, + u32 x, u32 y, u32 width, + u32 height, u32 color, u32 rop) +{ + u32 deCtrl; + + if (accel->de_wait() != 0) { + /* int time wait and always busy,seems hardware + * got something error + */ + dbg_msg("%s:De engine always bussy\n", __func__); + return -1; + } + + write_dpr(accel, DE_WINDOW_DESTINATION_BASE, base);/*dpr40*/ + write_dpr(accel, DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, pitch / Bpp) | + FIELD_VALUE(0, DE_PITCH, SOURCE, pitch/Bpp));/*dpr10*/ + + write_dpr(accel, DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, pitch / Bpp) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, pitch / Bpp)); + + write_dpr(accel, DE_FOREGROUND, color);/*DPR14*/ + + write_dpr(accel, DE_DESTINATION, + FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, x) | + FIELD_VALUE(0, DE_DESTINATION, Y, y));/*dpr4*/ + + write_dpr(accel, DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));/*dpr8*/ + + deCtrl = FIELD_SET(0, DE_CONTROL, STATUS, START) | + FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | + FIELD_SET(0, DE_CONTROL, LAST_PIXEL, ON) | + FIELD_SET(0, DE_CONTROL, COMMAND, RECTANGLE_FILL) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_VALUE(0, DE_CONTROL, ROP, rop);/*dpr0xc*/ + + write_dpr(accel, DE_CONTROL, deCtrl); + + return 0; +} + +int hw_copyarea( + struct hisi_accel *accel, + unsigned int sbase, /* Address of source: offset in frame buffer */ + unsigned int spitch, /* Pitch value of source surface in BYTE */ + unsigned int sx, + unsigned int sy, /* Starting coordinate of source surface */ + /* Address of destination: offset in frame buffer */ + unsigned int dbase, + unsigned int dpitch, /* Pitch value of destination surface in BYTE */ + unsigned int bpp, /* Color depth of destination surface */ + unsigned int dx, + unsigned int dy, /* Starting coordinate of destination surface */ + unsigned int width, + unsigned int height, + unsigned int rop2) +{ + unsigned int direction; + unsigned int de_ctrl; + int opsign; + + direction = LEFT_TO_RIGHT; + /* Direction of ROP2 operation: + * 1 = Left to Right, (-1) = Right to Left + */ + opsign = 1; + de_ctrl = 0; + + /* If source and destination are the same surface, + * need to check for overlay cases + */ + if (sbase == dbase && spitch == dpitch) { + /* Determine direction of operation */ + if (sy < dy) { + direction = BOTTOM_TO_TOP; + } else if (sy > dy) { + direction = TOP_TO_BOTTOM; + } else { + /* sy == dy */ + if (sx <= dx) { + direction = RIGHT_TO_LEFT; + } else { + /* sx > dx */ + direction = LEFT_TO_RIGHT; + } + } + } + + if ((direction == BOTTOM_TO_TOP) || (direction == RIGHT_TO_LEFT)) { + sx += width - 1; + sy += height - 1; + dx += width - 1; + dy += height - 1; + opsign = (-1); + } + + /* Note: + * DE_FOREGROUND are DE_BACKGROUND are don't care. + * DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS + * are set by set deSetTransparency(). + */ + + /* 2D Source Base. + * It is an address offset (128 bit aligned) from the beginning + * of frame buffer. + */ + write_dpr(accel, DE_WINDOW_SOURCE_BASE, sbase); /* dpr40 */ + + /* 2D Destination Base. + * It is an address offset (128 bit aligned) from the beginning + * of frame buffer. + */ + write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dbase); /* dpr44 */ + + write_dpr(accel, DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, (dpitch / bpp)) | + FIELD_VALUE(0, DE_PITCH, SOURCE, (spitch / bpp))); /* dpr10*/ + + /* Screen Window width in Pixels. + * 2D engine uses this value to calculate the linear address + * in frame buffer for a given point. + */ + /* dpr3c */ + write_dpr(accel, DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, + DESTINATION, (dpitch / bpp)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (spitch / bpp))); + + if (accel->de_wait() != 0) + return -1; + + write_dpr(accel, DE_SOURCE, + FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, sx) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); /* dpr0 */ + write_dpr(accel, DE_DESTINATION, + FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); /* dpr04 */ + write_dpr(accel, DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); /* dpr08 */ + + de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) | + ((direction == RIGHT_TO_LEFT) ? + FIELD_SET(0, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT) + : FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + write_dpr(accel, DE_CONTROL, de_ctrl); /* dpr0c */ + + return 0; +} + +static unsigned int de_get_transparency(struct hisi_accel *accel) +{ + unsigned int de_ctrl; + + de_ctrl = read_dpr(accel, DE_CONTROL); + + de_ctrl &= FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) | + FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT) | + FIELD_MASK(DE_CONTROL_TRANSPARENCY); + + return de_ctrl; +} + +int hw_imageblit( + struct hisi_accel *accel, + /* pointer to start of source buffer in system memory */ + const char *psrcbuf, + /* Pitch value (in bytes) of the source buffer, + * +ive means top down and -ive mean button up + */ + u32 srcdelta, + /* Mono data can start at any bit in a byte, + * this value should be 0 to 7 + */ + u32 startbit, + u32 dbase, /* Address of destination: offset in frame buffer */ + u32 dpitch, /* Pitch value of destination surface in BYTE */ + u32 bytperpxl, /* Color depth of destination surface */ + u32 dx, + u32 dy, /* Starting coordinate of destination surface */ + u32 width, + u32 height, /* width and height of rectange in pixel value */ + /* Foreground color (corresponding to a 1 in the monochrome data */ + u32 fcolor, + /* Background color (corresponding to a 0 in the monochrome data */ + u32 bcolor, + u32 rop2) /* ROP value */ +{ + unsigned int bytes_per_scan; + unsigned int qbytes_per_scan; + unsigned int bytes_remain; + unsigned int de_ctrl = 0; + unsigned char ajRemain[4]; + int i, j; + + /* Just make sure the start bit is within legal range */ + startbit &= 7; + bytes_per_scan = (width + startbit + 7) / 8; + qbytes_per_scan = bytes_per_scan & ~3; + bytes_remain = bytes_per_scan & 3; + + if (accel->de_wait() != 0) + return -1; + + /* 2D Source Base. Use 0 for HOST Blt.*/ + write_dpr(accel, DE_WINDOW_SOURCE_BASE, 0); + + /* 2D Destination Base. + * It is an address offset (128 bit aligned) + * from the beginning of frame buffer. + */ + write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dbase); + /* dpr10 */ + write_dpr(accel, DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, dpitch / bytperpxl)| + FIELD_VALUE(0, DE_PITCH, SOURCE, dpitch / bytperpxl)); + + /* Screen Window width in Pixels. + * 2D engine uses this value to calculate + * the linear address in frame buffer + * for a given point. + */ + write_dpr(accel, DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, + (dpitch / bytperpxl)) | + FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, + (dpitch / bytperpxl)) + ); + + /* Note: For 2D Source in Host Write, only X_K1_MONO + * field is needed, and Y_K2 field is not used.For mono bitmap, + * use startBit for X_K1. + */ + write_dpr(accel, DE_SOURCE, + FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1_MONO, startbit)); /* dpr00 */ + + write_dpr(accel, DE_DESTINATION, + FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); /* dpr04 */ + + write_dpr(accel, DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); /* dpr08 */ + + write_dpr(accel, DE_FOREGROUND, fcolor); + write_dpr(accel, DE_BACKGROUND, bcolor); + + de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) | + FIELD_SET(0, DE_CONTROL, HOST, MONO) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + + write_dpr(accel, DE_CONTROL, + de_ctrl | de_get_transparency(accel)); + + /* Write MONO data (line by line) to 2D Engine data port */ + for (i = 0; i < height; i++) { + /* For each line, send the data in chunks of 4 bytes */ + for (j = 0; j < (qbytes_per_scan/4); j++) + write_dpport(accel, + *(unsigned int *)(psrcbuf + (j * 4))); + + if (bytes_remain) { + memcpy(ajRemain, psrcbuf+qbytes_per_scan, + bytes_remain); + write_dpport(accel, *(unsigned int *)ajRemain); + } + + psrcbuf += srcdelta; + } + + return 0; +} diff --git a/drivers/video/fbdev/hisilicon/hisi_accel.h b/drivers/video/fbdev/hisilicon/hisi_accel.h new file mode 100644 index 0000000..3393b2e --- /dev/null +++ b/drivers/video/fbdev/hisilicon/hisi_accel.h @@ -0,0 +1,62 @@ +#ifndef HISI_ACCEL_H__ +#define HISI_ACCEL_H__ + +#define HW_ROP2_COPY 0xc +#define HW_ROP2_XOR 0x6 + + +/* blt direction */ +#define TOP_TO_BOTTOM 0 +#define LEFT_TO_RIGHT 0 +#define BOTTOM_TO_TOP 1 +#define RIGHT_TO_LEFT 1 + +void hw_set_2dformat(struct hisi_accel *accel, int fmt); +int hw_de_init(struct hisi_accel *accel); +int hw_fillrect(struct hisi_accel *accel, u32 base, u32 pitch, u32 bpp, + u32 x, u32 y, u32 width, u32 height, u32 color, u32 rop); + +int hw_copyarea( + struct hisi_accel *accel, + unsigned int sbase, /* Address of source: offset in frame buffer */ + unsigned int spitch, /* Pitch value of source surface in BYTE */ + unsigned int sx, + unsigned int sy, /* Starting coordinate of source surface */ + /* Address of destination: offset in frame buffer */ + unsigned int dbase, + unsigned int dpitch, /* Pitch value of destination surface in BYTE */ + unsigned int bpp, /* Color depth of destination surface */ + unsigned int dx, + unsigned int dy, /* Starting coordinate of destination surface */ + unsigned int width, + unsigned int height, + unsigned int rop2 +); + +int hw_imageblit( + struct hisi_accel *accel, + /* pointer to start of source buffer in system memory */ + const char *psrcbuf, + /* Pitch value (in bytes) of the source buffer, + * +ive means top down and -ive mean button up + */ + u32 srcdelta, + /* Mono data can start at any bit in a byte, this value + * should be 0 to 7 + */ + u32 startbit, + u32 dbase, /* Address of destination: offset in frame buffer */ + u32 dpitch, /* Pitch value of destination surface in BYTE */ + u32 byteperpixel, /* Color depth of destination surface */ + u32 dx, + u32 dy, /* Starting coordinate of destination surface */ + u32 width, + u32 height, /* width and height of rectange in pixel value */ + /* Foreground color (corresponding to a 1 in the monochrome data */ + u32 fcolor, + /* Background color (corresponding to a 0 in the monochrome data */ + u32 bcolor, + u32 rop2 +); + +#endif diff --git a/drivers/video/fbdev/hisilicon/hisi_drv.c b/drivers/video/fbdev/hisilicon/hisi_drv.c index 54231d3..e16f942 100644 --- a/drivers/video/fbdev/hisilicon/hisi_drv.c +++ b/drivers/video/fbdev/hisilicon/hisi_drv.c @@ -20,6 +20,7 @@ #include "hisi_drv.h" #include "hisi_cursor.h" #include "hisi_hw.h" +#include "hisi_accel.h" /* chip specific setup routine */ @@ -187,6 +188,103 @@ static int hisifb_ops_cursor(struct fb_info *info, struct fb_cursor *fbcursor) return 0; } +static void hisifb_ops_fillrect(struct fb_info *info, + const struct fb_fillrect *region) +{ + struct hisifb_par *par; + struct hisi_share *share; + unsigned int base, pitch, Bpp, rop; + u32 color; + + if (info->state != FBINFO_STATE_RUNNING) + return; + + par = info->par; + share = par->share; + + /* + * each time 2d function begin to work,below three variable always need + * be set, seems we can put them together in some place + */ + base = par->crtc.oscreen; + pitch = info->fix.line_length; + Bpp = info->var.bits_per_pixel >> 3; + + color = (Bpp == 1) ? region->color : + ((u32 *)info->pseudo_palette)[region->color]; + rop = (region->rop != ROP_COPY) ? + HW_ROP2_XOR : HW_ROP2_COPY; + + share->accel.de_fillrect(&share->accel, + base, pitch, Bpp, region->dx, + region->dy, region->width, + region->height, color, rop); +} + +static void hisifb_ops_copyarea(struct fb_info *info, + const struct fb_copyarea *region) +{ + struct hisifb_par *par; + struct hisi_share *share; + unsigned int base, pitch, Bpp; + + par = info->par; + share = par->share; + + /* + * each time 2d function begin to work,below three variable always need + * be set, seems we can put them together in some place + */ + base = par->crtc.oscreen; + pitch = info->fix.line_length; + Bpp = info->var.bits_per_pixel >> 3; + + share->accel.de_copyarea(&share->accel, base, pitch, + region->sx, region->sy, base, + pitch, Bpp, region->dx, region->dy, + region->width, region->height, + HW_ROP2_COPY); +} + +static void hisifb_ops_imageblit(struct fb_info *info, + const struct fb_image *image) +{ + unsigned int base, pitch, Bpp; + unsigned int fgcol, bgcol; + struct hisifb_par *par; + struct hisi_share *share; + + par = info->par; + share = par->share; + /* + * each time 2d function begin to work,below three variable always need + * be set, seems we can put them together in some place + */ + base = par->crtc.oscreen; + pitch = info->fix.line_length; + Bpp = info->var.bits_per_pixel >> 3; + + if (image->depth == 1) { + if (info->fix.visual == FB_VISUAL_TRUECOLOR || + info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + fgcol = ((u32 *)info->pseudo_palette)[image->fg_color]; + bgcol = ((u32 *)info->pseudo_palette)[image->bg_color]; + } else { + fgcol = image->fg_color; + bgcol = image->bg_color; + } + goto _do_work; + } + return; +_do_work: + share->accel.de_imageblit(&share->accel, + image->data, image->width >> 3, 0, + base, pitch, Bpp, + image->dx, image->dy, + image->width, image->height, + fgcol, bgcol, HW_ROP2_COPY); +} + static struct fb_ops hisifb_ops = { .owner = THIS_MODULE, .fb_check_var = hisifb_ops_check_var, @@ -710,7 +808,12 @@ static int hisifb_set_fbinfo(struct fb_info *info, int index) } /* set info->fbops, must be set before fb_find_mode */ - + if (!share->accel_off) { + /* use 2d acceleration */ + hisifb_ops.fb_fillrect = hisifb_ops_fillrect; + hisifb_ops.fb_copyarea = hisifb_ops_copyarea; + hisifb_ops.fb_imageblit = hisifb_ops_imageblit; + } info->fbops = &hisifb_ops; if (!g_fbmode[index]) { @@ -880,6 +983,23 @@ static int hisifb_pci_probe(struct pci_dev *pdev, share->accel_off = g_noaccel; share->dual = g_dualview; + + if (!share->accel_off) { + /* + * hook deInit and 2d routines, notes that below hw_xxx + * routine can work on most of hisi chips,if some chip need + * specific function,please hook it in smXXX_set_drv + * routine + */ + share->accel.de_init = hw_de_init; + share->accel.de_fillrect = hw_fillrect; + share->accel.de_copyarea = hw_copyarea; + share->accel.de_imageblit = hw_imageblit; + inf_msg("enable 2d acceleration\n"); + } else { + inf_msg("disable 2d acceleration\n"); + } + /* call chip specific setup routine */ hisi_fb_setup(share, g_settings); diff --git a/drivers/video/fbdev/hisilicon/hisi_hw.c b/drivers/video/fbdev/hisilicon/hisi_hw.c index e993f25..22fa166 100644 --- a/drivers/video/fbdev/hisilicon/hisi_hw.c +++ b/drivers/video/fbdev/hisilicon/hisi_hw.c @@ -18,6 +18,7 @@ #include #include #include "hisi_drv.h" +#include "hisi_accel.h" #include "hisi_help.h" #include "hisi_hw.h" #include "hisi_mode.h" @@ -138,14 +139,34 @@ int hw_hisi_crtc_setmode(struct hisifb_crtc *crtc, struct fb_var_screeninfo *var, struct fb_fix_screeninfo *fix) { - int ret; + int ret, fmt; u32 reg; struct mode_para modparm; enum clock_type clock; + struct hisi_share *share; struct hisifb_par *par; ret = 0; par = container_of(crtc, struct hisifb_par, crtc); + share = par->share; + + if (!share->accel_off) { + /* set 2d engine pixel format according to mode bpp */ + switch (var->bits_per_pixel) { + case 8: + fmt = 0; + break; + case 16: + fmt = 1; + break; + case 32: + default: + fmt = 2; + break; + } + hw_set_2dformat(&share->accel, fmt); + } + /* set timing */ modparm.pixel_clock = ps_to_hz(var->pixclock); modparm.vsync_polarity =