diff options
author | codeworkx <codeworkx@cyanogenmod.com> | 2012-09-17 17:53:57 +0200 |
---|---|---|
committer | codeworkx <codeworkx@cyanogenmod.com> | 2012-09-18 16:31:59 +0200 |
commit | c28265764ec6ad9995eb0c761a376ffc9f141fcd (patch) | |
tree | 3ad899757480d47deb2be6011509a4243e8e0dc2 /drivers/media/video/samsung | |
parent | 0ddbcb39c0dc0318f68d858f25a96a074142af2f (diff) | |
download | kernel_samsung_smdk4412-c28265764ec6ad9995eb0c761a376ffc9f141fcd.zip kernel_samsung_smdk4412-c28265764ec6ad9995eb0c761a376ffc9f141fcd.tar.gz kernel_samsung_smdk4412-c28265764ec6ad9995eb0c761a376ffc9f141fcd.tar.bz2 |
applied patches from i9305 jb sources, updated mali to r3p0
Change-Id: Iec4bc4e2fb59e2cf5b4d25568a644d4e3719565e
Diffstat (limited to 'drivers/media/video/samsung')
236 files changed, 17734 insertions, 18756 deletions
diff --git a/drivers/media/video/samsung/Makefile b/drivers/media/video/samsung/Makefile index 301cd9a..639d3bc 100644 --- a/drivers/media/video/samsung/Makefile +++ b/drivers/media/video/samsung/Makefile @@ -11,8 +11,27 @@ else obj-$(CONFIG_VIDEO_FIMG2D3X) += fimg2d3x/ obj-$(CONFIG_VIDEO_FIMG2D4X) += fimg2d4x/ endif + +ifeq ($(CONFIG_MACH_U1), y) +obj-$(CONFIG_VIDEO_UMP) += ump/ +else ifeq ($(CONFIG_MACH_SMDKC210), y) obj-$(CONFIG_VIDEO_UMP) += ump/ +else ifeq ($(CONFIG_MACH_SMDKV310), y) +obj-$(CONFIG_VIDEO_UMP) += ump/ +else +obj-$(CONFIG_VIDEO_UMP) += ump/ +endif + obj-$(CONFIG_VIDEO_TSI) += tsi/ + +ifeq ($(CONFIG_MACH_U1), y) +obj-$(CONFIG_VIDEO_MALI400MP) += mali/ +else ifeq ($(CONFIG_MACH_SMDKC210), y) +obj-$(CONFIG_VIDEO_MALI400MP) += mali/ +else ifeq ($(CONFIG_MACH_SMDKV310), y) obj-$(CONFIG_VIDEO_MALI400MP) += mali/ +else +obj-$(CONFIG_VIDEO_MALI400MP) += mali/ +endif EXTRA_CFLAGS += -Idrivers/media/video diff --git a/drivers/media/video/samsung/fimc/Kconfig b/drivers/media/video/samsung/fimc/Kconfig index 68f0b14..2fc4c86 100644 --- a/drivers/media/video/samsung/fimc/Kconfig +++ b/drivers/media/video/samsung/fimc/Kconfig @@ -6,6 +6,15 @@ config VIDEO_FIMC help This is a video4linux driver for Samsung FIMC device. +config USE_FIMC_CMA + bool "Use CMA for FIMC0/1 region (EXPERIMENTAL)" + depends on DMA_CMA + default n + help + This enables the Contiguous Memory Allocator for MFC SECURE region. + + If unsure, say "n". + choice depends on VIDEO_FIMC prompt "Select CSC Range config" diff --git a/drivers/media/video/samsung/fimc/fimc.h b/drivers/media/video/samsung/fimc/fimc.h index 9527f52..b648965 100644 --- a/drivers/media/video/samsung/fimc/fimc.h +++ b/drivers/media/video/samsung/fimc/fimc.h @@ -25,6 +25,9 @@ #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/videobuf-core.h> +#ifdef CONFIG_SLP_DMABUF +#include <media/videobuf2-core.h> +#endif #include <media/v4l2-mediabus.h> #if defined(CONFIG_BUSFREQ_OPP) || defined(CONFIG_BUSFREQ_LOCK_WRAPPER) #include <mach/dev.h> @@ -42,7 +45,9 @@ #define FIMC_CMA_NAME "fimc" #define FIMC_CORE_CLK "sclk_fimc" -#define FIMC_CLK_RATE 166750000 + +extern int fimc_clk_rate(void); + #define EXYNOS_BUSFREQ_NAME "exynos-busfreq" #if defined(CONFIG_ARCH_EXYNOS4) @@ -58,7 +63,11 @@ #define FIMC_SUBDEVS 3 #define FIMC_OUTBUFS 3 #define FIMC_INQUEUES 10 +#if defined(CONFIG_SLP) +#define FIMC_MAX_CTXS 8 +#else #define FIMC_MAX_CTXS 4 +#endif #define FIMC_TPID 3 #define FIMC_CAPBUFS 32 #define FIMC_ONESHOT_TIMEOUT 200 @@ -205,12 +214,22 @@ enum cam_mclk_status { CAM_MCLK_ON, }; +enum fimc_plane_num { + PLANE_1 = 0x1, + PLANE_2 = 0x2, + PLANE_3 = 0x3, + PLANE_4 = 0x4, +}; + /* * STRUCTURES */ /* for reserved memory */ struct fimc_meminfo { +#ifdef CONFIG_USE_FIMC_CMA + void *cpu_addr; +#endif dma_addr_t base; /* buffer base */ size_t size; /* total length */ dma_addr_t curr; /* current addr */ @@ -263,6 +282,9 @@ struct fimc_capinfo { /* using c210 */ struct list_head outgoing_q; int nr_bufs; +#ifdef CONFIG_SLP_DMABUF + int nr_plane; +#endif int irq; int lastirq; @@ -326,6 +348,9 @@ struct fimc_ctx { struct fimc_overlay overlay; u32 buf_num; +#ifdef CONFIG_SLP_DMABUF + int nr_plane; +#endif u32 is_requested; struct fimc_buf_set src[FIMC_OUTBUFS]; struct fimc_buf_set dst[FIMC_OUTBUFS]; @@ -477,6 +502,10 @@ struct fimc_control { struct timeval before_time; char cma_name[16]; bool restart; +#ifdef CONFIG_SLP_DMABUF + struct vb2_buffer *out_bufs[VIDEO_MAX_FRAME]; + struct vb2_buffer *cap_bufs[VIDEO_MAX_FRAME]; +#endif }; /* global */ @@ -766,5 +795,16 @@ static inline struct fimc_control *get_fimc_ctrl(int id) { return &fimc_dev->ctrl[id]; } +#ifdef CONFIG_SLP_DMABUF +extern void _fimc_queue_free(struct fimc_control *ctrl, + enum v4l2_buf_type type); +extern int fimc_queue_alloc(struct fimc_control *ctrl, enum v4l2_buf_type type, + enum v4l2_memory memory, unsigned int num_buffers, + unsigned int num_planes); +extern int _qbuf_dmabuf(struct fimc_control *ctrl, struct vb2_buffer *vb, + struct v4l2_buffer *b); +extern int _dqbuf_dmabuf(struct fimc_control *ctrl, struct vb2_buffer *vb, + struct v4l2_buffer *b); +#endif #endif /* __FIMC_H */ diff --git a/drivers/media/video/samsung/fimc/fimc_capture.c b/drivers/media/video/samsung/fimc/fimc_capture.c index fe0878a..7d00c8b 100644 --- a/drivers/media/video/samsung/fimc/fimc_capture.c +++ b/drivers/media/video/samsung/fimc/fimc_capture.c @@ -203,6 +203,9 @@ static const struct v4l2_queryctrl fimc_controls[] = { .default_value = 0, }, }; +#ifdef CONFIG_MACH_GC1 +static bool leave_power; +#endif #ifndef CONFIG_VIDEO_FIMC_MIPI void s3c_csis_start(int csis_id, int lanes, int settle, \ @@ -268,7 +271,12 @@ static int fimc_init_camera(struct fimc_control *ctrl) retry: /* set rate for mclk */ +#ifndef CONFIG_MACH_GC1 if ((clk_get_rate(cam->clk)) && (fimc->mclk_status == CAM_MCLK_OFF)) { +#else + if ((clk_get_rate(cam->clk)) && (fimc->mclk_status == CAM_MCLK_OFF) + && !leave_power) { +#endif clk_set_rate(cam->clk, cam->clk_rate); clk_enable(cam->clk); fimc->mclk_status = CAM_MCLK_ON; @@ -277,7 +285,14 @@ retry: /* enable camera power if needed */ if (cam->cam_power) { +#ifndef CONFIG_MACH_GC1 ret = cam->cam_power(1); +#else + if (!leave_power) + ret = cam->cam_power(1); + + leave_power = false; +#endif if (unlikely(ret < 0)) { fimc_err("\nfail to power on\n"); if (fimc->mclk_status == CAM_MCLK_ON) { @@ -720,11 +735,19 @@ int fimc_release_subdev(struct fimc_control *ctrl) client = v4l2_get_subdevdata(ctrl->cam->sd); i2c_unregister_device(client); ctrl->cam->sd = NULL; +#ifndef CONFIG_MACH_GC1 if (ctrl->cam->cam_power) +#else + if (ctrl->cam->cam_power && !leave_power) +#endif ctrl->cam->cam_power(0); /* shutdown the MCLK */ +#ifndef CONFIG_MACH_GC1 if (fimc->mclk_status == CAM_MCLK_ON) { +#else + if (fimc->mclk_status == CAM_MCLK_ON && !leave_power) { +#endif clk_disable(ctrl->cam->clk); fimc->mclk_status = CAM_MCLK_OFF; } @@ -801,9 +824,13 @@ static int fimc_configure_subdev(struct fimc_control *ctrl) ret = fimc_init_camera(ctrl); if (ret < 0) { fimc_err("%s: fail to initialize subdev\n", __func__); + +#ifndef CONFIG_MACH_GC1 client = v4l2_get_subdevdata(sd); i2c_unregister_device(client); ctrl->cam->sd = NULL; +#endif + return ret; } } @@ -1052,9 +1079,6 @@ int fimc_s_input(struct file *file, void *fh, unsigned int i) } #else ctrl->cam = NULL; -#ifdef CONFIG_MACH_P4NOTE - fimc_release_subdev(ctrl); -#endif /* CONFIG_MACH_P4NOTE */ mutex_unlock(&ctrl->v4l2_lock); fimc_err("%s: Could not register camera" \ " sensor with V4L2.\n", __func__); @@ -1117,20 +1141,43 @@ int fimc_s_input(struct file *file, void *fh, unsigned int i) } ret = v4l2_subdev_call(ctrl->is.sd, core, s_power, 1); if (ret < 0) { - fimc_dbg("FIMC-IS init failed"); + fimc_err("FIMC-IS init s_power failed"); mutex_unlock(&ctrl->v4l2_lock); return -ENODEV; } ret = v4l2_subdev_call(ctrl->is.sd, core, load_fw); if (ret < 0) { - fimc_dbg("FIMC-IS init failed"); + fimc_err("FIMC-IS init load_fw failed"); mutex_unlock(&ctrl->v4l2_lock); + if (!cap) { + cap = kzalloc(sizeof(*cap), GFP_KERNEL); + if (!cap) { + fimc_err("%s: no memory for " + "capture device info\n", __func__); + return -ENOMEM; + } + + /* assign to ctrl */ + ctrl->cap = cap; + } return -ENODEV; } ret = v4l2_subdev_call(ctrl->is.sd, core, init, ctrl->cam->sensor_index); if (ret < 0) { - fimc_dbg("FIMC-IS init failed"); + fimc_err("FIMC-IS init failed"); mutex_unlock(&ctrl->v4l2_lock); + if (!cap) { + cap = kzalloc(sizeof(*cap), GFP_KERNEL); + if (!cap) { + fimc_err("%s: no memory for " + "capture device info\n", __func__); + return -ENOMEM; + } + + /* assign to ctrl */ + ctrl->cap = cap; + } + return -ENODEV; } } @@ -1188,6 +1235,81 @@ int fimc_enum_fmt_vid_capture(struct file *file, void *fh, return 0; } +#ifdef CONFIG_SLP_DMABUF +/* + * figures out the depth of requested format + */ +static int fimc_fmt_depth_mplane(struct fimc_control *ctrl, + struct v4l2_format *f, int depth[]) +{ + int ret = 0; + + /* handles only supported pixelformats */ + switch (f->fmt.pix_mp.pixelformat) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV12T: + case V4L2_PIX_FMT_NV21: + f->fmt.pix_mp.num_planes = 2; + depth[0] = 8; + depth[1] = 4; + break; + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + f->fmt.pix_mp.num_planes = 3; + depth[0] = 8; + depth[1] = 2; + depth[2] = 2; + break; + case V4L2_PIX_FMT_JPEG: + case V4L2_PIX_FMT_INTERLEAVED: + f->fmt.pix_mp.num_planes = 1; + depth[0] = -1; + fimc_dbg("Compressed format.\n"); + break; + default: + fimc_dbg("why am I here?\n"); + ret = -EINVAL; + break; + } + + return ret; +} +static int fimc_g_fmt_vid_capture_mplane(struct fimc_control *ctrl, + struct v4l2_format *f) +{ + int depth[VIDEO_MAX_PLANES]; + int ret; + int i; + + /* + * Note that expecting format only can be with + * available output format from FIMC + * Following items should be handled in driver + * bytesperline = width * depth / 8 + * sizeimage = bytesperline * height + */ + + f->fmt.pix_mp.pixelformat = ctrl->cap->fmt.pixelformat; + f->fmt.pix_mp.width = ctrl->cap->fmt.width; + f->fmt.pix_mp.height = ctrl->cap->fmt.height; + + ret = fimc_fmt_depth_mplane(ctrl, f, depth); + if (ret < 0) { + fimc_err("Invaild format\n"); + return ret; + } + for (i = 0; i < f->fmt.pix_mp.num_planes; ++i) { + f->fmt.pix_mp.plane_fmt[i].bytesperline = (f->fmt.pix_mp.width * + depth[i]) >> 3; + f->fmt.pix_mp.plane_fmt[i].sizeimage = + (f->fmt.pix_mp.plane_fmt[i].bytesperline * + f->fmt.pix_mp.width); + } + + return 0; +} +#endif + int fimc_g_fmt_vid_capture(struct file *file, void *fh, struct v4l2_format *f) { struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; @@ -1201,8 +1323,20 @@ int fimc_g_fmt_vid_capture(struct file *file, void *fh, struct v4l2_format *f) mutex_lock(&ctrl->v4l2_lock); +#ifdef CONFIG_SLP_DMABUF + if (V4L2_TYPE_IS_MULTIPLANAR(f->type)) + if (fimc_g_fmt_vid_capture_mplane(ctrl, f) < 0) { + mutex_unlock(&ctrl->v4l2_lock); + return -EINVAL; + } + else { + memset(&f->fmt.pix, 0, sizeof(f->fmt.pix)); + memcpy(&f->fmt.pix, &ctrl->cap->fmt, sizeof(f->fmt.pix)); + } +#else memset(&f->fmt.pix, 0, sizeof(f->fmt.pix)); memcpy(&f->fmt.pix, &ctrl->cap->fmt, sizeof(f->fmt.pix)); +#endif mutex_unlock(&ctrl->v4l2_lock); @@ -1308,7 +1442,7 @@ int fimc_s_fmt_vid_private(struct file *file, void *fh, struct v4l2_format *f) */ mbus_fmt->field = pix->field; #endif -#if (defined(CONFIG_MACH_S2PLUS) || defined(CONFIG_MACH_GC1)) +#if defined(CONFIG_MACH_GC1) mbus_fmt->field = pix->priv; #endif printk(KERN_INFO "%s mbus_fmt->width = %d, height = %d,\n", @@ -1392,7 +1526,17 @@ int fimc_s_fmt_vid_capture(struct file *file, void *fh, struct v4l2_format *f) mutex_lock(&ctrl->v4l2_lock); memset(&cap->fmt, 0, sizeof(cap->fmt)); +#ifdef CONFIG_SLP_DMABUF + if (V4L2_TYPE_IS_MULTIPLANAR(f->type)) { + cap->fmt.pixelformat = f->fmt.pix_mp.pixelformat; + cap->fmt.width = f->fmt.pix_mp.width; + cap->fmt.height = f->fmt.pix_mp.height; + cap->fmt.pixelformat = f->fmt.pix_mp.pixelformat; + } else + memcpy(&cap->fmt, &f->fmt.pix, sizeof(cap->fmt)); +#else memcpy(&cap->fmt, &f->fmt.pix, sizeof(cap->fmt)); +#endif /* * Note that expecting format only can be with @@ -1434,7 +1578,11 @@ int fimc_s_fmt_vid_capture(struct file *file, void *fh, struct v4l2_format *f) Fimc scaler input Hsize is restricted to 4224 pixels. So, GC1 has to bypass fimc scaler to use more than 12M YUV. */ - ctrl->sc.bypass = 1; + if (cap->fmt.width > ctrl->limit->pre_dst_w) + ctrl->sc.bypass = 1; + else + ctrl->sc.bypass = 0; + #else ctrl->sc.bypass = 0; #endif @@ -1636,6 +1784,43 @@ static void fimc_free_buffers(struct fimc_control *ctrl) ctrl->mem.curr = ctrl->mem.base; } +#ifdef CONFIG_SLP_DMABUF +static int fimc_set_cap_num_plane(struct fimc_control *ctrl) +{ + struct fimc_capinfo *cap = ctrl->cap; + + switch (cap->fmt.pixelformat) { + case V4L2_PIX_FMT_RGB32: /* fall through */ + case V4L2_PIX_FMT_RGB565: /* fall through */ + case V4L2_PIX_FMT_YUYV: /* fall through */ + case V4L2_PIX_FMT_UYVY: /* fall through */ + case V4L2_PIX_FMT_VYUY: /* fall through */ + case V4L2_PIX_FMT_YVYU: /* fall through */ + case V4L2_PIX_FMT_NV16: /* fall through */ + case V4L2_PIX_FMT_NV61: /* fall through */ + case V4L2_PIX_FMT_JPEG: + case V4L2_PIX_FMT_INTERLEAVED: + return PLANE_1; + + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV12T: + return PLANE_2; + + case V4L2_PIX_FMT_YUV422P: /* fall through */ + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + return PLANE_3; + + default: + fimc_err("%s: Undefined format\n", __func__); + break; + } + + return 0; +} +#endif + int fimc_reqbufs_capture_mmap(void *fh, struct v4l2_requestbuffers *b) { struct fimc_control *ctrl = fh; @@ -1825,7 +2010,10 @@ int fimc_reqbufs_capture_userptr(void *fh, struct v4l2_requestbuffers *b) fimc_streamoff_capture(fh); fimc_free_buffers(ctrl); - +#ifdef CONFIG_SLP_DMABUF + if (b->memory == V4L2_MEMORY_DMABUF) + _fimc_queue_free(ctrl, V4L2_BUF_TYPE_VIDEO_CAPTURE); +#endif mutex_unlock(&ctrl->v4l2_lock); return 0; } @@ -1837,6 +2025,19 @@ int fimc_reqbufs_capture_userptr(void *fh, struct v4l2_requestbuffers *b) } cap->nr_bufs = b->count; +#ifdef CONFIG_SLP_DMABUF + if (b->memory == V4L2_MEMORY_DMABUF) { + int num_planes; + + num_planes = fimc_set_cap_num_plane(ctrl); + if (!num_planes) { + mutex_unlock(&ctrl->v4l2_lock); + return 0; + } + fimc_queue_alloc(ctrl, b->type, b->memory, + cap->nr_bufs, num_planes); + } +#endif #if (defined(CONFIG_EXYNOS_DEV_PD) && defined(CONFIG_PM_RUNTIME)) if (ctrl->power_status == FIMC_POWER_OFF) { @@ -1996,33 +2197,45 @@ int fimc_s_ctrl_capture(void *fh, struct v4l2_control *c) switch (c->id) { #ifdef CONFIG_MACH_GC1 - case V4L2_CID_CAM_UPDATE_FW: - if (fimc->mclk_status == CAM_MCLK_ON) { - if (ctrl->cam->cam_power) - ctrl->cam->cam_power(0); + case V4L2_CID_CAMERA_HOLD_LENS: + leave_power = true; + ret = v4l2_subdev_call(ctrl->cam->sd, core, s_ctrl, c); + break; - /* shutdown the MCLK */ - clk_disable(ctrl->cam->clk); - fimc->mclk_status = CAM_MCLK_OFF; + case V4L2_CID_CAM_UPDATE_FW: + if (c->value == FW_MODE_UPDATE || c->value == FW_MODE_DUMP) { + if (fimc->mclk_status == CAM_MCLK_ON) { + if (ctrl->cam->cam_power) + ctrl->cam->cam_power(0); - mdelay(5); - } + /* shutdown the MCLK */ + clk_disable(ctrl->cam->clk); + fimc->mclk_status = CAM_MCLK_OFF; - if ((clk_get_rate(ctrl->cam->clk)) && (fimc->mclk_status == CAM_MCLK_OFF)) { - clk_set_rate(ctrl->cam->clk, ctrl->cam->clk_rate); - clk_enable(ctrl->cam->clk); - fimc->mclk_status = CAM_MCLK_ON; - fimc_info1("clock for camera: %d\n", ctrl->cam->clk_rate); + mdelay(5); + } - if (ctrl->cam->cam_power) - ctrl->cam->cam_power(1); - } + if ((clk_get_rate(ctrl->cam->clk)) && + (fimc->mclk_status == CAM_MCLK_OFF)) { + clk_set_rate(ctrl->cam->clk, + ctrl->cam->clk_rate); + clk_enable(ctrl->cam->clk); + fimc->mclk_status = CAM_MCLK_ON; + fimc_info1("clock for camera: %d\n", + ctrl->cam->clk_rate); + + if (ctrl->cam->cam_power) + ctrl->cam->cam_power(1); + } - if (c->value == FW_MODE_UPDATE) - ret = v4l2_subdev_call(ctrl->cam->sd, core, load_fw); + if (c->value == FW_MODE_UPDATE) + ret = v4l2_subdev_call(ctrl->cam->sd, core, load_fw); + else + ret = v4l2_subdev_call(ctrl->cam->sd, core, s_ctrl, c); - else + } else { ret = v4l2_subdev_call(ctrl->cam->sd, core, s_ctrl, c); + } break; #endif case V4L2_CID_CAMERA_RESET: @@ -2206,6 +2419,12 @@ int fimc_s_ctrl_capture(void *fh, struct v4l2_control *c) break; #endif + case V4L2_CID_CAMERA_SET_DUAL_CAPTURE: + case V4L2_CID_CAMERA_DUAL_CAPTURE: + case V4L2_CID_CAMERA_DUAL_POSTVIEW: + ret = v4l2_subdev_call(ctrl->cam->sd, core, s_ctrl, c); + break; + case V4L2_CID_IS_CAMERA_FLASH_MODE: case V4L2_CID_CAMERA_SCENE_MODE: default: @@ -2445,6 +2664,9 @@ int fimc_streamon_capture(void *fh) struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); printk(KERN_INFO "%s++ fimc%d\n", __func__, ctrl->id); +#ifdef CONFIG_SLP + cam_frmsize.index = -1; +#endif cam_frmsize.discrete.width = 0; cam_frmsize.discrete.height = 0; is_ctrl.id = 0; @@ -2617,7 +2839,7 @@ int fimc_streamon_capture(void *fh) if (!ctrl->is.sd && cap->movie_mode && !((cam->width == 880 && cam->height == 720))) { printk(KERN_INFO "\n\n\n%s pm_qos_req is called..\n", __func__ ); - dev_lock(ctrl->bus_dev, ctrl->dev, (unsigned long)400200); + /*dev_lock(ctrl->bus_dev, ctrl->dev, (unsigned long)400200);*/ pm_qos_add_request(&bus_qos_pm_qos_req, PM_QOS_BUS_QOS, 1); /* ioremap for register block */ @@ -2746,6 +2968,15 @@ int fimc_streamoff_capture(void *fh) v4l2_subdev_call(ctrl->cam->sd, video, s_stream, 0); #endif + /* Set FIMD to write back */ + if ((ctrl->cam->id == CAMERA_WB) || (ctrl->cam->id == CAMERA_WB_B)) { + ret = s3cfb_direct_ioctl(0, S3CFB_SET_WRITEBACK, 0); + if (ret) { + fimc_err("failed set writeback\n"); + return ret; + } + } + /* wait for stop hardware */ fimc_wait_disable_capture(ctrl); @@ -2783,7 +3014,7 @@ int fimc_streamoff_capture(void *fh) !(ctrl->cam->width == 880 && ctrl->cam->height == 720)) { printk(KERN_INFO "\n\n\n%s pm_qos_req is removed..\n", __func__ ); pm_qos_remove_request(&bus_qos_pm_qos_req); - dev_unlock(ctrl->bus_dev, ctrl->dev); + /*dev_unlock(ctrl->bus_dev, ctrl->dev);*/ /* ioremap for register block */ qos_regs = ioremap(0x11a00400, 0x10); @@ -2798,14 +3029,6 @@ int fimc_streamoff_capture(void *fh) iounmap(qos_regs); } - /* Set FIMD to write back */ - if ((ctrl->cam->id == CAMERA_WB) || (ctrl->cam->id == CAMERA_WB_B)) { - ret = s3cfb_direct_ioctl(0, S3CFB_SET_WRITEBACK, 0); - if (ret) { - fimc_err("failed set writeback\n"); - return ret; - } - } /* disable camera power */ /* cam power off should call in the subdev release function */ if (fimc_cam_use) { @@ -2904,7 +3127,7 @@ static void fimc_buf2bs(struct fimc_buf_set *bs, struct fimc_buf *buf) int fimc_qbuf_capture(void *fh, struct v4l2_buffer *b) { struct fimc_control *ctrl = fh; - struct fimc_buf *buf = (struct fimc_buf *)b->m.userptr; + struct fimc_buf *buf; struct s3c_platform_fimc *pdata = to_fimc_plat(ctrl->dev); struct fimc_capinfo *cap = ctrl->cap; int idx = b->index; @@ -2926,8 +3149,58 @@ int fimc_qbuf_capture(void *fh, struct v4l2_buffer *b) return -EINVAL; } else { if (b->memory == V4L2_MEMORY_USERPTR) { + buf = (struct fimc_buf *)b->m.userptr; fimc_buf2bs(&cap->bufs[idx], buf); fimc_hwset_output_address(ctrl, &cap->bufs[idx], idx); +#ifdef CONFIG_SLP_DMABUF + } else if (b->memory == V4L2_MEMORY_DMABUF) { + struct vb2_buffer *vb; + struct sg_table *sg; + struct dma_buf_attachment *dba; + struct fimc_buf fimc_buf; + int ret; + unsigned int size; + + vb = ctrl->cap_bufs[b->index]; + + ret = _qbuf_dmabuf(ctrl, vb, b); + if (ret < 0) { + fimc_err("%s: _qbuf_dmabuf error.\n", + __func__); + mutex_unlock(&ctrl->v4l2_lock); + return -ENODEV; + } + for (i = 0; i < vb->num_planes; i++) { + dba = vb->planes[i].mem_priv; + sg = dba->priv; + if (sg) { + fimc_buf.base[i] = + sg_dma_address(sg->sgl); + fimc_buf.length[i] = + sg_dma_len(sg->sgl); + } else { + fimc_err("%s: Wrong sg value.\n", + __func__); + mutex_unlock(&ctrl->v4l2_lock); + return -ENODEV; + } + } + fimc_buf2bs(&cap->bufs[idx], &fimc_buf); + fimc_hwset_output_address(ctrl, &cap->bufs[idx], + idx); + if (cap->pktdata_enable) { + size = + fimc_buf.length[vb->num_planes-1]; + cap->bufs[b->index].vaddr_pktdata = + phys_to_virt( + cap->bufs[b->index].base + [vb->num_planes-1] + size); + cap->pktdata_plane = vb->num_planes; + + /* Size of packet data is fixed */ + cap->pktdata_size = 0x1000; + } +#endif } fimc_hwset_output_buf_sequence(ctrl, idx, FIMC_FRAMECNT_SEQ_ENABLE); @@ -3040,8 +3313,23 @@ int fimc_dqbuf_capture(void *fh, struct v4l2_buffer *b) b->index = bs->id; bs->state = VIDEOBUF_IDLE; - if (b->memory == V4L2_MEMORY_USERPTR) + if (b->memory == V4L2_MEMORY_USERPTR) { fimc_bs2buf(buf, bs); +#ifdef CONFIG_SLP_DMABUF + } else if (b->memory == V4L2_MEMORY_DMABUF) { + struct vb2_buffer *vb; + + vb = ctrl->cap_bufs[b->index]; + ret = _dqbuf_dmabuf(ctrl, vb, b); + if (ret < 0) { + fimc_err("%s: _qbuf_dmabuf error.\n", + __func__); + spin_unlock_irqrestore(&ctrl->outq_lock, + spin_flags); + return -ENODEV; + } +#endif + } list_del(&bs->list); } @@ -3123,6 +3411,12 @@ int fimc_enum_framesizes(struct file *filp, void *fh, struct v4l2_frmsizeenum *f struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; int i; u32 index = 0; + +#ifdef CONFIG_SLP + if (ctrl->cam && ctrl->cam->sd) + return v4l2_subdev_call(ctrl->cam->sd, video, + enum_framesizes, fsize); +#endif for (i = 0; i < ARRAY_SIZE(capture_fmts); i++) { if (fsize->pixel_format != capture_fmts[i].pixelformat) continue; diff --git a/drivers/media/video/samsung/fimc/fimc_capture_u1.c b/drivers/media/video/samsung/fimc/fimc_capture_u1.c index d21d877..1855abf 100644 --- a/drivers/media/video/samsung/fimc/fimc_capture_u1.c +++ b/drivers/media/video/samsung/fimc/fimc_capture_u1.c @@ -454,11 +454,7 @@ int fimc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) return 0; mutex_lock(&ctrl->v4l2_lock); -#ifdef CONFIG_MACH_S2PLUS - if (ctrl->id == FIMC0) -#else if (ctrl->id != FIMC2) -#endif ret = subdev_call(ctrl, video, s_parm, a); mutex_unlock(&ctrl->v4l2_lock); @@ -654,11 +650,7 @@ int fimc_s_input(struct file *file, void *fh, unsigned int i) if (!fimc->camera_isvalid[i]) return -EINVAL; -#ifdef CONFIG_MACH_S2PLUS - if (fimc->camera[i]->sd && ctrl->id == FIMC0) { -#else if (fimc->camera[i]->sd && ctrl->id != FIMC2) { -#endif fimc_err("%s: Camera already in use.\n", __func__); return -EBUSY; } @@ -685,18 +677,6 @@ int fimc_s_input(struct file *file, void *fh, unsigned int i) printk(KERN_INFO "fimc_s_input activated subdev = %d\n", i); } -#ifdef CONFIG_MACH_S2PLUS - if (ctrl->id == FIMC1) { - if (i == fimc->active_camera) { - ctrl->cam = fimc->camera[i]; - fimc_info2("fimc_s_input activating subdev FIMC1 %d\n", - ctrl->cam->initialized); - } else { - mutex_unlock(&ctrl->v4l2_lock); - return -EINVAL; - } - } -#else if (ctrl->id == FIMC2) { if (i == fimc->active_camera) { ctrl->cam = fimc->camera[i]; @@ -707,7 +687,6 @@ int fimc_s_input(struct file *file, void *fh, unsigned int i) return -EINVAL; } } -#endif /* * The first time alloc for struct cap_info, and will be @@ -973,11 +952,7 @@ int fimc_s_fmt_vid_capture(struct file *file, void *fh, struct v4l2_format *f) memcpy(&cap->fmt, &f->fmt.pix, sizeof(cap->fmt)); mbus_fmt = &cap->mbus_fmt; -#ifdef CONFIG_MACH_S2PLUS - if (ctrl->id == FIMC0) { -#else if (ctrl->id != FIMC2) { -#endif if (cap->movie_mode || cap->vt_mode || cap->fmt.priv == V4L2_PIX_FMT_MODE_HDR) { #if defined(CONFIG_MACH_PX) && defined(CONFIG_VIDEO_HD_SUPPORT) @@ -1053,11 +1028,7 @@ int fimc_s_fmt_vid_capture(struct file *file, void *fh, struct v4l2_format *f) return 0; } -#ifdef CONFIG_MACH_S2PLUS - if (ctrl->id == FIMC0) -#else if (ctrl->id != FIMC2) -#endif ret = subdev_call(ctrl, video, s_mbus_fmt, mbus_fmt); mutex_unlock(&ctrl->v4l2_lock); @@ -1637,11 +1608,7 @@ int fimc_s_ctrl_capture(void *fh, struct v4l2_control *c) if ((ctrl->cam->id == CAMERA_WB) || \ (ctrl->cam->id == CAMERA_WB_B)) break; -#ifdef CONFIG_MACH_S2PLUS - if (FIMC0 == ctrl->id) -#else if (FIMC2 != ctrl->id) -#endif ret = subdev_call(ctrl, core, s_ctrl, c); else ret = 0; @@ -1844,11 +1811,7 @@ int fimc_streamon_capture(void *fh) cam = ctrl->cam; if ((ctrl->cam->id != CAMERA_WB) && (ctrl->cam->id != CAMERA_WB_B)) { -#ifdef CONFIG_MACH_S2PLUS - if (ctrl->id == FIMC0) { -#else if (ctrl->id != FIMC2) { -#endif ret = subdev_call(ctrl, video, enum_framesizes, &cam_frmsize); if (ret < 0) { dev_err(ctrl->dev, "%s: enum_framesizes failed\n", __func__); @@ -2067,11 +2030,7 @@ int fimc_streamoff_capture(void *fh) #if defined(CONFIG_MACH_PX) #ifdef CONFIG_VIDEO_IMPROVE_STREAMOFF -#ifdef CONFIG_MACH_S2PLUS - if ((ctrl->id == FIMC0) && (ctrl->cam->type == CAM_TYPE_MIPI)) -#else if ((ctrl->id != FIMC2) && (ctrl->cam->type == CAM_TYPE_MIPI)) -#endif v4l2_subdev_call(ctrl->cam->sd, video, s_stream, STREAM_MODE_CAM_OFF); #endif /* CONFIG_VIDEO_IMPROVE_STREAMOFF */ @@ -2090,11 +2049,7 @@ int fimc_streamoff_capture(void *fh) INIT_LIST_HEAD(&cap->inq); ctrl->status = FIMC_STREAMOFF; -#ifdef CONFIG_MACH_S2PLUS - if (ctrl->id == FIMC0) { -#else if (ctrl->id != FIMC2) { -#endif if (ctrl->cam->type == CAM_TYPE_MIPI) { if (ctrl->cam->id == CAMERA_CSI_C) s3c_csis_stop(CSI_CH_0); diff --git a/drivers/media/video/samsung/fimc/fimc_dev.c b/drivers/media/video/samsung/fimc/fimc_dev.c index a0a91cd..1ed79dd 100644 --- a/drivers/media/video/samsung/fimc/fimc_dev.c +++ b/drivers/media/video/samsung/fimc/fimc_dev.c @@ -32,9 +32,12 @@ #include <linux/videodev2_exynos_camera.h> #include <linux/delay.h> #include <linux/cma.h> +#include <linux/dma-mapping.h> #include <plat/fimc.h> #include <plat/clock.h> #include <mach/regs-pmu.h> +#include <linux/cpufreq.h> +#include <mach/cpufreq.h> #include "fimc.h" @@ -711,20 +714,32 @@ static struct fimc_control *fimc_register_controller(struct platform_device *pde /* In Midas project, FIMC2 reserve memory is used by ION driver. */ if (id != 2) { #endif - sprintf(ctrl->cma_name, "%s%d", FIMC_CMA_NAME, ctrl->id); - err = cma_info(&mem_info, ctrl->dev, 0); - fimc_info1("%s : [cma_info] start_addr : 0x%x, end_addr : 0x%x, " - "total_size : 0x%x, free_size : 0x%x\n", - __func__, mem_info.lower_bound, mem_info.upper_bound, - mem_info.total_size, mem_info.free_size); - if (err) { - fimc_err("%s: get cma info failed\n", __func__); - ctrl->mem.size = 0; +#ifdef CONFIG_USE_FIMC_CMA + if (id == 1) { + ctrl->mem.size = + CONFIG_VIDEO_SAMSUNG_MEMSIZE_FIMC1 * SZ_1K; ctrl->mem.base = 0; - } else { - ctrl->mem.size = mem_info.total_size; - ctrl->mem.base = (dma_addr_t)cma_alloc - (ctrl->dev, ctrl->cma_name, (size_t)ctrl->mem.size, 0); + } else +#endif + { + sprintf(ctrl->cma_name, "%s%d", + FIMC_CMA_NAME, ctrl->id); + err = cma_info(&mem_info, ctrl->dev, 0); + fimc_info1("%s : [cma_info] start_addr : 0x%x, " + " end_addr : 0x%x, total_size : 0x%x, " + "free_size : 0x%x\n", __func__, + mem_info.lower_bound, mem_info.upper_bound, + mem_info.total_size, mem_info.free_size); + if (err) { + fimc_err("%s: get cma info failed\n", __func__); + ctrl->mem.size = 0; + ctrl->mem.base = 0; + } else { + ctrl->mem.size = mem_info.total_size; + ctrl->mem.base = (dma_addr_t)cma_alloc + (ctrl->dev, ctrl->cma_name, + (size_t)ctrl->mem.size, 0); + } } #ifdef CONFIG_ION_EXYNOS } @@ -813,7 +828,7 @@ static struct fimc_control *fimc_register_controller(struct platform_device *pde clk_put(fimc_src_clk); return NULL; } - clk_set_rate(sclk_fimc_lclk, FIMC_CLK_RATE); + clk_set_rate(sclk_fimc_lclk, fimc_clk_rate()); clk_put(sclk_fimc_lclk); clk_put(fimc_src_clk); @@ -1021,6 +1036,255 @@ static int fimc_mmap(struct file *filp, struct vm_area_struct *vma) return ret; } +#ifdef CONFIG_SLP_DMABUF +/** + * _fimc_dmabuf_put() - release memory associated with + * a DMABUF shared buffer + */ +static void _fimc_dmabuf_put(struct vb2_buffer *vb) +{ + unsigned int plane; + + for (plane = 0; plane < vb->num_planes; ++plane) { + void *mem_priv = vb->planes[plane].mem_priv; + + if (mem_priv) { + dma_buf_detach(vb->planes[plane].dbuf, + vb->planes[plane].mem_priv); + dma_buf_put(vb->planes[plane].dbuf); + vb->planes[plane].dbuf = NULL; + vb->planes[plane].mem_priv = NULL; + } + } +} + +void _fimc_queue_free(struct fimc_control *ctrl, enum v4l2_buf_type type) +{ + unsigned int buffer; + struct vb2_buffer *vb; + + for (buffer = 0; buffer < VIDEO_MAX_FRAME; ++buffer) { + if (V4L2_TYPE_IS_OUTPUT(type)) + vb = ctrl->out_bufs[buffer]; + else + vb = ctrl->cap_bufs[buffer]; + + if (!vb) + continue; + _fimc_dmabuf_put(vb); + kfree(vb); + vb = NULL; + } +} + +int fimc_queue_alloc(struct fimc_control *ctrl, enum v4l2_buf_type type, + enum v4l2_memory memory, unsigned int num_buffers, + unsigned int num_planes) +{ + unsigned int buffer; + struct vb2_buffer *vb; + + for (buffer = 0; buffer < num_buffers; ++buffer) { + vb = kzalloc(sizeof(struct vb2_buffer), GFP_KERNEL); + if (!vb) { + fimc_err("%s: Memory alloc for buffer struct failed\n", + __func__); + break; + } + + if (V4L2_TYPE_IS_MULTIPLANAR(type)) + vb->v4l2_buf.length = num_planes; + + vb->num_planes = num_planes; + vb->v4l2_buf.index = buffer; + vb->v4l2_buf.type = type; + vb->v4l2_buf.memory = memory; + + if (V4L2_TYPE_IS_OUTPUT(type)) + ctrl->out_bufs[buffer] = vb; + else + ctrl->cap_bufs[buffer] = vb; + } + + for (buffer = num_buffers; buffer < VIDEO_MAX_FRAME; ++buffer) { + ctrl->out_bufs[buffer] = NULL; + ctrl->cap_bufs[buffer] = NULL; + } + + return buffer; +} + +static inline int _verify_planes_array(struct vb2_buffer *vb, + const struct v4l2_buffer *b) +{ + if (NULL == b->m.planes) { + printk(KERN_ERR "%s: Multi-planar buffer passwd but planes" + " array not provided\n", __func__); + return -EINVAL; + } + if (b->length < vb->num_planes || b->length > VIDEO_MAX_PLANES) { + printk(KERN_ERR "%s: Incorrect planes array length, " + "expected %d, got %d\n", __func__, + vb->num_planes, b->length); + return -EINVAL; + } + + return 0; +} + +static int _fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b, + struct v4l2_plane *v4l2_planes) +{ + int plane; + int ret; + + memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m)); + b->input = vb->v4l2_buf.input; + b->reserved = vb->v4l2_buf.reserved; + + if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { + ret = _verify_planes_array(vb, b); + if (ret) + return ret; + + memcpy(b->m.planes, vb->v4l2_planes, + b->length * sizeof(struct v4l2_plane)); + + for (plane = 0; plane < vb->num_planes; ++plane) + b->m.planes[plane].m.fd = + vb->v4l2_planes[plane].m.fd; + } else { + b->length = vb->v4l2_planes[0].length; + b->bytesused = vb->v4l2_planes[0].bytesused; + b->m.fd = vb->v4l2_planes[0].m.fd; + } + + return ret; +} + +static int _fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b, + struct v4l2_plane *v4l2_planes) +{ + unsigned int plane; + int ret; + + if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { + ret = _verify_planes_array(vb, b); + if (ret) + return ret; + + if (V4L2_TYPE_IS_OUTPUT(b->type)) { + for (plane = 0; plane < vb->num_planes; ++plane) { + v4l2_planes[plane].bytesused = + b->m.planes[plane].bytesused; + v4l2_planes[plane].data_offset = + b->m.planes[plane].data_offset; + } + } + for (plane = 0; plane < vb->num_planes; ++plane) + v4l2_planes[plane].m.fd = + b->m.planes[plane].m.fd; + + } else { + if (V4L2_TYPE_IS_OUTPUT(b->type)) + v4l2_planes[0].bytesused = + b->bytesused; + v4l2_planes[0].m.fd = b->m.fd; + } + + vb->v4l2_buf.field = b->field; + vb->v4l2_buf.timestamp = b->timestamp; + vb->v4l2_buf.input = b->input; + + return 0; +} + +int _qbuf_dmabuf(struct fimc_control *ctrl, struct vb2_buffer *vb, + struct v4l2_buffer *b) +{ + struct v4l2_plane planes[VIDEO_MAX_PLANES]; + unsigned int plane; + struct sg_table *sg; + struct dma_buf_attachment *dba; + int ret; + + ret = _fill_vb2_buffer(vb, b, planes); + if (ret) + return ret; + + for (plane = 0; plane < vb->num_planes; ++plane) { + struct dma_buf *dbuf = dma_buf_get(planes[plane].m.fd); + + if (IS_ERR_OR_NULL(dbuf)) { + fimc_err("dmabuf get error!!! %x\n", plane); + ret = PTR_ERR(dbuf); + goto err; + } + planes[plane].length = dbuf->size; + + /* Skip the plane if already verified */ + if (dbuf == vb->planes[plane].dbuf) { + dma_buf_put(dbuf); + continue; + } + + vb->planes[plane].mem_priv = NULL; + + dba = dma_buf_attach(dbuf, ctrl->dev); + if (IS_ERR(dba)) { + fimc_err("failed to attach dmabuf\n"); + dma_buf_put(dbuf); + ret = PTR_ERR(dba); + goto err; + } + + sg = dma_buf_map_attachment(dba, DMA_BIDIRECTIONAL); + if (IS_ERR(sg)) { + fimc_err("qbuf: failed acquiring dmabuf " + "memory for plane\n"); + ret = PTR_ERR(sg); + goto err; + } + dba->priv = sg; + + vb->planes[plane].dbuf = dbuf; + vb->planes[plane].mem_priv = dba; + + vb->v4l2_planes[plane] = planes[plane]; + } + + return 0; + +err: + _fimc_dmabuf_put(vb); + + return ret; +} + +int _dqbuf_dmabuf(struct fimc_control *ctrl, struct vb2_buffer *vb, + struct v4l2_buffer *b) +{ + struct v4l2_plane planes[VIDEO_MAX_PLANES]; + struct sg_table *sg[VIDEO_MAX_PLANES]; + struct dma_buf_attachment *dba[VIDEO_MAX_PLANES]; + unsigned int plane; + int ret; + + ret = _fill_v4l2_buffer(vb, b, planes); + if (ret) + return ret; + + for (plane = 0; plane < vb->num_planes; ++plane) { + dba[plane] = vb->planes[plane].mem_priv; + sg[plane] = dba[plane]->priv; + dma_buf_unmap_attachment(dba[plane], + sg[plane], DMA_FROM_DEVICE); + } + + return 0; +} +#endif + static u32 fimc_poll(struct file *filp, poll_table *wait) { struct fimc_prv_data *prv_data = @@ -1226,6 +1490,19 @@ static int fimc_open(struct file *filp) goto kzalloc_err; } +#ifdef CONFIG_USE_FIMC_CMA + if (ctrl->id == 1) { + ctrl->mem.cpu_addr = dma_alloc_coherent(ctrl->dev, + ctrl->mem.size, &(ctrl->mem.base), 0); + if (!ctrl->mem.cpu_addr) { + printk(KERN_INFO "FIMC%d: dma_alloc_coherent failed\n", + ctrl->id); + ret = -ENOMEM; + goto dma_alloc_err; + } + } +#endif + if (in_use == 1) { #if (!defined(CONFIG_EXYNOS_DEV_PD) || !defined(CONFIG_PM_RUNTIME)) if (pdata->clk_on) @@ -1276,6 +1553,11 @@ static int fimc_open(struct file *filp) return 0; +#ifdef CONFIG_USE_FIMC_CMA +dma_alloc_err: + kfree(prv_data); +#endif + kzalloc_err: atomic_dec(&ctrl->in_use); @@ -1425,6 +1707,9 @@ static int fimc_release(struct file *filp) } else { ctrl->out->ctx_used[ctx_id] = false; } +#ifdef CONFIG_SLP_DMABUF + _fimc_queue_free(ctrl, V4L2_BUF_TYPE_VIDEO_OUTPUT); +#endif } if (ctrl->cap) { @@ -1445,6 +1730,9 @@ static int fimc_release(struct file *filp) } kfree(ctrl->cap); ctrl->cap = NULL; +#ifdef CONFIG_SLP_DMABUF + _fimc_queue_free(ctrl, V4L2_BUF_TYPE_VIDEO_CAPTURE); +#endif } /* @@ -1462,6 +1750,14 @@ static int fimc_release(struct file *filp) ctrl->fb.is_enable = 0; } +#ifdef CONFIG_USE_FIMC_CMA + if (ctrl->id == 1) { + dma_free_coherent(ctrl->dev, ctrl->mem.size, ctrl->mem.cpu_addr, + ctrl->mem.base); + ctrl->mem.base = 0; + ctrl->mem.cpu_addr = NULL; + } +#endif fimc_warn("FIMC%d %d released.\n", ctrl->id, atomic_read(&ctrl->in_use)); @@ -1840,7 +2136,7 @@ static int __devinit fimc_probe(struct platform_device *pdev) ret = device_create_file(&(pdev->dev), &dev_attr_range_mode); if (ret < 0) { fimc_err("failed to add sysfs entries for range mode\n"); - goto err_global; + goto err_create_file; } printk(KERN_INFO "FIMC%d registered successfully\n", ctrl->id); #if (defined(CONFIG_EXYNOS_DEV_PD) && defined(CONFIG_PM_RUNTIME)) @@ -1848,7 +2144,7 @@ static int __devinit fimc_probe(struct platform_device *pdev) ctrl->fimc_irq_wq = create_workqueue(buf); if (ctrl->fimc_irq_wq == NULL) { fimc_err("failed to create_workqueue\n"); - goto err_global; + goto err_wq; } INIT_WORK(&ctrl->work_struct, s3c_fimc_irq_work); @@ -1869,6 +2165,12 @@ static int __devinit fimc_probe(struct platform_device *pdev) return 0; +err_wq: + device_remove_file(&(pdev->dev), &dev_attr_range_mode); + +err_create_file: + device_remove_file(&(pdev->dev), &dev_attr_log_level); + err_global: video_unregister_device(ctrl->vd); diff --git a/drivers/media/video/samsung/fimc/fimc_dev_u1.c b/drivers/media/video/samsung/fimc/fimc_dev_u1.c index f36db5d..762256b 100644 --- a/drivers/media/video/samsung/fimc/fimc_dev_u1.c +++ b/drivers/media/video/samsung/fimc/fimc_dev_u1.c @@ -682,7 +682,7 @@ struct fimc_control *fimc_register_controller(struct platform_device *pdev) clk_put(fimc_src_clk); return NULL; } - clk_set_rate(sclk_fimc_lclk, FIMC_CLK_RATE); + clk_set_rate(sclk_fimc_lclk, fimc_clk_rate()); clk_put(sclk_fimc_lclk); clk_put(fimc_src_clk); @@ -1419,6 +1419,30 @@ static int fimc_init_global(struct platform_device *pdev) return 0; } +#ifdef CONFIG_DRM_EXYNOS_FIMD_WB +static BLOCKING_NOTIFIER_HEAD(fimc_notifier_client_list); + +int fimc_register_client(struct notifier_block *nb) +{ + return blocking_notifier_chain_register( + &fimc_notifier_client_list, nb); +} +EXPORT_SYMBOL(fimc_register_client); + +int fimc_unregister_client(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister( + &fimc_notifier_client_list, nb); +} +EXPORT_SYMBOL(fimc_unregister_client); + +int fimc_send_event(unsigned long val, void *v) +{ + return blocking_notifier_call_chain( + &fimc_notifier_client_list, val, v); +} +#endif + static int fimc_show_log_level(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/media/video/samsung/fimc/fimc_output.c b/drivers/media/video/samsung/fimc/fimc_output.c index 895cb7f..57611e5 100644 --- a/drivers/media/video/samsung/fimc/fimc_output.c +++ b/drivers/media/video/samsung/fimc/fimc_output.c @@ -25,6 +25,9 @@ #include <plat/media.h> #include <linux/clk.h> #include <linux/delay.h> +#ifdef CONFIG_SLP_DMABUF +#include <linux/dma-buf.h> +#endif #include "fimc.h" #include "fimc-ipc.h" @@ -287,6 +290,33 @@ static void fimc_init_out_buf(struct fimc_ctx *ctx) } } +#ifdef CONFIG_SLP_DMABUF +static int fimc_set_out_num_plane(struct fimc_control *ctrl, + struct fimc_ctx *ctx) +{ + u32 format = ctx->pix.pixelformat; + + switch (format) { + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_RGB565: /* fall through */ + case V4L2_PIX_FMT_UYVY: /* fall through */ + case V4L2_PIX_FMT_YUYV: + return PLANE_1; + case V4L2_PIX_FMT_NV12: /* fall through */ + case V4L2_PIX_FMT_NV21: /* fall through */ + case V4L2_PIX_FMT_NV12T: + return PLANE_2; + case V4L2_PIX_FMT_YUV420: /* fall through */ + return PLANE_3; + default: + fimc_err("%s: Invalid pixelformt : %d\n", __func__, format); + return -EINVAL; + } + + return 0; +} +#endif + static int fimc_outdev_set_src_buf(struct fimc_control *ctrl, struct fimc_ctx *ctx) { @@ -1690,6 +1720,10 @@ int fimc_reqbufs_output(void *fh, struct v4l2_requestbuffers *b) default: break; } +#ifdef CONFIG_SLP_DMABUF + if (b->memory == V4L2_MEMORY_DMABUF) + _fimc_queue_free(ctrl, V4L2_BUF_TYPE_VIDEO_OUTPUT); +#endif } else { /* initialize source buffers */ if (b->memory == V4L2_MEMORY_MMAP) { @@ -1701,6 +1735,14 @@ int fimc_reqbufs_output(void *fh, struct v4l2_requestbuffers *b) if (mode == FIMC_OVLY_DMA_AUTO || mode == FIMC_OVLY_NOT_FIXED) ctx->overlay.req_idx = FIMC_USERPTR_IDX; +#ifdef CONFIG_SLP_DMABUF + } else if (b->memory == V4L2_MEMORY_DMABUF) { + int num_planes; + + num_planes = fimc_set_out_num_plane(ctrl, ctx); + fimc_queue_alloc(ctrl, b->type, b->memory, b->count, + num_planes); +#endif } ctx->is_requested = 1; @@ -2365,6 +2407,7 @@ static int fimc_outdev_start_operation(struct fimc_control *ctrl, ret = fimc_outdev_start_camif(ctrl); if (ret < 0) { fimc_err("Fail: fimc_start_camif\n"); + spin_unlock_irqrestore(&ctrl->out->slock, spin_flags); return -EINVAL; } @@ -2399,6 +2442,7 @@ static int fimc_qbuf_output_single_buf(struct fimc_control *ctrl, case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: buf_set.base[FIMC_ADDR_Y] = (dma_addr_t)ctx->fbuf.base; break; case V4L2_PIX_FMT_YUV420: @@ -2465,9 +2509,11 @@ static int fimc_qbuf_output_multi_buf(struct fimc_control *ctrl, case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: buf_set.base[FIMC_ADDR_Y] = ctx->dst[idx].base[FIMC_ADDR_Y]; break; case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: /* fall through */ buf_set.base[FIMC_ADDR_Y] = ctx->dst[idx].base[FIMC_ADDR_Y]; buf_set.base[FIMC_ADDR_CB] = ctx->dst[idx].base[FIMC_ADDR_CB]; buf_set.base[FIMC_ADDR_CR] = ctx->dst[idx].base[FIMC_ADDR_CR]; @@ -2680,7 +2726,7 @@ static int fimc_update_in_queue_addr(struct fimc_control *ctrl, int fimc_qbuf_output(void *fh, struct v4l2_buffer *b) { - struct fimc_buf *buf = (struct fimc_buf *)b->m.userptr; + struct fimc_buf *buf; struct fimc_ctx *ctx; struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; int ctx_id = ((struct fimc_prv_data *)fh)->ctx_id; @@ -2716,9 +2762,40 @@ int fimc_qbuf_output(void *fh, struct v4l2_buffer *b) (ctrl->status == FIMC_STREAMON) || (ctrl->status == FIMC_STREAMON_IDLE)) { if (b->memory == V4L2_MEMORY_USERPTR) { + buf = (struct fimc_buf *)b->m.userptr; ret = fimc_update_in_queue_addr(ctrl, ctx, b->index, buf->base); if (ret < 0) return ret; +#ifdef CONFIG_SLP_DMABUF + } else if (b->memory == V4L2_MEMORY_DMABUF) { + struct vb2_buffer *vb; + dma_addr_t addr[3]; + struct sg_table *sg; + struct dma_buf_attachment *dba; + int i; + + vb = ctrl->out_bufs[b->index]; + ret = _qbuf_dmabuf(ctrl, vb, b); + if (ret < 0) { + fimc_err("_qbuf_dmabuf failed ret = %d\n", ret); + return ret; + } + for (i = 0; i < vb->num_planes; i++) { + dba = vb->planes[i].mem_priv; + sg = dba->priv; + if (sg) + addr[i] = sg_dma_address(sg->sgl); + else { + fimc_err("%s: Wrong sg value.\n", + __func__); + return -ENODEV; + } + } + ret = fimc_update_in_queue_addr(ctrl, ctx, b->index, + addr); + if (ret < 0) + return ret; +#endif } #if defined(CONFIG_EXYNOS_DEV_PD) && defined(CONFIG_PM_RUNTIME) @@ -2831,6 +2908,7 @@ int fimc_dqbuf_output(void *fh, struct v4l2_buffer *b) int idx = -1, ret = -1; ctx = &ctrl->out->ctx[ctx_id]; + ret = fimc_pop_outq(ctrl, ctx, &idx); if (ret < 0) { ret = wait_event_timeout(ctrl->wq, (ctx->outq[0] != -1), @@ -2838,7 +2916,6 @@ int fimc_dqbuf_output(void *fh, struct v4l2_buffer *b) if (ret == 0) { fimc_dump_context(ctrl, ctx); fimc_recover_output(ctrl, ctx); - pm_runtime_put_sync(ctrl->dev); fimc_err("[0] out_queue is empty\n"); return -EAGAIN; } else if (ret == -ERESTARTSYS) { @@ -2854,7 +2931,18 @@ int fimc_dqbuf_output(void *fh, struct v4l2_buffer *b) } } } +#ifdef CONFIG_SLP_DMABUF + if (b->memory == V4L2_MEMORY_DMABUF) { + struct vb2_buffer *vb; + vb = ctrl->out_bufs[idx]; + ret = _dqbuf_dmabuf(ctrl, vb, b); + if (ret < 0) { + fimc_err("%s: _qbuf_dmabuf error.\n", __func__); + return -ENODEV; + } + } +#endif b->index = idx; fimc_info2("ctx(%d) dqueued idx = %d\n", ctx->ctx_num, b->index); diff --git a/drivers/media/video/samsung/fimc/fimc_regs.c b/drivers/media/video/samsung/fimc/fimc_regs.c index 332e5db..20888c7 100644 --- a/drivers/media/video/samsung/fimc/fimc_regs.c +++ b/drivers/media/video/samsung/fimc/fimc_regs.c @@ -258,6 +258,9 @@ static void fimc_reset_cfg(struct fimc_control *ctrl) { int i; u32 cfg[][2] = { +#ifdef CONFIG_SLP + { 0x008, 0x20010480 }, +#endif { 0x018, 0x00000000 }, { 0x01c, 0x00000000 }, { 0x020, 0x00000000 }, { 0x024, 0x00000000 }, { 0x028, 0x00000000 }, { 0x02c, 0x00000000 }, @@ -1253,7 +1256,11 @@ int fimc_hwset_disable_capture(struct fimc_control *ctrl) void fimc_wait_disable_capture(struct fimc_control *ctrl) { +#ifdef CONFIG_VIDEO_S5K5BBGX + unsigned long timeo = jiffies + 60; /* more 40 ms */ +#else unsigned long timeo = jiffies + 40; /* timeout of 200 ms */ +#endif u32 cfg; if (!ctrl || !ctrl->cap) return; diff --git a/drivers/media/video/samsung/fimc/fimc_v4l2.c b/drivers/media/video/samsung/fimc/fimc_v4l2.c index 510e2f1..becd16c 100644 --- a/drivers/media/video/samsung/fimc/fimc_v4l2.c +++ b/drivers/media/video/samsung/fimc/fimc_v4l2.c @@ -35,8 +35,15 @@ static int fimc_querycap(struct file *filp, void *fh, sprintf(cap->bus_info, "FIMC AHB-bus"); cap->version = 0; +#ifdef CONFIG_SLP_DMABUF + cap->capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_VIDEO_CAPTURE_MPLANE); +#else cap->capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_STREAMING); +#endif return 0; } @@ -47,6 +54,18 @@ static int fimc_reqbufs(struct file *filp, void *fh, struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; int ret = -1; +#ifdef CONFIG_SLP_DMABUF + if (V4L2_TYPE_IS_OUTPUT(b->type)) { + ret = fimc_reqbufs_output(fh, b); + } else if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE + || b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + ret = fimc_reqbufs_capture(ctrl, b); + } else { + fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " + "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); + ret = -EINVAL; + } +#else if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { ret = fimc_reqbufs_capture(ctrl, b); } else if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { @@ -56,6 +75,7 @@ static int fimc_reqbufs(struct file *filp, void *fh, "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); ret = -EINVAL; } +#endif return ret; } @@ -65,6 +85,18 @@ static int fimc_querybuf(struct file *filp, void *fh, struct v4l2_buffer *b) struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; int ret = -1; +#ifdef CONFIG_SLP_DMABUF + if (V4L2_TYPE_IS_OUTPUT(b->type)) { + ret = fimc_querybuf_output(fh, b); + } else if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE + || b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + ret = fimc_querybuf_capture(ctrl, b); + } else { + fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " + "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); + ret = -EINVAL; + } +#else if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { ret = fimc_querybuf_capture(ctrl, b); } else if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { @@ -74,6 +106,7 @@ static int fimc_querybuf(struct file *filp, void *fh, struct v4l2_buffer *b) "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); ret = -EINVAL; } +#endif return ret; } @@ -148,6 +181,18 @@ static int fimc_cropcap(struct file *filp, void *fh, struct v4l2_cropcap *a) struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; int ret = -1; +#ifdef CONFIG_SLP_DMABUF + if (V4L2_TYPE_IS_OUTPUT(a->type)) { + ret = fimc_cropcap_output(fh, a); + } else if (a->type == V4L2_BUF_TYPE_VIDEO_CAPTURE + || a->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + ret = fimc_cropcap_capture(ctrl, a); + } else { + fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " + "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); + ret = -EINVAL; + } +#else if (a->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { ret = fimc_cropcap_capture(ctrl, a); } else if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { @@ -157,6 +202,7 @@ static int fimc_cropcap(struct file *filp, void *fh, struct v4l2_cropcap *a) "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); ret = -EINVAL; } +#endif return ret; } @@ -166,6 +212,18 @@ static int fimc_g_crop(struct file *filp, void *fh, struct v4l2_crop *a) struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; int ret = -1; +#ifdef CONFIG_SLP_DMABUF + if (V4L2_TYPE_IS_OUTPUT(a->type)) { + ret = fimc_g_crop_output(fh, a); + } else if (a->type == V4L2_BUF_TYPE_VIDEO_CAPTURE + || a->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + ret = fimc_g_crop_capture(ctrl, a); + } else { + fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " + "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); + ret = -EINVAL; + } +#else if (a->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { ret = fimc_g_crop_capture(ctrl, a); } else if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { @@ -175,6 +233,7 @@ static int fimc_g_crop(struct file *filp, void *fh, struct v4l2_crop *a) "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); ret = -EINVAL; } +#endif return ret; } @@ -184,6 +243,18 @@ static int fimc_s_crop(struct file *filp, void *fh, struct v4l2_crop *a) struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; int ret = -1; +#ifdef CONFIG_SLP_DMABUF + if (V4L2_TYPE_IS_OUTPUT(a->type)) { + ret = fimc_s_crop_output(fh, a); + } else if (a->type == V4L2_BUF_TYPE_VIDEO_CAPTURE + || a->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + ret = fimc_s_crop_capture(ctrl, a); + } else { + fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " + "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); + ret = -EINVAL; + } +#else if (a->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { ret = fimc_s_crop_capture(ctrl, a); } else if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { @@ -193,6 +264,7 @@ static int fimc_s_crop(struct file *filp, void *fh, struct v4l2_crop *a) "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); ret = -EINVAL; } +#endif return ret; } @@ -202,6 +274,18 @@ static int fimc_streamon(struct file *filp, void *fh, enum v4l2_buf_type i) struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; int ret = -1; +#ifdef CONFIG_SLP_DMABUF + if (V4L2_TYPE_IS_OUTPUT(i)) { + ret = fimc_streamon_output(fh); + } else if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE + || i == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + ret = fimc_streamon_capture(ctrl); + } else { + fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " + "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); + ret = -EINVAL; + } +#else if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE) { ret = fimc_streamon_capture(ctrl); } else if (i == V4L2_BUF_TYPE_VIDEO_OUTPUT) { @@ -211,6 +295,7 @@ static int fimc_streamon(struct file *filp, void *fh, enum v4l2_buf_type i) "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); ret = -EINVAL; } +#endif return ret; } @@ -220,6 +305,18 @@ static int fimc_streamoff(struct file *filp, void *fh, enum v4l2_buf_type i) struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; int ret = -1; +#ifdef CONFIG_SLP_DMABUF + if (V4L2_TYPE_IS_OUTPUT(i)) { + ret = fimc_streamoff_output(fh); + } else if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE + || i == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + ret = fimc_streamoff_capture(ctrl); + } else { + fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " + "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); + ret = -EINVAL; + } +#else if (i == V4L2_BUF_TYPE_VIDEO_CAPTURE) { ret = fimc_streamoff_capture(ctrl); } else if (i == V4L2_BUF_TYPE_VIDEO_OUTPUT) { @@ -229,6 +326,7 @@ static int fimc_streamoff(struct file *filp, void *fh, enum v4l2_buf_type i) "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); ret = -EINVAL; } +#endif return ret; } @@ -238,6 +336,18 @@ static int fimc_qbuf(struct file *filp, void *fh, struct v4l2_buffer *b) struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; int ret = -1; +#ifdef CONFIG_SLP_DMABUF + if (V4L2_TYPE_IS_OUTPUT(b->type)) { + ret = fimc_qbuf_output(fh, b); + } else if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE + || b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + ret = fimc_qbuf_capture(ctrl, b); + } else { + fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " + "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); + ret = -EINVAL; + } +#else if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { ret = fimc_qbuf_capture(ctrl, b); } else if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { @@ -247,6 +357,7 @@ static int fimc_qbuf(struct file *filp, void *fh, struct v4l2_buffer *b) "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); ret = -EINVAL; } +#endif return ret; } @@ -256,6 +367,18 @@ static int fimc_dqbuf(struct file *filp, void *fh, struct v4l2_buffer *b) struct fimc_control *ctrl = ((struct fimc_prv_data *)fh)->ctrl; int ret = -1; +#ifdef CONFIG_SLP_DMABUF + if (V4L2_TYPE_IS_OUTPUT(b->type)) { + ret = fimc_dqbuf_output(fh, b); + } else if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE + || b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + ret = fimc_dqbuf_capture(ctrl, b); + } else { + fimc_err("V4L2_BUF_TYPE_VIDEO_CAPTURE and " + "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); + ret = -EINVAL; + } +#else if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { ret = fimc_dqbuf_capture(ctrl, b); } else if (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { @@ -265,6 +388,7 @@ static int fimc_dqbuf(struct file *filp, void *fh, struct v4l2_buffer *b) "V4L2_BUF_TYPE_VIDEO_OUTPUT are only supported\n"); ret = -EINVAL; } +#endif return ret; } @@ -315,6 +439,12 @@ const struct v4l2_ioctl_ops fimc_v4l2_ops = { .vidioc_querymenu = fimc_querymenu, .vidioc_g_fmt_vid_out = fimc_g_fmt_vid_out, .vidioc_s_fmt_vid_out = fimc_s_fmt_vid_out, +#ifdef CONFIG_SLP_DMABUF + .vidioc_g_fmt_vid_cap_mplane = fimc_g_fmt_vid_capture, + .vidioc_s_fmt_vid_cap_mplane = fimc_s_fmt_vid_capture, + .vidioc_g_fmt_vid_out_mplane = fimc_g_fmt_vid_out, + .vidioc_s_fmt_vid_out_mplane = fimc_s_fmt_vid_out, +#endif .vidioc_try_fmt_vid_out = fimc_try_fmt_vid_out, .vidioc_g_fbuf = fimc_g_fbuf, .vidioc_s_fbuf = fimc_s_fbuf, diff --git a/drivers/media/video/samsung/fimg2d3x-exynos4/fimg2d_dev.c b/drivers/media/video/samsung/fimg2d3x-exynos4/fimg2d_dev.c index 5ccde4a..e0d7d4e 100644 --- a/drivers/media/video/samsung/fimg2d3x-exynos4/fimg2d_dev.c +++ b/drivers/media/video/samsung/fimg2d3x-exynos4/fimg2d_dev.c @@ -477,16 +477,27 @@ static int g2d_remove(struct platform_device *dev) #if defined(CONFIG_HAS_EARLYSUSPEND) void g2d_early_suspend(struct early_suspend *h) { + int i = 0; + atomic_set(&g2d_dev->ready_to_run, 0); /* wait until G2D running is finished */ while(1) { if (!atomic_read(&g2d_dev->in_use)) break; - + msleep_interruptible(2); + + i++; + /* Timeout 1sec */ + if (i > 500) { + g2d_clk_enable(g2d_dev); + g2d_reset(g2d_dev); + g2d_clk_disable(g2d_dev); + break; + } } - + g2d_sysmmu_off(g2d_dev); #if defined(CONFIG_EXYNOS_DEV_PD) @@ -513,25 +524,37 @@ void g2d_late_resume(struct early_suspend *h) #if !defined(CONFIG_HAS_EARLYSUSPEND) static int g2d_suspend(struct platform_device *dev, pm_message_t state) { + int i = 0; + atomic_set(&g2d_dev->ready_to_run, 0); /* wait until G2D running is finished */ while(1) { if (!atomic_read(&g2d_dev->in_use)) break; - + msleep_interruptible(2); + + i++; + /* Timeout 1sec */ + if (i > 500) { + g2d_clk_enable(g2d_dev); + g2d_reset(g2d_dev); + g2d_clk_disable(g2d_dev); + break; + } } - + g2d_sysmmu_off(g2d_dev); - + #if defined(CONFIG_EXYNOS_DEV_PD) /* disable the power domain */ pm_runtime_put(g2d_dev->dev); -#endif +#endif return 0; } + static int g2d_resume(struct platform_device *pdev) { diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d.h b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d.h index 2d8f3b7..3bbb194 100644 --- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d.h +++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d.h @@ -41,6 +41,15 @@ #define FIMG2D_BITBLT_SYNC _IOW(FIMG2D_IOCTL_MAGIC, 1, int) #define FIMG2D_BITBLT_VERSION _IOR(FIMG2D_IOCTL_MAGIC, 2, struct fimg2d_version) #define FIMG2D_BITBLT_SECURE _IOW(FIMG2D_IOCTL_MAGIC, 3, unsigned int) +#define FIMG2D_BITBLT_DBUFFER _IOW(FIMG2D_IOCTL_MAGIC, 4, unsigned long) + +#define SEQ_NO_BLT_SKIA 0x00000001 +#define SEQ_NO_BLT_HWC_SEC 0x00000012 +#define SEQ_NO_BLT_HWC_NOSEC 0x00000002 +#define SEQ_NO_BLT_HDMI 0x00000003 +#define SEQ_NO_CMD_SECURE_ON 0x10000001 +#define SEQ_NO_CMD_SECURE_OFF 0x10000002 +#define SEQ_NO_CMD_SET_DBUFFER 0x10000003 struct fimg2d_version { unsigned int hw; @@ -429,6 +438,7 @@ struct fimg2d_context { atomic_t ncmd; wait_queue_head_t wait_q; struct fimg2d_perf perf[MAX_PERF_DESCS]; + unsigned long *pgd_clone; }; /** @@ -486,6 +496,8 @@ struct fimg2d_control { int irq; unsigned int secure; + unsigned int dbuffer_addr; + unsigned long fault_addr; atomic_t nctx; atomic_t busy; atomic_t active; diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_blt.c b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_blt.c index fc6016c..1eb8d63 100644 --- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_blt.c +++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_blt.c @@ -83,7 +83,12 @@ void fimg2d4x_bitblt(struct fimg2d_control *info) goto blitend; if (cmd->image[IDST].addr.type != ADDR_PHYS) { - pgd = (unsigned long *)ctx->mm->pgd; + if ((cmd->image[IDST].addr.type == ADDR_USER_CONTIG) || + (cmd->image[ISRC].addr.type == ADDR_USER_CONTIG)) + pgd = (unsigned long *)ctx->pgd_clone; + else + pgd = (unsigned long *)ctx->mm->pgd; + s5p_sysmmu_enable(info->dev, (unsigned long)virt_to_phys(pgd)); fimg2d_debug("sysmmu enable: pgd %p ctx %p seq_no(%u)\n", pgd, ctx, cmd->seq_no); @@ -98,6 +103,8 @@ void fimg2d4x_bitblt(struct fimg2d_control *info) info->run(info); fimg2d4x_blit_wait(info, cmd); + if (info->fault_addr) + fimg2d_mmutable_value_replace(cmd, info->fault_addr, 0); #ifdef PERF_PROFILE perf_end(cmd->ctx, PERF_BLIT); #endif diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_hw.c b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_hw.c index 4eb4d04..7835dee 100644 --- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_hw.c +++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d4x_hw.c @@ -16,6 +16,7 @@ #include "fimg2d.h" #include "fimg2d4x.h" #include "fimg2d_clk.h" +#include "fimg2d_cache.h" #define wr(d, a) writel((d), info->regs + (a)) #define rd(a) readl(info->regs + (a)) @@ -124,7 +125,13 @@ void fimg2d4x_set_src_image(struct fimg2d_control *info, struct fimg2d_image *s) { unsigned long cfg; - wr(FIMG2D_ADDR(s->addr.start), FIMG2D_SRC_BASE_ADDR_REG); + if ((s->addr.type == ADDR_USER_CONTIG) && (s->order < ARGB_ORDER_END)) { + wr(FIMG2D_ADDR(GET_MVA(s->addr.start, s->plane2.start)), + FIMG2D_SRC_BASE_ADDR_REG); + } else { + wr(FIMG2D_ADDR(s->addr.start), FIMG2D_SRC_BASE_ADDR_REG); + } + wr(FIMG2D_STRIDE(s->stride), FIMG2D_SRC_STRIDE_REG); if (s->order < ARGB_ORDER_END) { /* argb */ @@ -173,7 +180,13 @@ void fimg2d4x_set_dst_image(struct fimg2d_control *info, struct fimg2d_image *d) { unsigned long cfg; - wr(FIMG2D_ADDR(d->addr.start), FIMG2D_DST_BASE_ADDR_REG); + if ((d->addr.type == ADDR_USER_CONTIG) && (d->order < ARGB_ORDER_END)) { + wr(FIMG2D_ADDR(GET_MVA(d->addr.start, d->plane2.start)), + FIMG2D_DST_BASE_ADDR_REG); + } else { + wr(FIMG2D_ADDR(d->addr.start), FIMG2D_DST_BASE_ADDR_REG); + } + wr(FIMG2D_STRIDE(d->stride), FIMG2D_DST_STRIDE_REG); if (d->order < ARGB_ORDER_END) { diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.c b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.c index 43489e4..f5486b1 100644 --- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.c +++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.c @@ -114,8 +114,48 @@ void fimg2d_clean_outer_pagetable(struct mm_struct *mm, unsigned long vaddr, lv1++; } while (lv1 != lv1end); } + +void fimg2d_clean_outer_pagetable_clone(unsigned long *pgd_clone, + unsigned long vaddr, size_t size) +{ + unsigned long *pgd; + unsigned long *lv1, *lv1end; + unsigned long lv2pa; + + pgd = (unsigned long *)pgd_clone; + + lv1 = pgd + (vaddr >> LV1_SHIFT); + lv1end = pgd + ((vaddr + size + LV1_PT_SIZE-1) >> LV1_SHIFT); + + /* clean level1 page table */ + outer_clean_range(virt_to_phys(lv1), virt_to_phys(lv1end)); + + do { + /* if page size is 4KB, clean level2 page table entry */ + if ((*lv1 & 0x3) == 0x1) { + lv2pa = *lv1 & ~LV2_BASE_MASK; /* lv2 pt base */ + /* clean level2 page table */ + outer_clean_range(lv2pa, lv2pa + LV2_PT_SIZE); + } + lv1++; + } while (lv1 != lv1end); +} #endif /* CONFIG_OUTER_CACHE */ +void fimg2d_clean_inner_pagetable_clone(unsigned long *pgd_clone, + unsigned long vaddr, size_t size) +{ + unsigned long *pgd; + unsigned long *lv1, *lv1end; + + pgd = (unsigned long *)pgd_clone; + + lv1 = pgd + (vaddr >> LV1_SHIFT); + lv1end = pgd + ((vaddr + size + LV1_PT_SIZE-1) >> LV1_SHIFT); + fimg2d_dma_sync_inner((unsigned long)lv1, + (unsigned int)lv1end - (unsigned int)lv1, DMA_TO_DEVICE); +} + enum pt_status fimg2d_check_pagetable(struct mm_struct *mm, unsigned long vaddr, size_t size) { @@ -166,3 +206,50 @@ enum pt_status fimg2d_check_pagetable(struct mm_struct *mm, unsigned long vaddr, return PT_NORMAL; } + +#define PT_NS 0x0 // Non Secure +#define PT_AP 0x8c00 // Access permission +#define PT_ENTRY 0x2 // 1MB Page + +enum pt_status fimg2d_migrate_pagetable(unsigned long *pgd_clone, + unsigned long vaddr, unsigned long paddr, size_t size) +{ + unsigned long *pgd; + unsigned long *lv1d; + + pgd = (unsigned long *)pgd_clone; + + size += vaddr & (SZ_1M - 1); + size = ALIGN(size, SZ_1M); + + while ((long)size > 0) { + lv1d = pgd + (vaddr >> LV1_SHIFT); + + *lv1d = (paddr & 0xfff00000) | PT_NS | PT_AP | PT_ENTRY; + + vaddr += SZ_1M; + paddr += SZ_1M; + size -= SZ_1M; + } + return PT_NORMAL; +} + +void fimg2d_mmutable_value_replace(struct fimg2d_bltcmd *cmd, + unsigned long fault_addr, unsigned long l2d_value) +{ + unsigned long *pgd; + unsigned long *lv1d, *lv2d; + + pgd = (unsigned long *)cmd->ctx->mm->pgd; + lv1d = pgd + (fault_addr >> LV1_SHIFT); + + lv2d = (unsigned long *)phys_to_virt(*lv1d & ~LV2_BASE_MASK) + + ((fault_addr & LV2_PT_MASK) >> LV2_SHIFT); + + *lv2d = l2d_value; + + flush_all_cpu_caches(); + fimg2d_clean_outer_pagetable(cmd->ctx->mm, fault_addr, 4); + + printk(KERN_INFO "MMU Level2 value replaced [0x%lx]", l2d_value); +} diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.h b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.h index f337ea5..7699a37 100644 --- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.h +++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_cache.h @@ -18,6 +18,10 @@ #define L1_CACHE_SIZE SZ_64K #define L2_CACHE_SIZE SZ_1M #define LINE_FLUSH_THRESHOLD SZ_1K +#define L1_DESCRIPTOR_SIZE SZ_16K + +/* Get Modified virtual address to use 1MB page */ +#define GET_MVA(V, P) ((V & 0xfff00000) | (P & 0x000fffff)) /** * cache_opr - [kernel] cache operation mode @@ -92,5 +96,11 @@ static inline void fimg2d_dma_unsync_inner(unsigned long addr, size_t size, int } void fimg2d_clean_outer_pagetable(struct mm_struct *mm, unsigned long addr, size_t size); +void fimg2d_clean_outer_pagetable_clone(unsigned long *pgd_clone, unsigned long addr, size_t size); +void fimg2d_clean_inner_pagetable_clone(unsigned long *pgd_clone, unsigned long addr, size_t size); void fimg2d_dma_sync_outer(struct mm_struct *mm, unsigned long addr, size_t size, enum cache_opr opr); enum pt_status fimg2d_check_pagetable(struct mm_struct *mm, unsigned long addr, size_t size); +enum pt_status fimg2d_migrate_pagetable(unsigned long *pgd_clone, + unsigned long vaddr, unsigned long paddr, size_t size); +void fimg2d_mmutable_value_replace(struct fimg2d_bltcmd *cmd, + unsigned long fault_addr, unsigned long l2d_value); diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_ctx.c b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_ctx.c index eaa722c..0c6c590 100644 --- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_ctx.c +++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_ctx.c @@ -130,6 +130,7 @@ static int fimg2d_check_dma_sync(struct fimg2d_bltcmd *cmd) enum pt_status pt; int clip_x, clip_w, clip_h, y, dir, i; unsigned long clip_start; + unsigned long modified_addr; clp = &p->clipping; @@ -155,6 +156,13 @@ static int fimg2d_check_dma_sync(struct fimg2d_bltcmd *cmd) pt = fimg2d_check_pagetable(mm, c->addr, c->size); if (pt == PT_FAULT) return -1; + } else if (img->addr.type == ADDR_USER_CONTIG) { + modified_addr = GET_MVA(img->addr.start, img->plane2.start); + pt = fimg2d_migrate_pagetable(cmd->ctx->pgd_clone, + modified_addr, img->plane2.start, img->height * img->stride); + if (pt != PT_NORMAL) { + return -1; + } } if (img->need_cacheopr && i != IMAGE_TMP) { @@ -175,7 +183,25 @@ static int fimg2d_check_dma_sync(struct fimg2d_bltcmd *cmd) c = &cmd->dma[i]; r = &img->rect; - if (!img->addr.type || !c->cached) + if (!img->addr.type) + continue; + + if ((cmd->image[IMAGE_SRC].addr.type == ADDR_USER_CONTIG) || + (cmd->image[IMAGE_DST].addr.type == ADDR_USER_CONTIG)) { + if (img->addr.type == ADDR_USER_CONTIG) { + if (i == IMAGE_DST && clp->enable) + modified_addr = GET_MVA(img->addr.start, img->plane2.start) + + (img->stride * clp->y1); + else + modified_addr = GET_MVA(img->addr.start, img->plane2.start) + + (img->stride * r->y1); + } else { + modified_addr = c->addr; + } + fimg2d_clean_inner_pagetable_clone(cmd->ctx->pgd_clone, modified_addr, c->size); + } + + if ( !c->cached) continue; if (i == IMAGE_DST) @@ -226,8 +252,22 @@ static int fimg2d_check_dma_sync(struct fimg2d_bltcmd *cmd) continue; /* clean pagetable */ - if (img->addr.type == ADDR_USER) + if ((cmd->image[IMAGE_SRC].addr.type == ADDR_USER_CONTIG) || + (cmd->image[IMAGE_DST].addr.type == ADDR_USER_CONTIG)) { + if (img->addr.type == ADDR_USER_CONTIG) { + if (i == IMAGE_DST && clp->enable) + modified_addr = GET_MVA(img->addr.start, img->plane2.start) + + (img->stride * clp->y1); + else + modified_addr = GET_MVA(img->addr.start, img->plane2.start) + + (img->stride * r->y1); + } else { + modified_addr = c->addr; + } + fimg2d_clean_outer_pagetable_clone(cmd->ctx->pgd_clone, modified_addr, c->size); + } else { fimg2d_clean_outer_pagetable(mm, c->addr, c->size); + } if (!c->cached) continue; @@ -275,14 +315,17 @@ int fimg2d_add_command(struct fimg2d_control *info, struct fimg2d_context *ctx, int i, ret; struct fimg2d_image *buf[MAX_IMAGES] = image_table(blit); struct fimg2d_bltcmd *cmd; + struct fimg2d_image *img; - if ((blit->dst) && (type == ADDR_USER)) + if ((blit->dst) && (type == ADDR_USER) + && (blit->seq_no == SEQ_NO_BLT_SKIA)) up_write(&page_alloc_slow_rwsem); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { - if ((blit->dst) && (type == ADDR_USER)) + if ((blit->dst) && (type == ADDR_USER) + && (blit->seq_no == SEQ_NO_BLT_SKIA)) if (!down_write_trylock(&page_alloc_slow_rwsem)) return -EAGAIN; return -ENOMEM; @@ -294,7 +337,8 @@ int fimg2d_add_command(struct fimg2d_control *info, struct fimg2d_context *ctx, if (copy_from_user(&cmd->image[i], buf[i], sizeof(struct fimg2d_image))) { - if ((blit->dst) && (type == ADDR_USER)) + if ((blit->dst) && (type == ADDR_USER) + && (blit->seq_no == SEQ_NO_BLT_SKIA)) if (!down_write_trylock(&page_alloc_slow_rwsem)) { ret = -EAGAIN; goto err_user; @@ -304,7 +348,8 @@ int fimg2d_add_command(struct fimg2d_control *info, struct fimg2d_context *ctx, } } - if ((blit->dst) && (type == ADDR_USER)) + if ((blit->dst) && (type == ADDR_USER) + && (blit->seq_no == SEQ_NO_BLT_SKIA)) if (!down_write_trylock(&page_alloc_slow_rwsem)) { ret = -EAGAIN; goto err_user; @@ -329,6 +374,13 @@ int fimg2d_add_command(struct fimg2d_control *info, struct fimg2d_context *ctx, fimg2d_fixup_params(cmd); + for (i = 0; i < MAX_IMAGES; i++) { + img = &cmd->image[i]; + if (img->addr.type == ADDR_USER_CONTIG) { + memcpy(cmd->ctx->pgd_clone, cmd->ctx->mm->pgd, L1_DESCRIPTOR_SIZE); + } + } + if (fimg2d_check_dma_sync(cmd)) { ret = -EFAULT; goto err_user; diff --git a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_drv.c b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_drv.c index ed14901..84c7db5 100644 --- a/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_drv.c +++ b/drivers/media/video/samsung/fimg2d4x-exynos4/fimg2d_drv.c @@ -46,6 +46,8 @@ #define LV2_PT_MASK 0xff000 #define LV2_SHIFT 12 #define LV1_DESC_MASK 0x3 +#define LV2_VALUE_META 0xc7f +#define LV2_VALUE_BASE_MASK 0xfff static struct fimg2d_control *info; @@ -116,7 +118,12 @@ static int fimg2d_sysmmu_fault_handler(enum S5P_SYSMMU_INTERRUPT_TYPE itype, lv2d = (unsigned long *)phys_to_virt(*lv1d & ~LV2_BASE_MASK) + ((fault_addr & LV2_PT_MASK) >> LV2_SHIFT); printk(KERN_ERR " Level 2 descriptor(0x%lx)\n", *lv2d); - fimg2d_clean_outer_pagetable(cmd->ctx->mm, fault_addr, 4); + if (*lv2d == 0) { + fimg2d_mmutable_value_replace(cmd, fault_addr, + (info->dbuffer_addr & ~LV2_VALUE_BASE_MASK) | LV2_VALUE_META); + info->fault_addr = fault_addr; + } else + fimg2d_clean_outer_pagetable(cmd->ctx->mm, fault_addr, 4); next: return 0; @@ -161,6 +168,8 @@ static int fimg2d_open(struct inode *inode, struct file *file) ctx, (unsigned long *)ctx->mm->pgd, (unsigned long *)init_mm.pgd); + ctx->pgd_clone = kzalloc(L1_DESCRIPTOR_SIZE, GFP_KERNEL); + fimg2d_add_context(info, ctx); return 0; } @@ -178,6 +187,7 @@ static int fimg2d_release(struct inode *inode, struct file *file) } fimg2d_del_context(info, ctx); + kfree(ctx->pgd_clone); kfree(ctx); return 0; } @@ -223,7 +233,8 @@ static long fimg2d_ioctl(struct file *file, unsigned int cmd, unsigned long arg) dev_lock(info->bus_dev, info->dev, 160160); #endif #endif - if ((blit.dst) && (dst.addr.type == ADDR_USER)) + if ((blit.dst) && (dst.addr.type == ADDR_USER) + && (blit.seq_no == SEQ_NO_BLT_SKIA)) if (!down_write_trylock(&page_alloc_slow_rwsem)) ret = -EAGAIN; @@ -238,7 +249,9 @@ static long fimg2d_ioctl(struct file *file, unsigned int cmd, unsigned long arg) perf_print(ctx, blit.seq_no); perf_clear(ctx); #endif - if ((blit.dst) && (dst.addr.type == ADDR_USER) && ret != -EAGAIN) + if ((blit.dst) && (dst.addr.type == ADDR_USER) + && (blit.seq_no == SEQ_NO_BLT_SKIA) + && ret != -EAGAIN) up_write(&page_alloc_slow_rwsem); #ifdef CONFIG_BUSFREQ_OPP @@ -246,6 +259,13 @@ static long fimg2d_ioctl(struct file *file, unsigned int cmd, unsigned long arg) dev_unlock(info->bus_dev, info->dev); #endif #endif + + if (info->fault_addr) { + printk(KERN_INFO "Return by G2D fault handler"); + info->fault_addr = 0; + ret = -EFAULT; + } + break; case FIMG2D_BITBLT_SYNC: @@ -281,6 +301,17 @@ static long fimg2d_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; + case FIMG2D_BITBLT_DBUFFER: + if (copy_from_user(&info->dbuffer_addr, + (unsigned long *)arg, + sizeof(unsigned long))) { + printk(KERN_ERR + "[%s] failed to FIMG2D_BITBLT_DBUFFER: copy_from_user error\n\n", + __func__); + return -EFAULT; + } + break; + default: printk(KERN_ERR "[%s] unknown ioctl\n", __func__); ret = -EFAULT; @@ -315,6 +346,7 @@ static int fimg2d_setup_controller(struct fimg2d_control *info) atomic_set(&info->nctx, 0); atomic_set(&info->active, 0); info->secure = 0; + info->fault_addr = 0; spin_lock_init(&info->bltlock); @@ -384,12 +416,20 @@ static int fimg2d_probe(struct platform_device *pdev) fimg2d_debug("device name: %s base address: 0x%lx\n", pdev->name, (unsigned long)res->start); + /* Clock setup */ + ret = fimg2d_clk_setup(info); + if (ret) { + printk(KERN_ERR "FIMG2D failed to setup clk\n"); + ret = -ENOENT; + goto err_clk; + } + /* irq */ info->irq = platform_get_irq(pdev, 0); if (!info->irq) { printk(KERN_ERR "FIMG2D failed to get irq resource\n"); ret = -ENOENT; - goto err_map; + goto err_irq; } fimg2d_debug("irq: %d\n", info->irq); @@ -400,13 +440,6 @@ static int fimg2d_probe(struct platform_device *pdev) goto err_irq; } - ret = fimg2d_clk_setup(info); - if (ret) { - printk(KERN_ERR "FIMG2D failed to setup clk\n"); - ret = -ENOENT; - goto err_clk; - } - #ifdef CONFIG_PM_RUNTIME pm_runtime_enable(info->dev); fimg2d_debug("enable runtime pm\n"); @@ -432,19 +465,20 @@ static int fimg2d_probe(struct platform_device *pdev) return 0; err_reg: - fimg2d_clk_release(info); - -err_clk: free_irq(info->irq, NULL); err_irq: + fimg2d_clk_release(info); + +err_clk: iounmap(info->regs); err_map: + release_mem_region(res->start, resource_size(res)); kfree(info->mem); err_region: - release_resource(info->mem); + release_resource(res); err_res: destroy_workqueue(info->work_q); diff --git a/drivers/media/video/samsung/jpeg_v2x/jpeg_conf.h b/drivers/media/video/samsung/jpeg_v2x/jpeg_conf.h index 6fcc276..086c20a 100644 --- a/drivers/media/video/samsung/jpeg_v2x/jpeg_conf.h +++ b/drivers/media/video/samsung/jpeg_v2x/jpeg_conf.h @@ -15,27 +15,37 @@ /* Q-table for JPEG */ /* ITU standard Q-table */ -const unsigned int ITU_Q_tbl[4][16] = { +const unsigned int ITU_Q_tbl[6][16] = { { - 0x01010101, 0x01020303, 0x01010101, 0x01030303, /* Y */ - 0x01010101, 0x02030303, 0x01010101, 0x03040403, - 0x01010203, 0x03050504, 0x01020303, 0x04050605, - 0x02030404, 0x05060605, 0x04050505, 0x06050505 + 0x06030303, 0x07070706, 0x03030303, 0x08080804, /* Y QF:97 */ + 0x01010101, 0x03040303, 0x03010101, 0x04050503, + 0x03030101, 0x05060704, 0x04030301, 0x06070605, + 0x05050403, 0x06070706, 0x06060604, 0x06070707 } , { - 0x01010102, 0x05050505, 0x01010103, 0x05050505, /* CbCr */ - 0x01010503, 0x05050505, 0x02030505, 0x05050505, - 0x05050505, 0x05050505, 0x05050505, 0x05050505, - 0x05050505, 0x05050505, 0x05050505, 0x05050505 + 0x06030303, 0x07070706, 0x04030303, 0x08080806, /* CbCr QF:97 */ + 0x06030301, 0x06060606, 0x06060403, 0x06060606, + 0x06060606, 0x06060606, 0x06060606, 0x06060606, + 0x06060606, 0x06060606, 0x06060606, 0x06060606 } , { - 0x05020205, 0x0a161e25, 0x02020307, 0x0c232521, /* Y */ - 0x0302050a, 0x16222b22, 0x0305090e, 0x1e393326, - 0x06091422, 0x2a384431, 0x0a122118, 0x34454b3c, - 0x1d283238, 0x44525142, 0x2d3c3e40, 0x4a424441 + 0x06030303, 0x0a080706, 0x03030303, 0x090a0904, /* Y QF:92 */ + 0x04030303, 0x090b0906, 0x05040303, 0x0a0d0e08, + 0x09060403, 0x0c10110d, 0x0a090604, 0x0f12110d, + 0x0e0c0a08, 0x10131310, 0x100f0f0c, 0x10101012 } , { - 0x05020205, 0x251e160a, 0x07030202, 0x2125230c, /* CbCr */ - 0x0a050203, 0x222b2216, 0x0e090503, 0x2633391e, - 0x22140906, 0x3144382a, 0x1821120a, 0x3c4b4534, - 0x3832281d, 0x42515244, 0x403e3c2d, 0x4144424a + 0x08040303, 0x10101010, 0x0b040303, 0x10101010, /* CbCr QF:92 */ + 0x10090404, 0x10101010, 0x10100b08, 0x10101010, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x10101010, 0x10101010, 0x10101010, 0x10101010 + } , { + 0x06030304, 0x0e0c0a06, 0x05030303, 0x0d0e0e06, /* Y QF:88 */ + 0x06040303, 0x0d110e0a, 0x07050403, 0x0f13150c, + 0x0d090504, 0x12191a10, 0x0f0d0806, 0x161b1913, + 0x15130f0c, 0x181d1d19, 0x18171611, 0x1819181b + } , { + 0x0b060404, 0x18181818, 0x10060504, 0x18181818, /* CbCr QF:88 */ + 0x180d0606, 0x18181818, 0x1818100b, 0x18181818, + 0x18181818, 0x18181818, 0x18181818, 0x18181818, + 0x18181818, 0x18181818, 0x18181818, 0x18181818 } }; diff --git a/drivers/media/video/samsung/jpeg_v2x/jpeg_dev.c b/drivers/media/video/samsung/jpeg_v2x/jpeg_dev.c index 1e6b085..eb026ab 100644 --- a/drivers/media/video/samsung/jpeg_v2x/jpeg_dev.c +++ b/drivers/media/video/samsung/jpeg_v2x/jpeg_dev.c @@ -504,7 +504,7 @@ static void jpeg_device_enc_run(void *priv) jpeg_sw_reset(dev->reg_base); jpeg_set_interrupt(dev->reg_base); jpeg_set_huf_table_enable(dev->reg_base, 1); - jpeg_set_enc_tbl(dev->reg_base); + jpeg_set_enc_tbl(dev->reg_base, enc_param.quality); jpeg_set_encode_tbl_select(dev->reg_base, enc_param.quality); jpeg_set_stream_size(dev->reg_base, enc_param.in_width, enc_param.in_height); @@ -893,12 +893,16 @@ static int jpeg_probe(struct platform_device *pdev) #endif #ifdef CONFIG_JPEG_V2_1 - dev->watchdog_workqueue = create_singlethread_workqueue(JPEG_NAME); - INIT_WORK(&dev->watchdog_work, jpeg_watchdog_worker); - atomic_set(&dev->watchdog_cnt, 0); - init_timer(&dev->watchdog_timer); - dev->watchdog_timer.data = (unsigned long)dev; - dev->watchdog_timer.function = jpeg_watchdog; + dev->watchdog_workqueue = create_singlethread_workqueue(JPEG_NAME); + if (!dev->watchdog_workqueue) { + ret = -ENOMEM; + goto err_video_reg; + } + INIT_WORK(&dev->watchdog_work, jpeg_watchdog_worker); + atomic_set(&dev->watchdog_cnt, 0); + init_timer(&dev->watchdog_timer); + dev->watchdog_timer.data = (unsigned long)dev; + dev->watchdog_timer.function = jpeg_watchdog; #endif /* clock disable */ clk_disable(dev->clk); @@ -1043,7 +1047,8 @@ static int jpeg_runtime_suspend(struct device *dev) struct jpeg_dev *jpeg_drv = platform_get_drvdata(pdev); #if defined(CONFIG_BUSFREQ_OPP) || defined(CONFIG_BUSFREQ_LOCK_WRAPPER) /* lock bus frequency */ - dev_unlock(jpeg_drv->bus_dev, dev); + if (samsung_rev() < EXYNOS4412_REV_2_0) + dev_unlock(jpeg_drv->bus_dev, dev); #endif jpeg_drv->vb2->suspend(jpeg_drv->alloc_ctx); /* clock disable */ @@ -1057,7 +1062,9 @@ static int jpeg_runtime_resume(struct device *dev) struct jpeg_dev *jpeg_drv = platform_get_drvdata(pdev); #if defined(CONFIG_BUSFREQ_OPP) || defined(CONFIG_BUSFREQ_LOCK_WRAPPER) /* lock bus frequency */ - dev_lock(jpeg_drv->bus_dev, &jpeg_drv->plat_dev->dev, BUSFREQ_400MHZ); + if (samsung_rev() < EXYNOS4412_REV_2_0) + dev_lock(jpeg_drv->bus_dev, + &jpeg_drv->plat_dev->dev, BUSFREQ_400MHZ); #endif clk_enable(jpeg_drv->clk); jpeg_drv->vb2->resume(jpeg_drv->alloc_ctx); @@ -1104,9 +1111,7 @@ static int __init jpeg_init(void) { printk(KERN_CRIT "Initialize JPEG driver\n"); - platform_driver_register(&jpeg_driver); - - return 0; + return platform_driver_register(&jpeg_driver); } static void __exit jpeg_exit(void) diff --git a/drivers/media/video/samsung/jpeg_v2x/jpeg_mem.h b/drivers/media/video/samsung/jpeg_v2x/jpeg_mem.h index d912628..9336bb8 100644 --- a/drivers/media/video/samsung/jpeg_v2x/jpeg_mem.h +++ b/drivers/media/video/samsung/jpeg_v2x/jpeg_mem.h @@ -33,7 +33,12 @@ extern const struct jpeg_vb2 jpeg_vb2_cma; extern const struct jpeg_vb2 jpeg_vb2_ion; #endif +#if defined(CONFIG_MACH_GC1) +#define MAX_JPEG_WIDTH 4608 +#define MAX_JPEG_HEIGHT 3456 +#else #define MAX_JPEG_WIDTH 3264 #define MAX_JPEG_HEIGHT 2448 +#endif #endif /* __JPEG_MEM_H__ */ diff --git a/drivers/media/video/samsung/jpeg_v2x/jpeg_regs.c b/drivers/media/video/samsung/jpeg_v2x/jpeg_regs.c index e3300cc..0c9bc4b 100644 --- a/drivers/media/video/samsung/jpeg_v2x/jpeg_regs.c +++ b/drivers/media/video/samsung/jpeg_v2x/jpeg_regs.c @@ -341,28 +341,99 @@ void jpeg_set_enc_out_fmt(void __iomem *base, writel(reg, base + S5P_JPEG_IMG_FMT_REG); } -void jpeg_set_enc_tbl(void __iomem *base) +void jpeg_set_enc_tbl(void __iomem *base, + enum jpeg_img_quality_level level) { int i; - for (i = 0; i < 16; i++) { - writel((unsigned int)ITU_Q_tbl[0][i], - base + S5P_JPEG_QUAN_TBL_ENTRY_REG + (i*0x04)); - } + switch (level) { + case QUALITY_LEVEL_1: + for (i = 0; i < 16; i++) { + writel((unsigned int)ITU_Q_tbl[0][i], + base + S5P_JPEG_QUAN_TBL_ENTRY_REG + (i*0x04)); + } - for (i = 0; i < 16; i++) { - writel((unsigned int)ITU_Q_tbl[1][i], - base + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0x40 + (i*0x04)); - } + for (i = 0; i < 16; i++) { + writel((unsigned int)ITU_Q_tbl[1][i], + base + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0x40 + (i*0x04)); + } - for (i = 0; i < 16; i++) { - writel((unsigned int)ITU_Q_tbl[2][i], - base + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0x80 + (i*0x04)); - } + for (i = 0; i < 16; i++) { + writel((unsigned int)ITU_Q_tbl[0][i], + base + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0x80 + (i*0x04)); + } + + for (i = 0; i < 16; i++) { + writel((unsigned int)ITU_Q_tbl[1][i], + base + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0xc0 + (i*0x04)); + } + break; + + case QUALITY_LEVEL_2: + for (i = 0; i < 16; i++) { + writel((unsigned int)ITU_Q_tbl[2][i], + base + S5P_JPEG_QUAN_TBL_ENTRY_REG + (i*0x04)); + } + + for (i = 0; i < 16; i++) { + writel((unsigned int)ITU_Q_tbl[3][i], + base + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0x40 + (i*0x04)); + } - for (i = 0; i < 16; i++) { - writel((unsigned int)ITU_Q_tbl[3][i], - base + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0xc0 + (i*0x04)); + for (i = 0; i < 16; i++) { + writel((unsigned int)ITU_Q_tbl[2][i], + base + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0x80 + (i*0x04)); + } + + for (i = 0; i < 16; i++) { + writel((unsigned int)ITU_Q_tbl[3][i], + base + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0xc0 + (i*0x04)); + } + break; + + case QUALITY_LEVEL_3: + for (i = 0; i < 16; i++) { + writel((unsigned int)ITU_Q_tbl[4][i], + base + S5P_JPEG_QUAN_TBL_ENTRY_REG + (i*0x04)); + } + + for (i = 0; i < 16; i++) { + writel((unsigned int)ITU_Q_tbl[5][i], + base + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0x40 + (i*0x04)); + } + + for (i = 0; i < 16; i++) { + writel((unsigned int)ITU_Q_tbl[4][i], + base + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0x80 + (i*0x04)); + } + + for (i = 0; i < 16; i++) { + writel((unsigned int)ITU_Q_tbl[5][i], + base + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0xc0 + (i*0x04)); + } + break; + + default: + for (i = 0; i < 16; i++) { + writel((unsigned int)ITU_Q_tbl[0][i], + base + S5P_JPEG_QUAN_TBL_ENTRY_REG + (i*0x04)); + } + + for (i = 0; i < 16; i++) { + writel((unsigned int)ITU_Q_tbl[1][i], + base + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0x40 + (i*0x04)); + } + + for (i = 0; i < 16; i++) { + writel((unsigned int)ITU_Q_tbl[0][i], + base + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0x80 + (i*0x04)); + } + + for (i = 0; i < 16; i++) { + writel((unsigned int)ITU_Q_tbl[1][i], + base + S5P_JPEG_QUAN_TBL_ENTRY_REG + 0xc0 + (i*0x04)); + } + break; } for (i = 0; i < 4; i++) { diff --git a/drivers/media/video/samsung/jpeg_v2x/jpeg_regs.h b/drivers/media/video/samsung/jpeg_v2x/jpeg_regs.h index 535a3f9..1dee4b2 100644 --- a/drivers/media/video/samsung/jpeg_v2x/jpeg_regs.h +++ b/drivers/media/video/samsung/jpeg_v2x/jpeg_regs.h @@ -23,7 +23,7 @@ void jpeg_set_enc_in_fmt(void __iomem *base, enum jpeg_frame_format in_fmt); void jpeg_set_enc_out_fmt(void __iomem *base, enum jpeg_stream_format out_fmt); -void jpeg_set_enc_tbl(void __iomem *base); +void jpeg_set_enc_tbl(void __iomem *base, enum jpeg_img_quality_level level); void jpeg_set_interrupt(void __iomem *base); void jpeg_clean_interrupt(void __iomem *base); unsigned int jpeg_get_int_status(void __iomem *base); diff --git a/drivers/media/video/samsung/mali/Kconfig b/drivers/media/video/samsung/mali/Kconfig index b93bccf..ae9bd7d 100644 --- a/drivers/media/video/samsung/mali/Kconfig +++ b/drivers/media/video/samsung/mali/Kconfig @@ -6,7 +6,7 @@ config VIDEO_MALI400MP bool "Enable MALI integration" depends on VIDEO_SAMSUNG - default n + default y ---help--- This enables MALI integration in the multimedia device driver @@ -39,7 +39,6 @@ int "Dedicated Memory Size" ---help--- This value is dedicated memory size of Mali GPU(unit is MByte). - # For DEBUG config VIDEO_MALI400MP_DEBUG bool "Enables debug messages" @@ -48,13 +47,6 @@ config VIDEO_MALI400MP_DEBUG help This enables Mali driver debug messages. -config VIDEO_MALI400MP_STREAMLINE_PROFILING - bool "Enables mali streamline profiling" - depends on VIDEO_MALI400MP - default n - help - This enables Mali streamline profiling. - config VIDEO_MALI400MP_DVFS bool "Enables DVFS" depends on VIDEO_MALI400MP && PM diff --git a/drivers/media/video/samsung/mali/Makefile b/drivers/media/video/samsung/mali/Makefile index 0ce60a3..db5ce6a 100644 --- a/drivers/media/video/samsung/mali/Makefile +++ b/drivers/media/video/samsung/mali/Makefile @@ -10,7 +10,7 @@ OSKOS :=linux FILES_PREFIX= -MALI_FILE_PREFIX := drivers/media/video/samsung/mali +MALI_INCLUDE_PREFIX := drivers/media/video/samsung/mali/ KBUILDROOT = ifeq ($(CONFIG_MALI_DED_ONLY),y) @@ -54,12 +54,8 @@ ifeq ($(CONFIG_VIDEO_MALI400MP_DEBUG),y) BUILD=debug endif -ifeq ($(CONFIG_VIDEO_MALI400MP_STREAMLINE_PROFILING),y) -USING_PROFILING=1 -USING_TRACEPOINTS=1 -endif - # set up defaults if not defined by the user +USE_UMPV2 ?= 0 PANIC_ON_WATCHDOG_TIMEOUT ?= 1 USING_MALI400 ?= 1 USING_MMU ?= 1 @@ -75,21 +71,47 @@ USING_MALI_PMU ?= 0 USING_GPU_UTILIZATION ?= 0 OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB ?= 6 USING_PROFILING ?= 0 +USING_INTERNAL_PROFILING ?= 0 USING_TRACEPOINTS ?= 0 USING_MALI_MAJOR_PREDEFINE = 1 -USING_MALI_DVFS_ENABLED ?= 0 +USING_MALI_DVFS_ENABLED ?= 1 TIMESTAMP ?= default BUILD ?= release USING_MALI_PMM_EARLYSUSPEND ?= 0 #USING_KERNEL_WITH_DMA_ALLOC_PHYS_PAGE ?= 0 -CONFIG_MALI_MEM_SIZE ?= 64 +CONFIG_MALI_MEM_SIZE ?= 512 +DISABLE_PP0 ?= 0 +DISABLE_PP1 ?= 0 +DISABLE_PP2 ?= 0 +DISABLE_PP3 ?= 0 +MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP ?= 0 +MALI_PP_SCHEDULER_KEEP_SUB_JOB_STARTS_ALIGNED ?= 0 +MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP_BETWEEN_APPS ?= 0 + +# Get path to driver source from Linux build system +ifeq ($(USING_PROFILING),1) +ifeq ($(USING_INTERNAL_PROFILING),0) +ifndef CONFIG_TRACEPOINTS +# Should default to gator profiling, but we dont have the kernel feature required, so disable profiling +USING_PROFILING = 0 +endif +endif +endif + +ifeq ($(USING_PROFILING),0) +# make sure user hasnt selected incompatible flags +USING_INTERNAL_PROFILING = 0 +endif + +USING_MALI_SLP_GLOBAL_LOCK ?= 0 #config validtion check ifeq ($(USING_OS_MEMORY),1) USING_MMU = 1 endif + # Check if a Mali Core sub module should be enabled, true or false returned -#submodule_enabled = $(shell gcc $(DEFINES) -E $(MALI_FILE_PREFIX)/arch/config.h | grep type | grep -c $(2)) +#submodule_enabled = $(shell gcc $(DEFINES) -E $(FILES_PREFIX)/arch/config.h | grep type | grep -c $(2)) # Inside the kernel build system @@ -111,14 +133,21 @@ DEFINES += -DMALI_GPU_UTILIZATION=$(USING_GPU_UTILIZATION) DEFINES += -DCONFIG_MALI_MEM_SIZE=$(CONFIG_MALI_MEM_SIZE) DEFINES += -D_MALI_OSK_SPECIFIC_INDIRECT_MMAP DEFINES += -DMALI_TIMELINE_PROFILING_ENABLED=$(USING_PROFILING) +DEFINES += -DMALI_INTERNAL_TIMELINE_PROFILING_ENABLED=$(USING_INTERNAL_PROFILING) DEFINES += -DMALI_POWER_MGMT_TEST_SUITE=$(USING_MALI_PMM_TESTSUITE) DEFINES += -DMALI_MAJOR_PREDEFINE=$(USING_MALI_MAJOR_PREDEFINE) DEFINES += -DMALI_DVFS_ENABLED=$(USING_MALI_DVFS_ENABLED) DEFINES += -DUSING_MALI_PMM_EARLYSUSPEND=$(USING_MALI_PMM_EARLYSUSPEND) -DEFINES += -DMALI_STATE_TRACKING=1 +DEFINES += -DMALI_STATE_TRACKING=0 DEFINES += -DMALI_OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB=$(OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB) DEFINES += -DMALI_TRACEPOINTS_ENABLED=$(USING_TRACEPOINTS) -DEFINES += -DMALI_REBOOTNOTIFIER +DEFINES += -DDISABLE_PP0=$(DISABLE_PP0) +DEFINES += -DDISABLE_PP1=$(DISABLE_PP1) +DEFINES += -DDISABLE_PP2=$(DISABLE_PP2) +DEFINES += -DDISABLE_PP3=$(DISABLE_PP3) +DEFINES += -DMALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP=$(MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP) +DEFINES += -DMALI_PP_SCHEDULER_KEEP_SUB_JOB_STARTS_ALIGNED=$(MALI_PP_SCHEDULER_KEEP_SUB_JOB_STARTS_ALIGNED) +DEFINES += -DMALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP_BETWEEN_APPS=$(MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP_BETWEEN_APPS) ifeq ($(BUILD),debug) DEFINES += -DDEBUG @@ -130,7 +159,7 @@ DEFINES += -DMALI_UKK_HAS_IMPLICIT_MMAP_CLEANUP # UMP ifeq ($(CONFIG_VIDEO_UMP),y) DEFINES += -DMALI_USE_UNIFIED_MEMORY_PROVIDER=1 -DHAVE_UNLOCKED_IOCTL - EXTRA_CFLAGS += -I$(MALI_FILE_PREFIX)/../ump/include + EXTRA_CFLAGS += -I$(MALI_INCLUDE_PREFIX)../ump/include else DEFINES += -DMALI_USE_UNIFIED_MEMORY_PROVIDER=0 endif @@ -141,17 +170,23 @@ obj-$(CONFIG_VIDEO_MALI400MP) += mali.o # Use our defines when compiling # MALI INCLUDES = \ - -I$(MALI_FILE_PREFIX)\ - -I$(MALI_FILE_PREFIX)/platform\ - -I$(MALI_FILE_PREFIX)/common \ - -I$(MALI_FILE_PREFIX)/linux + -I$(MALI_INCLUDE_PREFIX)\ + -I$(MALI_INCLUDE_PREFIX)include \ + -I$(MALI_INCLUDE_PREFIX)platform\ + -I$(MALI_INCLUDE_PREFIX)common \ + -I$(MALI_INCLUDE_PREFIX)linux \ + -I$(MALI_INCLUDE_PREFIX)regs + +ifeq ($(USING_PROFILING),1) +INCLUDES += \ + -I$(MALI_INCLUDE_PREFIX)include +endif EXTRA_CFLAGS += $(INCLUDES)\ $(DEFINES) - -EXTRA_CFLAGS += -I$(MALI_FILE_PREFIX)/linux/license/gpl -EXTRA_CFLAGS += -I$(MALI_FILE_PREFIX)/common/pmm +EXTRA_CFLAGS += -I$(MALI_INCLUDE_PREFIX)linux/license/gpl +EXTRA_CFLAGS += -I$(MALI_INCLUDE_PREFIX)common/pmm # Source files which always are included in a build ifeq ($(CONFIG_VIDEO_UMP),y) @@ -178,11 +213,12 @@ OSKFILES=\ endif #($(CONFIG_VIDEO_UMP),y) ifeq ($(CONFIG_CPU_EXYNOS4210),y) - MALI_PLATFORM_FILE = platform/orion-m400/mali_platform.o + MALI_PLATFORM_DIR = platform/orion-m400 else - MALI_PLATFORM_FILE = platform/pegasus-m400/mali_platform.o + MALI_PLATFORM_DIR = platform/pegasus-m400 endif #($(CONFIG_CPU_EXYNOS4210),y) +MALI_PLATFORM_FILE=$(MALI_PLATFORM_DIR)/mali_platform.o UKKFILES=\ $(FILES_PREFIX)$(OSKOS)/mali_ukk_mem.o \ $(FILES_PREFIX)$(OSKOS)/mali_ukk_gp.o \ @@ -190,85 +226,94 @@ UKKFILES=\ $(FILES_PREFIX)$(OSKOS)/mali_ukk_core.o \ $(FILES_PREFIX)$(OSKOS)/mali_ukk_vsync.o -mali-y := \ - $(KBUILDROOT)common/mali_kernel_core.o \ - $(KBUILDROOT)linux/mali_kernel_linux.o \ - $(KBUILDROOT)linux/mali_osk_indir_mmap.o \ - $(KBUILDROOT)common/mali_kernel_rendercore.o \ - $(KBUILDROOT)common/mali_kernel_descriptor_mapping.o \ - $(KBUILDROOT)common/mali_kernel_vsync.o \ - $(KBUILDROOT)linux/mali_kernel_sysfs.o \ - $(KBUILDROOT)$(MALI_PLATFORM_FILE) \ - $(KBUILDROOT)$(OSKFILES) \ - $(KBUILDROOT)$(UKKFILES) - #__malidrv_build_info.o - ifeq ($(USING_PROFILING),1) -EXTRA_CFLAGS += -I$(MALI_FILE_PREFIX)/timestamp-default -EXTRA_CFLAGS += -I$(MALI_FILE_PREFIX)/profiling/include -mali-y += \ - common/mali_kernel_profiling.o \ - timestamp-$(TIMESTAMP)/mali_timestamp.o \ - linux/mali_ukk_profiling.o - -EXTRA_CFLAGS += -I$(KBUILD_EXTMOD)/timestamp-$(TIMESTAMP) +UKKFILES += \ + $(FILES_PREFIX)$(OSKOS)/mali_ukk_profiling.o endif -ifeq ($(USING_TRACEPOINTS),1) -mali-y += \ - linux/mali_osk_profiling.o -endif +mali-y := \ + common/mali_kernel_core.o \ + linux/mali_kernel_linux.o \ + $(OSKOS)/mali_osk_indir_mmap.o \ + common/mali_kernel_descriptor_mapping.o \ + common/mali_session.o \ + common/mali_device_pause_resume.o \ + common/mali_kernel_vsync.o \ + linux/mali_ukk_vsync.o \ + linux/mali_kernel_sysfs.o \ + common/mali_mmu.o \ + common/mali_mmu_page_directory.o \ + common/mali_memory.o \ + common/mali_kernel_memory_engine.o \ + common/mali_block_allocator.o \ + common/mali_kernel_mem_os.o \ + common/mali_mem_validation.o \ + common/mali_hw_core.o \ + common/mali_gp.o \ + common/mali_pp.o \ + common/mali_pp_job.o \ + common/mali_gp_job.o \ + common/mali_scheduler.o \ + common/mali_gp_scheduler.o \ + common/mali_pp_scheduler.o \ + common/mali_cluster.o \ + common/mali_group.o \ + common/mali_dlbu.o \ + common/mali_pm.o \ + common/mali_pmu.o \ + common/mali_user_settings_db.o \ + $(OSKOS)/mali_osk_pm.o \ + linux/mali_kernel_pm.o \ + $(OSKOS)/mali_osk_wait_queue.o \ + $(MALI_PLATFORM_FILE) \ + $(OSKFILES) \ + $(UKKFILES) +# __malidrv_build_info.c # Selecting files to compile by parsing the config file -ifeq ($(USING_PMM),1) -mali-y += \ - common/pmm/mali_pmm.o \ - common/pmm/mali_pmm_policy.o \ - common/pmm/mali_pmm_policy_alwayson.o \ - common/pmm/mali_pmm_policy_jobcontrol.o \ - common/pmm/mali_pmm_state.o \ - linux/mali_kernel_pm.o \ - linux/mali_osk_pm.o \ - linux/mali_device_pause_resume.o +ifeq ($(USING_INTERNAL_PROFILING),1) +PROFILING_BACKEND_SOURCES = \ + linux/mali_osk_profiling_internal.o \ + timestamp-$(TIMESTAMP)/mali_timestamp.o +EXTRA_CFLAGS += -I$(MALI_INCLUDE_PREFIX)timestamp-$(TIMESTAMP) +else +ifeq ($(USING_PROFILING),1) +PROFILING_BACKEND_SOURCES = \ + linux/mali_osk_profiling_gator.o endif -ifeq ($(USING_MALI_PMU),1) -mali-y += \ - common/pmm/mali_pmm_pmu.o +endif + +# Add the profiling sources +mali-y += $(PROFILING_BACKEND_SOURCES) + +# Mali-400 PP in use +ifeq ($(USING_MALI_PMM_TESTSUITE),1) +EXTRA_CFLAGS += -I$(MALI_INCLUDE_PREFIX)platform/mali_pmu_testing endif ifeq ($(USING_GPU_UTILIZATION),1) +EXTRA_CFLAGS += -DCONFIG_MALI400_GPU_UTILIZATION=1 + mali-y += \ common/mali_kernel_utilization.o endif -# Mali-400 PP in use -EXTRA_CFLAGS += -DUSING_MALI400 -mali-y += common/mali_kernel_MALI200.o - -# Mali-400 GP in use -mali-y += common/mali_kernel_GP2.o +ifeq ($(USING_MALI_DVFS_ENABLED),1) +mali-y += $(MALI_PLATFORM_DIR)/mali_platform_dvfs.o +endif #($(USING_MALI_DVFS_ENABLED),1) -# Mali MMU in use -mali-y += \ - common/mali_kernel_mem_mmu.o \ - common/mali_kernel_memory_engine.o \ - common/mali_block_allocator.o \ - common/mali_kernel_mem_os.o +EXTRA_CFLAGS += -DUSING_MALI400 # Mali Level2 cache in use EXTRA_CFLAGS += -DUSING_MALI400_L2_CACHE -mali-y += common/mali_kernel_l2_cache.o - -ifeq ($(USING_MALI_DVFS_ENABLED),1) -ifeq ($(CONFIG_CPU_EXYNOS4210),y) +mali-y += common/mali_l2_cache.o +# Mali SLP Global lock feature +ifeq ($(USING_MALI_SLP_GLOBAL_LOCK),1) mali-y += \ - platform/orion-m400/mali_platform_dvfs.o -else -mali-y += \ - platform/pegasus-m400/mali_platform_dvfs.o -endif #($(CONFIG_CPU_EXYNOS4210),y) -endif #($(USING_MALI_DVFS_ENABLED),1) + linux/mali_slp_global_lock.o +endif + ifeq ($(PANIC_ON_WATCHDOG_TIMEOUT),1) EXTRA_CFLAGS += -DUSING_KERNEL_PANIC diff --git a/drivers/media/video/samsung/mali/Makefile.common b/drivers/media/video/samsung/mali/Makefile.common deleted file mode 100644 index 53d4e5b..0000000 --- a/drivers/media/video/samsung/mali/Makefile.common +++ /dev/null @@ -1,59 +0,0 @@ -# -# Copyright (C) 2010 ARM Limited. All rights reserved. -# -# This program is free software and is provided to you under the terms of the GNU General Public License version 2 -# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. -# -# A copy of the licence is included with the program, and can also be obtained from Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# - -# Check if a Mali Core sub module should be enabled, true or false returned -submodule_enabled = $(shell gcc $(DEFINES) -E $1/arch/config.h | grep type | grep -c $(2)) - -OSKFILES=\ - $(FILES_PREFIX)$(OSKOS)/mali_osk_atomics.c \ - $(FILES_PREFIX)$(OSKOS)/mali_osk_irq.c \ - $(FILES_PREFIX)$(OSKOS)/mali_osk_locks.c \ - $(FILES_PREFIX)$(OSKOS)/mali_osk_low_level_mem.c \ - $(FILES_PREFIX)$(OSKOS)/mali_osk_math.c \ - $(FILES_PREFIX)$(OSKOS)/mali_osk_memory.c \ - $(FILES_PREFIX)$(OSKOS)/mali_osk_misc.c \ - $(FILES_PREFIX)$(OSKOS)/mali_osk_mali.c \ - $(FILES_PREFIX)$(OSKOS)/mali_osk_notification.c \ - $(FILES_PREFIX)$(OSKOS)/mali_osk_time.c \ - $(FILES_PREFIX)$(OSKOS)/mali_osk_timers.c - -UKKFILES=\ - $(FILES_PREFIX)$(OSKOS)/mali_ukk_mem.c \ - $(FILES_PREFIX)$(OSKOS)/mali_ukk_gp.c \ - $(FILES_PREFIX)$(OSKOS)/mali_ukk_pp.c \ - $(FILES_PREFIX)$(OSKOS)/mali_ukk_core.c - -ifeq ($(USING_PROFILING),1) -UKKFILES+=\ - $(FILES_PREFIX)$(OSKOS)/mali_ukk_profiling.c -endif - -ifeq ($(MALI_PLATFORM_FILE),) -MALI_PLATFORM_FILE=platform/default/mali_platform.c -endif - -# Get subversion revision number, fall back to only ${MALI_RELEASE_NAME} if no svn info is available -SVN_REV := $(shell (cd $(DRIVER_DIR); (svnversion | grep -qv exported && svnversion) || git svn info | grep '^Revision: '| sed -e 's/^Revision: //' ) 2>/dev/null ) -ifeq ($(SVN_REV),) -SVN_REV := $(MALI_RELEASE_NAME) -else -SVN_REV := $(MALI_RELEASE_NAME)-r$(SVN_REV) -endif - -# Common version-string, will be extended by OS-specifc sections -VERSION_STRINGS := -VERSION_STRINGS += CONFIG=$(CONFIG) -VERSION_STRINGS += USING_OS_MEMORY=$(USING_OS_MEMORY) -VERSION_STRINGS += API_VERSION=$(shell cd $(DRIVER_DIR); grep "\#define _MALI_API_VERSION" $(FILES_PREFIX)common\/mali_uk_types.h | cut -d' ' -f 3 ) -VERSION_STRINGS += REPO_URL=$(shell cd $(DRIVER_DIR); (svn info || git svn info || echo 'URL: $(MALI_RELEASE_NAME)') 2>/dev/null | grep '^URL: ' | cut -d: -f2- | cut -b2-) -VERSION_STRINGS += REVISION=$(SVN_REV) -VERSION_STRINGS += CHANGED_REVISION=$(shell cd $(DRIVER_DIR); (svn info || git svn info || echo 'Last Changed Rev: $(MALI_RELEASE_NAME)') 2>/dev/null | grep '^Last Changed Rev: ' | cut -d: -f2- | cut -b2-) -VERSION_STRINGS += CHANGE_DATE=$(shell cd $(DRIVER_DIR); (svn info || git svn info || echo 'Last Changed Date: $(MALI_RELEASE_NAME)') 2>/dev/null | grep '^Last Changed Date: ' | cut -d: -f2- | cut -b2-) -VERSION_STRINGS += BUILD_DATE=$(shell date) diff --git a/drivers/media/video/samsung/mali/Makefile_module b/drivers/media/video/samsung/mali/Makefile_module new file mode 100644 index 0000000..4fb0226 --- /dev/null +++ b/drivers/media/video/samsung/mali/Makefile_module @@ -0,0 +1,89 @@ +# +# Copyright (C) 2010-2012 ARM Limited. All rights reserved. +# +# This program is free software and is provided to you under the terms of the GNU General Public License version 2 +# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. +# +# A copy of the licence is included with the program, and can also be obtained from Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +USE_UMPV2=0 + +# The Makefile sets up "arch" based on the CONFIG, creates the version info +# string and the __malidrv_build_info.c file, and then call the Linux build +# system to actually build the driver. After that point the Kbuild file takes +# over. + +# set up defaults if not defined by the user +ARCH ?= arm + +OSKOS=linux +FILES_PREFIX= + +# This conditional makefile exports the global definition ARM_INTERNAL_BUILD. Customer releases will not include arm_internal.mak +-include ../../../arm_internal.mak + +# Check that required parameters are supplied. +ifeq ($(CONFIG),) +$(error "CONFIG must be specified.") +endif +ifeq ($(CPU)$(KDIR),) +$(error "KDIR or CPU must be specified.") +endif + +ifeq ($(USING_UMP),1) +ifeq ($(USE_UMPV2),1) +UMP_SYMVERS_FILE ?= ../umpv2/Module.symvers +else +UMP_SYMVERS_FILE ?= ../ump/Module.symvers +endif +KBUILD_EXTRA_SYMBOLS = $(realpath $(UMP_SYMVERS_FILE)) +$(warning $(KBUILD_EXTRA_SYMBOLS)) +endif + +# Get any user defined KDIR-<names> or maybe even a hardcoded KDIR +-include KDIR_CONFIGURATION + +# Define host system directory +KDIR-$(shell uname -m):=/lib/modules/$(shell uname -r)/build + +ifeq ($(ARCH), arm) + # when compiling for ARM we're cross compiling + export CROSS_COMPILE ?= arm-none-linux-gnueabi- +endif + +# look up KDIR based om CPU selection +KDIR ?= $(KDIR-$(CPU)) + +# validate lookup result +ifeq ($(KDIR),) +$(error No KDIR found for platform $(CPU)) +endif + +# report detected/selected settings +ifdef ARM_INTERNAL_BUILD +$(warning Config $(CONFIG)) +$(warning Host CPU $(CPU)) +$(warning OS_MEMORY $(USING_OS_MEMORY)) +endif + +# Set up build config +export CONFIG_MALI400=m + +ifeq ($(USING_GPU_UTILIZATION),1) +export EXTRA_DEFINES += -DCONFIG_MALI400_GPU_UTILIZATION=1 +export CONFIG_MALI400_GPU_UTILIZATION := y +endif + +all: $(UMP_SYMVERS_FILE) + $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) modules + @rm $(FILES_PREFIX)__malidrv_build_info.c $(FILES_PREFIX)__malidrv_build_info.o + +clean: + $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) clean + +kernelrelease: + $(MAKE) ARCH=$(ARCH) -C $(KDIR) kernelrelease + +export CONFIG KBUILD_EXTRA_SYMBOLS diff --git a/drivers/media/video/samsung/mali/arch b/drivers/media/video/samsung/mali/arch deleted file mode 120000 index 6154ca4..0000000 --- a/drivers/media/video/samsung/mali/arch +++ /dev/null @@ -1 +0,0 @@ -arch-orion-m400
\ No newline at end of file diff --git a/drivers/media/video/samsung/mali/arch-orion-m400/config.h b/drivers/media/video/samsung/mali/arch-debug/config.h index 5c4d79d..d5196c3 100644 --- a/drivers/media/video/samsung/mali/arch-orion-m400/config.h +++ b/drivers/media/video/samsung/mali/arch-debug/config.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. diff --git a/drivers/media/video/samsung/mali/arch-pb-virtex5-m300/config.h b/drivers/media/video/samsung/mali/arch-pb-virtex5-m300/config.h new file mode 100644 index 0000000..e579526 --- /dev/null +++ b/drivers/media/video/samsung/mali/arch-pb-virtex5-m300/config.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __ARCH_CONFIG_H__ +#define __ARCH_CONFIG_H__ + +/* Configuration for the PB platform with ZBT memory enabled */ + +static _mali_osk_resource_t arch_configuration [] = +{ + { + .type = PMU, + .description = "Mali-300 PMU", + .base = 0xC0002000, + .irq = -1, + .mmu_id = 0 + + }, + { + .type = MALI300GP, + .description = "Mali-300 GP", + .base = 0xC0000000, + .irq = -1, + .mmu_id = 1 + }, + { + .type = MALI300PP, + .base = 0xc0008000, + .irq = -1, + .description = "Mali-300 PP", + .mmu_id = 2 + }, + { + .type = MMU, + .base = 0xC0003000, + .irq = -1, + .description = "Mali-300 MMU for GP", + .mmu_id = 1 + }, + { + .type = MMU, + .base = 0xC0004000, + .irq = -1, + .description = "Mali-300 MMU for PP", + .mmu_id = 2 + }, + { + .type = MEMORY, + .description = "Mali SDRAM remapped to baseboard", + .cpu_usage_adjust = -0x50000000, + .alloc_order = 0, /* Highest preference for this memory */ + .base = 0xD0000000, + .size = 0x10000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, + { + .type = MEMORY, + .description = "Mali ZBT", + .alloc_order = 5, /* Medium preference for this memory */ + .base = 0xe1000000, + .size = 0x01000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, + { + .type = MEM_VALIDATION, + .description = "Framebuffer", + .base = 0xe0000000, + .size = 0x01000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_WRITEABLE | _MALI_PP_READABLE + }, + { + .type = MALI300L2, + .base = 0xC0001000, + .description = "Mali-300 L2 cache" + }, +}; + +#endif /* __ARCH_CONFIG_H__ */ diff --git a/drivers/media/video/samsung/mali/arch-pb-virtex5-m400-1-direct/config.h b/drivers/media/video/samsung/mali/arch-pb-virtex5-m400-1-direct/config.h new file mode 100644 index 0000000..3893d72 --- /dev/null +++ b/drivers/media/video/samsung/mali/arch-pb-virtex5-m400-1-direct/config.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __ARCH_CONFIG_H__ +#define __ARCH_CONFIG_H__ + +/* Configuration for the PB platform with ZBT memory enabled */ + +static _mali_osk_resource_t arch_configuration [] = +{ + + { + .type = PMU, + .description = "Mali-400 PMU", + .base = 0xC0002000, + .irq = -1, + .mmu_id = 0 + }, + { + .type = MALI400GP, + .description = "Mali-400 GP", + .base = 0xC0000000, + .irq = -1, + .mmu_id = 1 + }, + { + .type = MALI400PP, + .base = 0xc0008000, + .irq = -1, + .description = "Mali-400 PP", + .mmu_id = 2 + }, + { + .type = MMU, + .base = 0xC0003000, + .irq = -1, + .description = "Mali-400 MMU for GP", + .mmu_id = 1 + }, + { + .type = MMU, + .base = 0xC0004000, + .irq = -1, + .description = "Mali-400 MMU for PP", + .mmu_id = 2 + }, + { + .type = OS_MEMORY, + .description = "OS Memory", + .alloc_order = 10, /* Lowest preference for this memory */ + .size = 96 * 1024 * 1024, /* 96 MB */ + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, + { + .type = MEMORY, + .description = "Mali SDRAM remapped to baseboard", + .cpu_usage_adjust = 0, + .alloc_order = 5, /* Medium preference for this memory */ + .base = 0x80000000, + .size = 0x10000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, + { + .type = MEMORY, + .description = "Mali ZBT", + .alloc_order = 0, /* Highest preference for this memory */ + .base = 0xe1000000, + .size = 0x01000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, + { + .type = MEM_VALIDATION, + .description = "Framebuffer", + .base = 0xe0000000, + .size = 0x01000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_WRITEABLE | _MALI_PP_READABLE + }, + { + .type = MALI400L2, + .base = 0xC0001000, + .description = "Mali-400 L2 cache" + }, +}; + +#endif /* __ARCH_CONFIG_H__ */ diff --git a/drivers/media/video/samsung/mali/arch-pb-virtex5-m400-1-pmu/config.h b/drivers/media/video/samsung/mali/arch-pb-virtex5-m400-1-pmu/config.h new file mode 100644 index 0000000..d85c090 --- /dev/null +++ b/drivers/media/video/samsung/mali/arch-pb-virtex5-m400-1-pmu/config.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2010-2011 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __ARCH_CONFIG_H__ +#define __ARCH_CONFIG_H__ + +/* Configuration for the PB platform with ZBT memory enabled */ + +static _mali_osk_resource_t arch_configuration [] = +{ + { + .type = PMU, + .description = "Mali-400 PMU", + .base = 0xC0002000, + .irq = -1, + .mmu_id = 0 + + }, + { + .type = MALI400GP, + .description = "Mali-400 GP", + .base = 0xC0000000, + .irq = -1, + .mmu_id = 1 + }, + { + .type = MALI400PP, + .base = 0xc0008000, + .irq = -1, + .description = "Mali-400 PP", + .mmu_id = 2 + }, + { + .type = MMU, + .base = 0xC0003000, + .irq = -1, + .description = "Mali-400 MMU for GP", + .mmu_id = 1 + }, + { + .type = MMU, + .base = 0xC0004000, + .irq = -1, + .description = "Mali-400 MMU for PP", + .mmu_id = 2 + }, + { + .type = MEMORY, + .description = "Mali SDRAM remapped to baseboard", + .cpu_usage_adjust = -0x50000000, + .alloc_order = 0, /* Highest preference for this memory */ + .base = 0xD0000000, + .size = 0x10000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, + { + .type = MEMORY, + .description = "Mali ZBT", + .alloc_order = 5, /* Medium preference for this memory */ + .base = 0xe1000000, + .size = 0x01000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, + { + .type = MEM_VALIDATION, + .description = "Framebuffer", + .base = 0xe0000000, + .size = 0x01000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_WRITEABLE | _MALI_PP_READABLE + }, + { + .type = MALI400L2, + .base = 0xC0001000, + .description = "Mali-400 L2 cache" + }, +}; + +#endif /* __ARCH_CONFIG_H__ */ diff --git a/drivers/media/video/samsung/mali/arch-pb-virtex5-m400-1/config.h b/drivers/media/video/samsung/mali/arch-pb-virtex5-m400-1/config.h new file mode 100644 index 0000000..568ac0a --- /dev/null +++ b/drivers/media/video/samsung/mali/arch-pb-virtex5-m400-1/config.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __ARCH_CONFIG_H__ +#define __ARCH_CONFIG_H__ + +/* Configuration for the PB platform with ZBT memory enabled */ + +static _mali_osk_resource_t arch_configuration [] = +{ + { + .type = MALI400GP, + .description = "Mali-400 GP", + .base = 0xC0000000, + .irq = -1, + .mmu_id = 1 + }, + { + .type = MALI400PP, + .base = 0xc0008000, + .irq = -1, + .description = "Mali-400 PP", + .mmu_id = 2 + }, + { + .type = MMU, + .base = 0xC0003000, + .irq = -1, + .description = "Mali-400 MMU for GP", + .mmu_id = 1 + }, + { + .type = MMU, + .base = 0xC0004000, + .irq = -1, + .description = "Mali-400 MMU for PP", + .mmu_id = 2 + }, + { + .type = MEMORY, + .description = "Mali SDRAM remapped to baseboard", + .cpu_usage_adjust = -0x50000000, + .alloc_order = 0, /* Highest preference for this memory */ + .base = 0xD0000000, + .size = 0x10000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, + { + .type = MEMORY, + .description = "Mali ZBT", + .alloc_order = 5, /* Medium preference for this memory */ + .base = 0xe1000000, + .size = 0x01000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, + { + .type = MEM_VALIDATION, + .description = "Framebuffer", + .base = 0xe0000000, + .size = 0x01000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_WRITEABLE | _MALI_PP_READABLE + }, + { + .type = MALI400L2, + .base = 0xC0001000, + .description = "Mali-400 L2 cache" + }, +}; + +#endif /* __ARCH_CONFIG_H__ */ diff --git a/drivers/media/video/samsung/mali/arch-pb-virtex5-m400-2/config.h b/drivers/media/video/samsung/mali/arch-pb-virtex5-m400-2/config.h new file mode 100644 index 0000000..98b8059 --- /dev/null +++ b/drivers/media/video/samsung/mali/arch-pb-virtex5-m400-2/config.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __ARCH_CONFIG_H__ +#define __ARCH_CONFIG_H__ + +/* Configuration for the PB platform with ZBT memory enabled */ + +static _mali_osk_resource_t arch_configuration [] = +{ + { + .type = MALI400GP, + .description = "Mali-400 GP", + .base = 0xC0000000, + .irq = -1, + .mmu_id = 1 + }, + { + .type = MALI400PP, + .base = 0xc0008000, + .irq = -1, + .description = "Mali-400 PP 0", + .mmu_id = 2 + }, + { + .type = MALI400PP, + .base = 0xc000A000, + .irq = -1, + .description = "Mali-400 PP 1", + .mmu_id = 3 + }, + { + .type = MMU, + .base = 0xC0003000, + .irq = -1, + .description = "Mali-400 MMU for GP", + .mmu_id = 1 + }, + { + .type = MMU, + .base = 0xC0004000, + .irq = -1, + .description = "Mali-400 MMU for PP 0", + .mmu_id = 2 + }, + { + .type = MMU, + .base = 0xC0005000, + .irq = -1, + .description = "Mali-400 MMU for PP 1", + .mmu_id = 3 + }, + { + .type = MEMORY, + .description = "Mali SDRAM remapped to baseboard", + .cpu_usage_adjust = -0x50000000, + .alloc_order = 0, /* Highest preference for this memory */ + .base = 0xD0000000, + .size = 0x10000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, + { + .type = MEMORY, + .description = "Mali ZBT", + .alloc_order = 5, /* Medium preference for this memory */ + .base = 0xe1000000, + .size = 0x01000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, + { + .type = MEM_VALIDATION, + .description = "Framebuffer", + .base = 0xe0000000, + .size = 0x01000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_WRITEABLE | _MALI_PP_READABLE + }, + { + .type = MALI400L2, + .base = 0xC0001000, + .description = "Mali-400 L2 cache" + }, +}; + +#endif /* __ARCH_CONFIG_H__ */ diff --git a/drivers/media/video/samsung/mali/arch-pb-virtex5-m400-3/config.h b/drivers/media/video/samsung/mali/arch-pb-virtex5-m400-3/config.h new file mode 100644 index 0000000..7b10925 --- /dev/null +++ b/drivers/media/video/samsung/mali/arch-pb-virtex5-m400-3/config.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __ARCH_CONFIG_H__ +#define __ARCH_CONFIG_H__ + +/* Configuration for the PB platform with ZBT memory enabled */ + +static _mali_osk_resource_t arch_configuration [] = +{ + { + .type = MALI400GP, + .description = "Mali-400 GP", + .base = 0xC0000000, + .irq = -1, + .mmu_id = 1 + }, + { + .type = MALI400PP, + .base = 0xc0008000, + .irq = -1, + .description = "Mali-400 PP 0", + .mmu_id = 2 + }, + { + .type = MALI400PP, + .base = 0xc000A000, + .irq = -1, + .description = "Mali-400 PP 1", + .mmu_id = 3 + }, + { + .type = MALI400PP, + .base = 0xc000C000, + .irq = -1, + .description = "Mali-400 PP 2", + .mmu_id = 4 + }, + { + .type = MMU, + .base = 0xC0003000, + .irq = 102, + .description = "Mali-400 MMU for GP", + .mmu_id = 1 + }, + { + .type = MMU, + .base = 0xC0004000, + .irq = 102, + .description = "Mali-400 MMU for PP 0", + .mmu_id = 2 + }, + { + .type = MMU, + .base = 0xC0005000, + .irq = 102, + .description = "Mali-400 MMU for PP 1", + .mmu_id = 3 + }, + { + .type = MMU, + .base = 0xC0006000, + .irq = 102, + .description = "Mali-400 MMU for PP 2", + .mmu_id = 4 + }, + { + .type = MEMORY, + .description = "Mali SDRAM remapped to baseboard", + .cpu_usage_adjust = -0x50000000, + .alloc_order = 0, /* Highest preference for this memory */ + .base = 0xD0000000, + .size = 0x10000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, + { + .type = MEMORY, + .description = "Mali ZBT", + .alloc_order = 5, /* Medium preference for this memory */ + .base = 0xe1000000, + .size = 0x01000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, + { + .type = MEM_VALIDATION, + .description = "Framebuffer", + .base = 0xe0000000, + .size = 0x01000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_WRITEABLE | _MALI_PP_READABLE + }, + { + .type = MALI400L2, + .base = 0xC0001000, + .description = "Mali-400 L2 cache" + }, +}; + +#endif /* __ARCH_CONFIG_H__ */ diff --git a/drivers/media/video/samsung/mali/arch-pb-virtex5-m400-4/config.h b/drivers/media/video/samsung/mali/arch-pb-virtex5-m400-4/config.h new file mode 100644 index 0000000..a15a6bd --- /dev/null +++ b/drivers/media/video/samsung/mali/arch-pb-virtex5-m400-4/config.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __ARCH_CONFIG_H__ +#define __ARCH_CONFIG_H__ + +/* Configuration for the EB platform with ZBT memory enabled */ + +static _mali_osk_resource_t arch_configuration [] = +{ + { + .type = MALI400GP, + .description = "Mali-400 GP", + .base = 0xC0000000, + .irq = -1, + .mmu_id = 1 + }, + { + .type = MALI400PP, + .base = 0xc0008000, + .irq = -1, + .description = "Mali-400 PP 0", + .mmu_id = 2 + }, + { + .type = MALI400PP, + .base = 0xc000A000, + .irq = -1, + .description = "Mali-400 PP 1", + .mmu_id = 3 + }, + { + .type = MALI400PP, + .base = 0xc000C000, + .irq = -1, + .description = "Mali-400 PP 2", + .mmu_id = 4 + }, + { + .type = MALI400PP, + .base = 0xc000E000, + .irq = -1, + .description = "Mali-400 PP 3", + .mmu_id = 5 + }, + { + .type = MMU, + .base = 0xC0003000, + .irq = 102, + .description = "Mali-400 MMU for GP", + .mmu_id = 1 + }, + { + .type = MMU, + .base = 0xC0004000, + .irq = 102, + .description = "Mali-400 MMU for PP 0", + .mmu_id = 2 + }, + { + .type = MMU, + .base = 0xC0005000, + .irq = 102, + .description = "Mali-400 MMU for PP 1", + .mmu_id = 3 + }, + { + .type = MMU, + .base = 0xC0006000, + .irq = 102, + .description = "Mali-400 MMU for PP 2", + .mmu_id = 4 + }, + { + .type = MMU, + .base = 0xC0007000, + .irq = 102, + .description = "Mali-400 MMU for PP 3", + .mmu_id = 5 + }, + { + .type = MEMORY, + .description = "Mali SDRAM remapped to baseboard", + .cpu_usage_adjust = -0x50000000, + .alloc_order = 0, /* Highest preference for this memory */ + .base = 0xD0000000, + .size = 0x10000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, + { + .type = MEMORY, + .description = "Mali ZBT", + .alloc_order = 5, /* Medium preference for this memory */ + .base = 0xe1000000, + .size = 0x01000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, + { + .type = MEM_VALIDATION, + .description = "Framebuffer", + .base = 0xe0000000, + .size = 0x01000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_WRITEABLE | _MALI_PP_READABLE + }, + { + .type = MALI400L2, + .base = 0xC0001000, + .description = "Mali-400 L2 cache" + }, +}; + +#endif /* __ARCH_CONFIG_H__ */ diff --git a/drivers/media/video/samsung/mali/arch-pegasus-m400/config.h b/drivers/media/video/samsung/mali/arch-pegasus-m400/config.h new file mode 100644 index 0000000..d5196c3 --- /dev/null +++ b/drivers/media/video/samsung/mali/arch-pegasus-m400/config.h @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __ARCH_CONFIG_H__ +#define __ARCH_CONFIG_H__ + +/* Configuration for the EB platform with ZBT memory enabled */ +/*zepplin added 2010.08.17 for orion configuration*/ +#define MALI_BASE_ADDR 0x13000000 +#define GP_ADDR MALI_BASE_ADDR +#define L2_ADDR MALI_BASE_ADDR+0x1000 +#define PMU_ADDR MALI_BASE_ADDR+0x2000 +#define GP_MMU_ADDR MALI_BASE_ADDR+0x3000 +#define PP0_MMU_ADDR MALI_BASE_ADDR+0x4000 +#define PP1_MMU_ADDR MALI_BASE_ADDR+0x5000 +#define PP2_MMU_ADDR MALI_BASE_ADDR+0x6000 +#define PP3_MMU_ADDR MALI_BASE_ADDR+0x7000 +#define PP0_ADDR MALI_BASE_ADDR+0x8000 +#define PP1_ADDR MALI_BASE_ADDR+0xA000 +#define PP2_ADDR MALI_BASE_ADDR+0xC000 +#define PP3_ADDR MALI_BASE_ADDR+0xE000 + +/*for mmu and os memory*/ +#define MEM_BASE_ADDR 0x40000000 +#define MEM_TOTAL_SIZE 0x40000000 +#define MEM_MALI_OS_SIZE 0x40000000 + +/*for dedicated memory*/ +//#define MEM_MALI_BASE 0x58000000 +//#define MEM_MALI_SIZE 0x08000000 +#define MEM_MALI_SIZE CONFIG_MALI_MEM_SIZE*1024*1024 +#define MEM_MALI_BASE 0x80000000 - MEM_MALI_SIZE + +static _mali_osk_resource_t arch_configuration [] = +{ + { + .type = MALI400GP, + .description = "Mali-400 GP", + .base = GP_ADDR, + .irq = IRQ_GP_3D, + .mmu_id = 1 + }, + { + .type = MALI400PP, + .base = PP0_ADDR, + .irq = IRQ_PP0_3D, + .description = "Mali-400 PP 0", + .mmu_id = 2 + }, + { + .type = MALI400PP, + .base = PP1_ADDR, + .irq = IRQ_PP1_3D, + .description = "Mali-400 PP 1", + .mmu_id = 3 + }, + { + .type = MALI400PP, + .base = PP2_ADDR, + .irq = IRQ_PP2_3D, + .description = "Mali-400 PP 2", + .mmu_id = 4 + }, + { + .type = MALI400PP, + .base = PP3_ADDR, + .irq = IRQ_PP3_3D, + .description = "Mali-400 PP 3", + .mmu_id = 5 + }, +#if USING_MMU + { + .type = MMU, + .base = GP_MMU_ADDR, + .irq = IRQ_GPMMU_3D, + .description = "Mali-400 MMU for GP", + .mmu_id = 1 + }, + { + .type = MMU, + .base = PP0_MMU_ADDR, + .irq = IRQ_PPMMU0_3D, + .description = "Mali-400 MMU for PP 0", + .mmu_id = 2 + }, + { + .type = MMU, + .base = PP1_MMU_ADDR, + .irq = IRQ_PPMMU1_3D, + .description = "Mali-400 MMU for PP 1", + .mmu_id = 3 + }, + { + .type = MMU, + .base = PP2_MMU_ADDR, + .irq = IRQ_PPMMU2_3D, + .description = "Mali-400 MMU for PP 2", + .mmu_id = 4 + }, + { + .type = MMU, + .base = PP3_MMU_ADDR, + .irq = IRQ_PPMMU3_3D, + .description = "Mali-400 MMU for PP 3", + .mmu_id = 5 + }, +#if USING_OS_MEMORY + { + .type = OS_MEMORY, + .description = "System Memory", + .size = MEM_MALI_OS_SIZE, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE | _MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, +#endif +#if USING_DED /* Dedicated Memory */ + { + .type = MEMORY, + .description = "Dedicated Memory", + .base = MEM_MALI_BASE, + .size = MEM_MALI_SIZE, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE | _MALI_GP_READABLE | _MALI_GP_WRITEABLE | _MALI_MMU_READABLE | _MALI_MMU_WRITEABLE + }, +#endif/* if USING_OS_MEMORY*/ + { + .type = MEM_VALIDATION, + .description = "memory validation", + .base = MEM_BASE_ADDR, + .size = MEM_TOTAL_SIZE, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE | _MALI_GP_READABLE | _MALI_GP_WRITEABLE | _MALI_MMU_READABLE | _MALI_MMU_WRITEABLE + }, +#else /* Not using MMU */ + { + .type = MEMORY, + .description = "Dedicated Memory", + .base = MEM_MALI_BASE, + .size = MEM_MALI_SIZE, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE | _MALI_GP_READABLE | _MALI_GP_WRITEABLE | _MALI_MMU_READABLE | _MALI_MMU_WRITEABLE + }, +#endif + { + .type = MALI400L2, + .base = L2_ADDR, + .description = "Mali-400 L2 cache" + }, +}; + +#endif /* __ARCH_CONFIG_H__ */ diff --git a/drivers/media/video/samsung/mali/arch-release/config.h b/drivers/media/video/samsung/mali/arch-release/config.h new file mode 100644 index 0000000..d5196c3 --- /dev/null +++ b/drivers/media/video/samsung/mali/arch-release/config.h @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __ARCH_CONFIG_H__ +#define __ARCH_CONFIG_H__ + +/* Configuration for the EB platform with ZBT memory enabled */ +/*zepplin added 2010.08.17 for orion configuration*/ +#define MALI_BASE_ADDR 0x13000000 +#define GP_ADDR MALI_BASE_ADDR +#define L2_ADDR MALI_BASE_ADDR+0x1000 +#define PMU_ADDR MALI_BASE_ADDR+0x2000 +#define GP_MMU_ADDR MALI_BASE_ADDR+0x3000 +#define PP0_MMU_ADDR MALI_BASE_ADDR+0x4000 +#define PP1_MMU_ADDR MALI_BASE_ADDR+0x5000 +#define PP2_MMU_ADDR MALI_BASE_ADDR+0x6000 +#define PP3_MMU_ADDR MALI_BASE_ADDR+0x7000 +#define PP0_ADDR MALI_BASE_ADDR+0x8000 +#define PP1_ADDR MALI_BASE_ADDR+0xA000 +#define PP2_ADDR MALI_BASE_ADDR+0xC000 +#define PP3_ADDR MALI_BASE_ADDR+0xE000 + +/*for mmu and os memory*/ +#define MEM_BASE_ADDR 0x40000000 +#define MEM_TOTAL_SIZE 0x40000000 +#define MEM_MALI_OS_SIZE 0x40000000 + +/*for dedicated memory*/ +//#define MEM_MALI_BASE 0x58000000 +//#define MEM_MALI_SIZE 0x08000000 +#define MEM_MALI_SIZE CONFIG_MALI_MEM_SIZE*1024*1024 +#define MEM_MALI_BASE 0x80000000 - MEM_MALI_SIZE + +static _mali_osk_resource_t arch_configuration [] = +{ + { + .type = MALI400GP, + .description = "Mali-400 GP", + .base = GP_ADDR, + .irq = IRQ_GP_3D, + .mmu_id = 1 + }, + { + .type = MALI400PP, + .base = PP0_ADDR, + .irq = IRQ_PP0_3D, + .description = "Mali-400 PP 0", + .mmu_id = 2 + }, + { + .type = MALI400PP, + .base = PP1_ADDR, + .irq = IRQ_PP1_3D, + .description = "Mali-400 PP 1", + .mmu_id = 3 + }, + { + .type = MALI400PP, + .base = PP2_ADDR, + .irq = IRQ_PP2_3D, + .description = "Mali-400 PP 2", + .mmu_id = 4 + }, + { + .type = MALI400PP, + .base = PP3_ADDR, + .irq = IRQ_PP3_3D, + .description = "Mali-400 PP 3", + .mmu_id = 5 + }, +#if USING_MMU + { + .type = MMU, + .base = GP_MMU_ADDR, + .irq = IRQ_GPMMU_3D, + .description = "Mali-400 MMU for GP", + .mmu_id = 1 + }, + { + .type = MMU, + .base = PP0_MMU_ADDR, + .irq = IRQ_PPMMU0_3D, + .description = "Mali-400 MMU for PP 0", + .mmu_id = 2 + }, + { + .type = MMU, + .base = PP1_MMU_ADDR, + .irq = IRQ_PPMMU1_3D, + .description = "Mali-400 MMU for PP 1", + .mmu_id = 3 + }, + { + .type = MMU, + .base = PP2_MMU_ADDR, + .irq = IRQ_PPMMU2_3D, + .description = "Mali-400 MMU for PP 2", + .mmu_id = 4 + }, + { + .type = MMU, + .base = PP3_MMU_ADDR, + .irq = IRQ_PPMMU3_3D, + .description = "Mali-400 MMU for PP 3", + .mmu_id = 5 + }, +#if USING_OS_MEMORY + { + .type = OS_MEMORY, + .description = "System Memory", + .size = MEM_MALI_OS_SIZE, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE | _MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, +#endif +#if USING_DED /* Dedicated Memory */ + { + .type = MEMORY, + .description = "Dedicated Memory", + .base = MEM_MALI_BASE, + .size = MEM_MALI_SIZE, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE | _MALI_GP_READABLE | _MALI_GP_WRITEABLE | _MALI_MMU_READABLE | _MALI_MMU_WRITEABLE + }, +#endif/* if USING_OS_MEMORY*/ + { + .type = MEM_VALIDATION, + .description = "memory validation", + .base = MEM_BASE_ADDR, + .size = MEM_TOTAL_SIZE, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE | _MALI_GP_READABLE | _MALI_GP_WRITEABLE | _MALI_MMU_READABLE | _MALI_MMU_WRITEABLE + }, +#else /* Not using MMU */ + { + .type = MEMORY, + .description = "Dedicated Memory", + .base = MEM_MALI_BASE, + .size = MEM_MALI_SIZE, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE | _MALI_GP_READABLE | _MALI_GP_WRITEABLE | _MALI_MMU_READABLE | _MALI_MMU_WRITEABLE + }, +#endif + { + .type = MALI400L2, + .base = L2_ADDR, + .description = "Mali-400 L2 cache" + }, +}; + +#endif /* __ARCH_CONFIG_H__ */ diff --git a/drivers/media/video/samsung/mali/arch-ve-virtex6-m450-8/config.h b/drivers/media/video/samsung/mali/arch-ve-virtex6-m450-8/config.h new file mode 100644 index 0000000..9b38f35 --- /dev/null +++ b/drivers/media/video/samsung/mali/arch-ve-virtex6-m450-8/config.h @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2010, 2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __ARCH_CONFIG_H__ +#define __ARCH_CONFIG_H__ + +/* Configuration for the Versatile Express platform */ + +#define MALI_BASE_ADDRESS 0xFC040000 + +static _mali_osk_resource_t arch_configuration [] = +{ + /* GP cluster */ + { + .type = MALI400L2, + .base = MALI_BASE_ADDRESS + 0x10000, + .description = "Mali-450 L2 cache for GP" + }, + { + .type = MALI400GP, + .description = "Mali-450 GP", + .base = MALI_BASE_ADDRESS, + .irq = -1, + }, + { + .type = MMU, + .base = MALI_BASE_ADDRESS + 0x3000, + .irq = 70, + .description = "Mali-450 MMU for GP", + }, + + /* PP0-3 cluster */ + { + .type = MALI400L2, + .base = MALI_BASE_ADDRESS + 0x1000, + .description = "Mali-450 L2 cache for PP0-3" + }, + { + .type = MALI400PP, + .base = MALI_BASE_ADDRESS + 0x8000, + .irq = 70, + .description = "Mali-450 PP0", + }, + { + .type = MMU, + .base = MALI_BASE_ADDRESS + 0x4000, + .irq = 70, + .description = "Mali-450 MMU for PP0", + }, + { + .type = MALI400PP, + .base = MALI_BASE_ADDRESS + 0xA000, + .irq = 70, + .description = "Mali-450 PP1", + }, + { + .type = MMU, + .base = MALI_BASE_ADDRESS + 0x5000, + .irq = 70, + .description = "Mali-450 MMU for PP1", + }, + { + .type = MALI400PP, + .base = MALI_BASE_ADDRESS + 0xC000, + .irq = 70, + .description = "Mali-450 PP2", + }, + { + .type = MMU, + .base = MALI_BASE_ADDRESS + 0x6000, + .irq = 70, + .description = "Mali-450 MMU for PP2", + }, + { + .type = MALI400PP, + .base = MALI_BASE_ADDRESS + 0xE000, + .irq = 70, + .description = "Mali-450 PP3", + }, + { + .type = MMU, + .base = MALI_BASE_ADDRESS + 0x7000, + .irq = 70, + .description = "Mali-450 MMU for PP3", + }, + + /* PP4-7 cluster */ + { + .type = MALI400L2, + .base = MALI_BASE_ADDRESS + 0x11000, + .description = "Mali-450 L2 cache for PP4-7" + }, + { + .type = MALI400PP, + .base = MALI_BASE_ADDRESS + 0x28000, + .irq = 70, + .description = "Mali-450 PP4", + }, + { + .type = MMU, + .base = MALI_BASE_ADDRESS + 0x1C000, + .irq = 70, + .description = "Mali-450 MMU for PP4", + }, + { + .type = MALI400PP, + .base = MALI_BASE_ADDRESS + 0x2A000, + .irq = 70, + .description = "Mali-450 PP5", + }, + { + .type = MMU, + .base = MALI_BASE_ADDRESS + 0x1D000, + .irq = 70, + .description = "Mali-450 MMU for PP5", + }, + { + .type = MALI400PP, + .base = MALI_BASE_ADDRESS + 0x2C000, + .irq = 70, + .description = "Mali-450 PP6", + }, + { + .type = MMU, + .base = MALI_BASE_ADDRESS + 0x1E000, + .irq = 70, + .description = "Mali-450 MMU for PP6", + }, + { + .type = MALI400PP, + .base = MALI_BASE_ADDRESS + 0x2E000, + .irq = 70, + .description = "Mali-450 PP7", + }, + { + .type = MMU, + .base = MALI_BASE_ADDRESS + 0x1F000, + .irq = 70, + .description = "Mali-450 MMU for PP7", + }, + + /* Memory */ + { + .type = OS_MEMORY, + .description = "Mali OS memory", + .cpu_usage_adjust = 0, + .alloc_order = 0, /* Highest preference for this memory */ + .base = 0x0, + .size = 256 * 1024 * 1024, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, + { + .type = MEM_VALIDATION, + .description = "Framebuffer", + .base = 0xe0000000, + .size = 0x01000000, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_WRITEABLE | _MALI_PP_READABLE + }, +}; + +#endif /* __ARCH_CONFIG_H__ */ diff --git a/drivers/media/video/samsung/mali/arch/config.h b/drivers/media/video/samsung/mali/arch/config.h new file mode 100644 index 0000000..d5196c3 --- /dev/null +++ b/drivers/media/video/samsung/mali/arch/config.h @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __ARCH_CONFIG_H__ +#define __ARCH_CONFIG_H__ + +/* Configuration for the EB platform with ZBT memory enabled */ +/*zepplin added 2010.08.17 for orion configuration*/ +#define MALI_BASE_ADDR 0x13000000 +#define GP_ADDR MALI_BASE_ADDR +#define L2_ADDR MALI_BASE_ADDR+0x1000 +#define PMU_ADDR MALI_BASE_ADDR+0x2000 +#define GP_MMU_ADDR MALI_BASE_ADDR+0x3000 +#define PP0_MMU_ADDR MALI_BASE_ADDR+0x4000 +#define PP1_MMU_ADDR MALI_BASE_ADDR+0x5000 +#define PP2_MMU_ADDR MALI_BASE_ADDR+0x6000 +#define PP3_MMU_ADDR MALI_BASE_ADDR+0x7000 +#define PP0_ADDR MALI_BASE_ADDR+0x8000 +#define PP1_ADDR MALI_BASE_ADDR+0xA000 +#define PP2_ADDR MALI_BASE_ADDR+0xC000 +#define PP3_ADDR MALI_BASE_ADDR+0xE000 + +/*for mmu and os memory*/ +#define MEM_BASE_ADDR 0x40000000 +#define MEM_TOTAL_SIZE 0x40000000 +#define MEM_MALI_OS_SIZE 0x40000000 + +/*for dedicated memory*/ +//#define MEM_MALI_BASE 0x58000000 +//#define MEM_MALI_SIZE 0x08000000 +#define MEM_MALI_SIZE CONFIG_MALI_MEM_SIZE*1024*1024 +#define MEM_MALI_BASE 0x80000000 - MEM_MALI_SIZE + +static _mali_osk_resource_t arch_configuration [] = +{ + { + .type = MALI400GP, + .description = "Mali-400 GP", + .base = GP_ADDR, + .irq = IRQ_GP_3D, + .mmu_id = 1 + }, + { + .type = MALI400PP, + .base = PP0_ADDR, + .irq = IRQ_PP0_3D, + .description = "Mali-400 PP 0", + .mmu_id = 2 + }, + { + .type = MALI400PP, + .base = PP1_ADDR, + .irq = IRQ_PP1_3D, + .description = "Mali-400 PP 1", + .mmu_id = 3 + }, + { + .type = MALI400PP, + .base = PP2_ADDR, + .irq = IRQ_PP2_3D, + .description = "Mali-400 PP 2", + .mmu_id = 4 + }, + { + .type = MALI400PP, + .base = PP3_ADDR, + .irq = IRQ_PP3_3D, + .description = "Mali-400 PP 3", + .mmu_id = 5 + }, +#if USING_MMU + { + .type = MMU, + .base = GP_MMU_ADDR, + .irq = IRQ_GPMMU_3D, + .description = "Mali-400 MMU for GP", + .mmu_id = 1 + }, + { + .type = MMU, + .base = PP0_MMU_ADDR, + .irq = IRQ_PPMMU0_3D, + .description = "Mali-400 MMU for PP 0", + .mmu_id = 2 + }, + { + .type = MMU, + .base = PP1_MMU_ADDR, + .irq = IRQ_PPMMU1_3D, + .description = "Mali-400 MMU for PP 1", + .mmu_id = 3 + }, + { + .type = MMU, + .base = PP2_MMU_ADDR, + .irq = IRQ_PPMMU2_3D, + .description = "Mali-400 MMU for PP 2", + .mmu_id = 4 + }, + { + .type = MMU, + .base = PP3_MMU_ADDR, + .irq = IRQ_PPMMU3_3D, + .description = "Mali-400 MMU for PP 3", + .mmu_id = 5 + }, +#if USING_OS_MEMORY + { + .type = OS_MEMORY, + .description = "System Memory", + .size = MEM_MALI_OS_SIZE, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE | _MALI_GP_READABLE | _MALI_GP_WRITEABLE + }, +#endif +#if USING_DED /* Dedicated Memory */ + { + .type = MEMORY, + .description = "Dedicated Memory", + .base = MEM_MALI_BASE, + .size = MEM_MALI_SIZE, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE | _MALI_GP_READABLE | _MALI_GP_WRITEABLE | _MALI_MMU_READABLE | _MALI_MMU_WRITEABLE + }, +#endif/* if USING_OS_MEMORY*/ + { + .type = MEM_VALIDATION, + .description = "memory validation", + .base = MEM_BASE_ADDR, + .size = MEM_TOTAL_SIZE, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE | _MALI_GP_READABLE | _MALI_GP_WRITEABLE | _MALI_MMU_READABLE | _MALI_MMU_WRITEABLE + }, +#else /* Not using MMU */ + { + .type = MEMORY, + .description = "Dedicated Memory", + .base = MEM_MALI_BASE, + .size = MEM_MALI_SIZE, + .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE | _MALI_GP_READABLE | _MALI_GP_WRITEABLE | _MALI_MMU_READABLE | _MALI_MMU_WRITEABLE + }, +#endif + { + .type = MALI400L2, + .base = L2_ADDR, + .description = "Mali-400 L2 cache" + }, +}; + +#endif /* __ARCH_CONFIG_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_block_allocator.c b/drivers/media/video/samsung/mali/common/mali_block_allocator.c index 5f421f0..269e662 100644 --- a/drivers/media/video/samsung/mali/common/mali_block_allocator.c +++ b/drivers/media/video/samsung/mali/common/mali_block_allocator.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -76,7 +76,7 @@ mali_physical_memory_allocator * mali_block_allocator_create(u32 base_address, u info = _mali_osk_malloc(sizeof(block_allocator)); if (NULL != info) { - info->mutex = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED, 0, 105); + info->mutex = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED, 0, _MALI_OSK_LOCK_ORDER_MEM_INFO); if (NULL != info->mutex) { info->all_blocks = _mali_osk_malloc(sizeof(block_info) * num_blocks); @@ -355,7 +355,7 @@ static void block_allocator_release_page_table_block( mali_page_table_block *pag _mali_osk_mem_unmapioregion( page_table_block->phys_base, page_table_block->size, page_table_block->mapping ); /** @note This loop handles the case where more than one block_info was linked. - * Probably unnecssary for page table block releasing. */ + * Probably unnecessary for page table block releasing. */ while (block) { next = block->next; diff --git a/drivers/media/video/samsung/mali/common/mali_cluster.c b/drivers/media/video/samsung/mali/common/mali_cluster.c new file mode 100644 index 0000000..f0fb2b6 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_cluster.c @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mali_kernel_common.h" +#include "mali_cluster.h" +#include "mali_osk.h" +#include "mali_group.h" +#include "mali_l2_cache.h" +#include "mali_scheduler.h" + +static struct mali_cluster *mali_global_clusters[MALI_MAX_NUMBER_OF_CLUSTERS] = { NULL, NULL, NULL }; +static u32 mali_global_num_clusters = 0; + +/** + * The structure represents a render cluster + * A render cluster is defined by all the cores that share the same Mali L2 cache + */ +struct mali_cluster +{ + struct mali_l2_cache_core *l2; + u32 number_of_groups; + struct mali_group* groups[MALI_MAX_NUMBER_OF_GROUPS_PER_CLUSTER]; + u32 last_invalidated_id; + mali_bool power_is_enabled; +}; + +struct mali_cluster *mali_cluster_create(struct mali_l2_cache_core *l2_cache) +{ + struct mali_cluster *cluster = NULL; + + if (mali_global_num_clusters >= MALI_MAX_NUMBER_OF_CLUSTERS) + { + MALI_PRINT_ERROR(("Mali cluster: Too many cluster objects created\n")); + return NULL; + } + + cluster = _mali_osk_malloc(sizeof(struct mali_cluster)); + if (NULL != cluster) + { + _mali_osk_memset(cluster, 0, sizeof(struct mali_cluster)); + cluster->l2 = l2_cache; /* This cluster now owns this L2 cache object */ + cluster->last_invalidated_id = 0; + cluster->power_is_enabled = MALI_TRUE; + + mali_global_clusters[mali_global_num_clusters] = cluster; + mali_global_num_clusters++; + + return cluster; + } + + return NULL; +} + +void mali_cluster_power_is_enabled_set(struct mali_cluster * cluster, mali_bool power_is_enabled) +{ + cluster->power_is_enabled = power_is_enabled; +} + +mali_bool mali_cluster_power_is_enabled_get(struct mali_cluster * cluster) +{ + return cluster->power_is_enabled; +} + + +void mali_cluster_add_group(struct mali_cluster *cluster, struct mali_group *group) +{ + MALI_DEBUG_ASSERT_POINTER(cluster); + + if (cluster->number_of_groups < MALI_MAX_NUMBER_OF_GROUPS_PER_CLUSTER) + { + /* This cluster now owns the group object */ + cluster->groups[cluster->number_of_groups] = group; + cluster->number_of_groups++; + } +} + +void mali_cluster_delete(struct mali_cluster *cluster) +{ + u32 i; + + MALI_DEBUG_ASSERT_POINTER(cluster); + + /* Free all the resources we own */ + for (i = 0; i < cluster->number_of_groups; i++) + { + mali_group_delete(cluster->groups[i]); + } + + if (NULL != cluster->l2) + { + mali_l2_cache_delete(cluster->l2); + } + + for (i = 0; i < mali_global_num_clusters; i++) + { + if (mali_global_clusters[i] == cluster) + { + mali_global_clusters[i] = NULL; + mali_global_num_clusters--; + break; + } + } + + _mali_osk_free(cluster); +} + +void mali_cluster_reset(struct mali_cluster *cluster) +{ + u32 i; + + MALI_DEBUG_ASSERT_POINTER(cluster); + + /* Free all the resources we own */ + for (i = 0; i < cluster->number_of_groups; i++) + { + struct mali_group *group = cluster->groups[i]; + + mali_group_reset(group); + } + + if (NULL != cluster->l2) + { + mali_l2_cache_reset(cluster->l2); + } +} + +struct mali_l2_cache_core* mali_cluster_get_l2_cache_core(struct mali_cluster *cluster) +{ + MALI_DEBUG_ASSERT_POINTER(cluster); + return cluster->l2; +} + +struct mali_group *mali_cluster_get_group(struct mali_cluster *cluster, u32 index) +{ + MALI_DEBUG_ASSERT_POINTER(cluster); + + if (index < cluster->number_of_groups) + { + return cluster->groups[index]; + } + + return NULL; +} + +struct mali_cluster *mali_cluster_get_global_cluster(u32 index) +{ + if (MALI_MAX_NUMBER_OF_CLUSTERS > index) + { + return mali_global_clusters[index]; + } + + return NULL; +} + +u32 mali_cluster_get_glob_num_clusters(void) +{ + return mali_global_num_clusters; +} + +mali_bool mali_cluster_l2_cache_invalidate_all(struct mali_cluster *cluster, u32 id) +{ + MALI_DEBUG_ASSERT_POINTER(cluster); + + if (NULL != cluster->l2) + { + /* If the last cache invalidation was done by a job with a higher id we + * don't have to flush. Since user space will store jobs w/ their + * corresponding memory in sequence (first job #0, then job #1, ...), + * we don't have to flush for job n-1 if job n has already invalidated + * the cache since we know for sure that job n-1's memory was already + * written when job n was started. */ + if (((s32)id) <= ((s32)cluster->last_invalidated_id)) + { + return MALI_FALSE; + } + else + { + cluster->last_invalidated_id = mali_scheduler_get_new_id(); + } + + mali_l2_cache_invalidate_all(cluster->l2); + } + return MALI_TRUE; +} + +void mali_cluster_l2_cache_invalidate_all_force(struct mali_cluster *cluster) +{ + MALI_DEBUG_ASSERT_POINTER(cluster); + + if (NULL != cluster->l2) + { + cluster->last_invalidated_id = mali_scheduler_get_new_id(); + mali_l2_cache_invalidate_all(cluster->l2); + } +} + +void mali_cluster_invalidate_pages(u32 *pages, u32 num_pages) +{ + u32 i; + + for (i = 0; i < mali_global_num_clusters; i++) + { + /*additional check for cluster*/ + if (MALI_TRUE == mali_l2_cache_lock_power_state(mali_global_clusters[i]->l2)) + { + mali_l2_cache_invalidate_pages(mali_global_clusters[i]->l2, pages, num_pages); + } + mali_l2_cache_unlock_power_state(mali_global_clusters[i]->l2); + /*check for failed power locking???*/ + } +} diff --git a/drivers/media/video/samsung/mali/common/mali_cluster.h b/drivers/media/video/samsung/mali/common/mali_cluster.h new file mode 100644 index 0000000..33debdb --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_cluster.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MALI_CLUSTER_H__ +#define __MALI_CLUSTER_H__ + +#include "mali_osk.h" +#include "mali_l2_cache.h" + +/* Maximum 1 GP and 4 PP for a cluster (Mali-400 Quad-core) */ +#define MALI_MAX_NUMBER_OF_GROUPS_PER_CLUSTER 5 +#define MALI_MAX_NUMBER_OF_CLUSTERS 3 + +struct mali_cluster; +struct mali_group; + +struct mali_cluster *mali_cluster_create(struct mali_l2_cache_core *l2_cache); +void mali_cluster_add_group(struct mali_cluster *cluster, struct mali_group *group); +void mali_cluster_delete(struct mali_cluster *cluster); + +void mali_cluster_power_is_enabled_set(struct mali_cluster * cluster, mali_bool power_is_enabled); +mali_bool mali_cluster_power_is_enabled_get(struct mali_cluster * cluster); + +void mali_cluster_reset(struct mali_cluster *cluster); + +struct mali_l2_cache_core* mali_cluster_get_l2_cache_core(struct mali_cluster *cluster); +struct mali_group *mali_cluster_get_group(struct mali_cluster *cluster, u32 index); + +struct mali_cluster *mali_cluster_get_global_cluster(u32 index); +u32 mali_cluster_get_glob_num_clusters(void); + +/* Returns MALI_TRUE if it did the flush */ +mali_bool mali_cluster_l2_cache_invalidate_all(struct mali_cluster *cluster, u32 id); +void mali_cluster_l2_cache_invalidate_all_force(struct mali_cluster *cluster); +void mali_cluster_invalidate_pages(u32 *pages, u32 num_pages); + +#endif /* __MALI_CLUSTER_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_device_pause_resume.c b/drivers/media/video/samsung/mali/common/mali_device_pause_resume.c new file mode 100644 index 0000000..6af1279 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_device_pause_resume.c @@ -0,0 +1,46 @@ +/** + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** + * @file mali_device_pause_resume.c + * Implementation of the Mali pause/resume functionality + */ + +#include "mali_gp_scheduler.h" +#include "mali_pp_scheduler.h" +#include "mali_pm.h" + +void mali_dev_pause(mali_bool *power_is_on) +{ + mali_gp_scheduler_suspend(); + mali_pp_scheduler_suspend(); + + /* + * Take and hold the PM lock to be sure we don't change power state as well. + * (it might be unsafe to for instance change frequency if Mali GPU is powered off) + */ + mali_pm_execute_state_change_lock(); + if (NULL != power_is_on) + { + *power_is_on = mali_pm_is_powered_on(); + } +} + +void mali_dev_resume(void) +{ + mali_pm_execute_state_change_unlock(); + mali_gp_scheduler_resume(); + mali_pp_scheduler_resume(); +} + +/* +EXPORT_SYMBOL(mali_dev_pause); +EXPORT_SYMBOL(mali_dev_resume); +*/ diff --git a/drivers/media/video/samsung/mali/common/mali_device_pause_resume.h b/drivers/media/video/samsung/mali/common/mali_device_pause_resume.h new file mode 100644 index 0000000..6be75b0 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_device_pause_resume.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MALI_DEVICE_PAUSE_RESUME_H__ +#define __MALI_DEVICE_PAUSE_RESUME_H__ + +#include "mali_osk.h" + +/** + * Pause the scheduling and power state changes of Mali device driver. + * mali_dev_resume() must always be called as soon as possible after this function + * in order to resume normal operation of the Mali driver. + * + * @param power_is_on Receives the power current status of Mali GPU. MALI_TRUE if GPU is powered on + */ +void mali_dev_pause(mali_bool *power_is_on); + +/** + * Resume scheduling and allow power changes in Mali device driver. + * This must always be called after mali_dev_pause(). + */ +void mali_dev_resume(void); + +#endif /* __MALI_DEVICE_PAUSE_RESUME_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_dlbu.c b/drivers/media/video/samsung/mali/common/mali_dlbu.c new file mode 100644 index 0000000..fcc51fa --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_dlbu.c @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mali_dlbu.h" +#include "mali_memory.h" +#include "mali_pp.h" +#include "mali_group.h" +#include "mali_osk.h" +#include "mali_hw_core.h" + +/** + * Size of DLBU registers in bytes + */ +#define MALI_DLBU_SIZE 0x400 + +u32 mali_dlbu_phys_addr = 0; +static mali_io_address mali_dlbu_cpu_addr = 0; + +static u32 mali_dlbu_tile_position; + +/** + * DLBU register numbers + * Used in the register read/write routines. + * See the hardware documentation for more information about each register + */ +typedef enum mali_dlbu_register { + MALI_DLBU_REGISTER_MASTER_TLLIST_PHYS_ADDR = 0x0000, /**< Master tile list physical base address; + 31:12 Physical address to the page used for the DLBU + 0 DLBU enable - set this bit to 1 enables the AXI bus + between PPs and L2s, setting to 0 disables the router and + no further transactions are sent to DLBU */ + MALI_DLBU_REGISTER_MASTER_TLLIST_VADDR = 0x0004, /**< Master tile list virtual base address; + 31:12 Virtual address to the page used for the DLBU */ + MALI_DLBU_REGISTER_TLLIST_VBASEADDR = 0x0008, /**< Tile list virtual base address; + 31:12 Virtual address to the tile list. This address is used when + calculating the call address sent to PP.*/ + MALI_DLBU_REGISTER_FB_DIM = 0x000C, /**< Framebuffer dimension; + 23:16 Number of tiles in Y direction-1 + 7:0 Number of tiles in X direction-1 */ + MALI_DLBU_REGISTER_TLLIST_CONF = 0x0010, /**< Tile list configuration; + 29:28 select the size of each allocated block: 0=128 bytes, 1=256, 2=512, 3=1024 + 21:16 2^n number of tiles to be binned to one tile list in Y direction + 5:0 2^n number of tiles to be binned to one tile list in X direction */ + MALI_DLBU_REGISTER_START_TILE_POS = 0x0014, /**< Start tile positions; + 31:24 start position in Y direction for group 1 + 23:16 start position in X direction for group 1 + 15:8 start position in Y direction for group 0 + 7:0 start position in X direction for group 0 */ + MALI_DLBU_REGISTER_PP_ENABLE_MASK = 0x0018, /**< PP enable mask; + 7 enable PP7 for load balancing + 6 enable PP6 for load balancing + 5 enable PP5 for load balancing + 4 enable PP4 for load balancing + 3 enable PP3 for load balancing + 2 enable PP2 for load balancing + 1 enable PP1 for load balancing + 0 enable PP0 for load balancing */ +} mali_dlbu_register; + +typedef enum +{ + PP0ENABLE = 0, + PP1ENABLE, + PP2ENABLE, + PP3ENABLE, + PP4ENABLE, + PP5ENABLE, + PP6ENABLE, + PP7ENABLE +} mali_dlbu_pp_enable; + +struct mali_dlbu_core +{ + struct mali_hw_core hw_core; /**< Common for all HW cores */ + u32 pp_cores_mask; /**< This is a mask for the PP cores whose operation will be controlled by LBU + see MALI_DLBU_REGISTER_PP_ENABLE_MASK register */ +}; + +_mali_osk_errcode_t mali_dlbu_initialize(void) +{ + + MALI_DEBUG_PRINT(2, ("Dynamic Load Balancing Unit initializing\n")); + + if (_MALI_OSK_ERR_OK == mali_mmu_get_table_page(&mali_dlbu_phys_addr, &mali_dlbu_cpu_addr)) + { + MALI_SUCCESS; + } + + return _MALI_OSK_ERR_FAULT; +} + +void mali_dlbu_terminate(void) +{ + MALI_DEBUG_PRINT(3, ("Mali DLBU: terminating\n")); + + mali_mmu_release_table_page(mali_dlbu_phys_addr); +} + +struct mali_dlbu_core *mali_dlbu_create(const _mali_osk_resource_t * resource) +{ + struct mali_dlbu_core *core = NULL; + + MALI_DEBUG_PRINT(2, ("Mali DLBU: Creating Mali dynamic load balancing unit: %s\n", resource->description)); + + core = _mali_osk_malloc(sizeof(struct mali_dlbu_core)); + if (NULL != core) + { + if (_MALI_OSK_ERR_OK == mali_hw_core_create(&core->hw_core, resource, MALI_DLBU_SIZE)) + { + if (_MALI_OSK_ERR_OK == mali_dlbu_reset(core)) + { + mali_hw_core_register_write(&core->hw_core, MALI_DLBU_REGISTER_MASTER_TLLIST_VADDR, MALI_DLB_VIRT_ADDR); + + return core; + } + MALI_PRINT_ERROR(("Failed to reset DLBU %s\n", core->hw_core.description)); + mali_hw_core_delete(&core->hw_core); + } + + _mali_osk_free(core); + } + else + { + MALI_PRINT_ERROR(("Mali DLBU: Failed to allocate memory for DLBU core\n")); + } + + return NULL; +} + +void mali_dlbu_delete(struct mali_dlbu_core *dlbu) +{ + mali_dlbu_reset(dlbu); + mali_hw_core_delete(&dlbu->hw_core); + _mali_osk_free(dlbu); +} + +void mali_dlbu_enable(struct mali_dlbu_core *dlbu) +{ + u32 wval = mali_hw_core_register_read(&dlbu->hw_core, MALI_DLBU_REGISTER_MASTER_TLLIST_PHYS_ADDR); + + wval |= 0x1; + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_MASTER_TLLIST_PHYS_ADDR, wval); +} + +void mali_dlbu_disable(struct mali_dlbu_core *dlbu) +{ + u32 wval = mali_hw_core_register_read(&dlbu->hw_core, MALI_DLBU_REGISTER_MASTER_TLLIST_PHYS_ADDR); + + wval |= (wval & 0xFFFFFFFE); + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_MASTER_TLLIST_PHYS_ADDR, wval); +} + +_mali_osk_errcode_t mali_dlbu_enable_pp_core(struct mali_dlbu_core *dlbu, u32 pp_core_enable, u32 val) +{ + u32 wval = mali_hw_core_register_read(&dlbu->hw_core, MALI_DLBU_REGISTER_PP_ENABLE_MASK); + + if((pp_core_enable < mali_pp_get_glob_num_pp_cores()) && ((0 == val) || (1 == val))) /* check for valid input parameters */ + { + if (val == 1) + { + val = (wval | (pp_core_enable <<= 0x1)); + } + if (val == 0) + { + val = (wval & ~(pp_core_enable << 0x1)); + } + wval |= val; + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_PP_ENABLE_MASK, wval); + dlbu->pp_cores_mask = wval; + + return _MALI_OSK_ERR_OK; + } + + return _MALI_OSK_ERR_FAULT; +} + +void mali_dlbu_enable_all_pp_cores(struct mali_dlbu_core *dlbu) +{ + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_PP_ENABLE_MASK, dlbu->pp_cores_mask); +} + +void mali_dlbu_disable_all_pp_cores(struct mali_dlbu_core *dlbu) +{ + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_PP_ENABLE_MASK, 0x0); +} + +void mali_dlbu_setup(struct mali_dlbu_core *dlbu, u8 fb_xdim, u8 fb_ydim, u8 xtilesize, u8 ytilesize, u8 blocksize, u8 xgr0, u8 ygr0, u8 xgr1, u8 ygr1) +{ + u32 wval = 0x0; + + /* write the framebuffer dimensions */ + wval = (16 << (u32)fb_ydim) | (u32)fb_xdim; + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_FB_DIM, wval); + + /* write the tile list configuration */ + wval = 0x0; + wval = (28 << (u32)blocksize) | (16 << (u32)ytilesize) | ((u32)xtilesize); + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_TLLIST_CONF, wval); + + /* write the start tile position */ + wval = 0x0; + wval = (24 << (u32)ygr1 | (16 << (u32)xgr1) | 8 << (u32)ygr0) | (u32)xgr0; + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_START_TILE_POS, wval); +} + +_mali_osk_errcode_t mali_dlbu_reset(struct mali_dlbu_core *dlbu) +{ + _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; + MALI_DEBUG_ASSERT_POINTER(dlbu); + + MALI_DEBUG_PRINT(4, ("Mali DLBU: mali_dlbu_reset: %s\n", dlbu->hw_core.description)); + + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_MASTER_TLLIST_PHYS_ADDR, mali_dlbu_phys_addr); + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_TLLIST_VBASEADDR, 0x00); + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_FB_DIM, 0x00); + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_TLLIST_CONF, 0x00); + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_START_TILE_POS, 0x00); + + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_PP_ENABLE_MASK, dlbu->pp_cores_mask); + + err = _MALI_OSK_ERR_OK; + + return err; +} + +_mali_osk_errcode_t mali_dlbu_add_group(struct mali_dlbu_core *dlbu, struct mali_group *group) +{ + _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; + u32 wval, rval; + struct mali_pp_core *pp_core = mali_group_get_pp_core(group); + + /* find the core id and set the mask */ + + if (NULL != pp_core) + { + wval = mali_pp_core_get_id(pp_core); + rval = mali_hw_core_register_read(&dlbu->hw_core, MALI_DLBU_REGISTER_PP_ENABLE_MASK); + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_PP_ENABLE_MASK, (wval << 0x1) | rval); + err = _MALI_OSK_ERR_OK; + } + + return err; +} + +void mali_dlbu_set_tllist_base_address(struct mali_dlbu_core *dlbu, u32 val) +{ + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_TLLIST_VBASEADDR, val); +} + +void mali_dlbu_pp_jobs_stop(struct mali_dlbu_core *dlbu) +{ + /* this function to implement (see documentation): + * 1) clear all bits in the enable register + * 2) wait until all PPs have finished - mali_pp_scheduler.c code - this done in interrupts call? + * 3) read the current tile position registers to get current tile positions - + * note that current tile position register is the same as start tile position - perhaps the name should be changed!!! */ + + /* 1) */ + mali_dlbu_disable_all_pp_cores(dlbu); + + /* 3) */ + mali_dlbu_tile_position = mali_hw_core_register_read(&dlbu->hw_core, MALI_DLBU_REGISTER_START_TILE_POS); +} + +void mali_dlbu_pp_jobs_restart(struct mali_dlbu_core *dlbu) +{ + /* this function to implement (see the document): + * 1) configure the dynamic load balancing unit as normal + * 2) set the current tile position registers as read when stopping the job + * 3) configure the PPs to start the job as normal - done by another part of the system - scheduler */ + + /* 1) */ + mali_dlbu_reset(dlbu); + /* ++ setup the needed values - see this */ + + /* 2) */ + mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_START_TILE_POS, mali_dlbu_tile_position); +} diff --git a/drivers/media/video/samsung/mali/common/mali_dlbu.h b/drivers/media/video/samsung/mali/common/mali_dlbu.h new file mode 100644 index 0000000..e3c3b9d --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_dlbu.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MALI_DLBU_H__ +#define __MALI_DLBU_H__ + +#include "mali_osk.h" +#include "mali_group.h" + +#define MALI_DLB_VIRT_ADDR 0xFFF00000 /* master tile virtual address fixed at this value and mapped into every session */ + +extern u32 mali_dlbu_phys_addr; + +struct mali_dlbu_core; + +_mali_osk_errcode_t mali_dlbu_initialize(void); +void mali_dlbu_terminate(void); + +struct mali_dlbu_core *mali_dlbu_create(const _mali_osk_resource_t * resource); +void mali_dlbu_delete(struct mali_dlbu_core *dlbu); + +void mali_dlbu_enable(struct mali_dlbu_core *dlbu); +void mali_dlbu_disable(struct mali_dlbu_core *dlbu); + +_mali_osk_errcode_t mali_dlbu_enable_pp_core(struct mali_dlbu_core *dlbu, u32 pp_core_enable, u32 val); +void mali_dlbu_enable_all_pp_cores(struct mali_dlbu_core *dlbu); +void mali_dlbu_disable_all_pp_cores(struct mali_dlbu_core *dlbu); + +_mali_osk_errcode_t mali_dlbu_reset(struct mali_dlbu_core *dlbu); +void mali_dlbu_setup(struct mali_dlbu_core *dlbu, u8 fb_xdim, u8 fb_ydim, u8 xtilesize, u8 ytilesize, u8 blocksize, u8 xgr0, u8 ygr0, u8 xgr1, u8 ygr1); + +_mali_osk_errcode_t mali_dlbu_add_group(struct mali_dlbu_core *dlbu, struct mali_group *group); +void mali_dlbu_set_tllist_base_address(struct mali_dlbu_core *dlbu, u32 val); + +void mali_dlbu_pp_jobs_stop(struct mali_dlbu_core *dlbu); +void mali_dlbu_pp_jobs_restart(struct mali_dlbu_core *dlbu); + +#endif /* __MALI_DLBU_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_gp.c b/drivers/media/video/samsung/mali/common/mali_gp.c new file mode 100644 index 0000000..d03721c --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_gp.c @@ -0,0 +1,693 @@ +/* + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mali_gp.h" +#include "mali_hw_core.h" +#include "mali_group.h" +#include "mali_osk.h" +#include "regs/mali_gp_regs.h" +#include "mali_kernel_common.h" +#include "mali_kernel_core.h" +#if MALI_TIMELINE_PROFILING_ENABLED +#include "mali_osk_profiling.h" +#endif + +/** + * Definition of the GP core struct + * Used to track a GP core in the system. + */ +struct mali_gp_core +{ + struct mali_hw_core hw_core; /**< Common for all HW cores */ + struct mali_group *group; /**< Parent group for this core */ + _mali_osk_irq_t *irq; /**< IRQ handler */ + struct mali_gp_job *running_job; /**< Current running job */ + _mali_osk_timer_t *timeout_timer; /**< timeout timer for this core */ + u32 timeout_job_id; /**< job id for the timed out job - relevant only if gp_core_timed_out == MALI_TRUE */ + mali_bool core_timed_out; /**< if MALI_TRUE, this gp core has timed out; if MALI_FALSE, no timeout on this gp core */ + u32 counter_src0; /**< Performance counter 0, MALI_HW_CORE_NO_COUNTER for disabled */ + u32 counter_src1; /**< Performance counter 1, MALI_HW_CORE_NO_COUNTER for disabled */ + u32 counter_src0_used; /**< The selected performance counter 0 when a job is running */ + u32 counter_src1_used; /**< The selected performance counter 1 when a job is running */ +}; + +static struct mali_gp_core *mali_global_gp_core = NULL; + +/* Interrupt handlers */ +static _mali_osk_errcode_t mali_gp_upper_half(void *data); +static void mali_gp_bottom_half(void *data); +static void mali_gp_irq_probe_trigger(void *data); +static _mali_osk_errcode_t mali_gp_irq_probe_ack(void *data); +static void mali_gp_post_process_job(struct mali_gp_core *core, mali_bool suspend); +static void mali_gp_timeout(void *data); + +struct mali_gp_core *mali_gp_create(const _mali_osk_resource_t * resource, struct mali_group *group) +{ + struct mali_gp_core* core = NULL; + + MALI_DEBUG_ASSERT(NULL == mali_global_gp_core); + MALI_DEBUG_PRINT(2, ("Mali GP: Creating Mali GP core: %s\n", resource->description)); + + core = _mali_osk_malloc(sizeof(struct mali_gp_core)); + if (NULL != core) + { + core->group = group; + core->running_job = NULL; + core->counter_src0 = MALI_HW_CORE_NO_COUNTER; + core->counter_src1 = MALI_HW_CORE_NO_COUNTER; + core->counter_src0_used = MALI_HW_CORE_NO_COUNTER; + core->counter_src1_used = MALI_HW_CORE_NO_COUNTER; + if (_MALI_OSK_ERR_OK == mali_hw_core_create(&core->hw_core, resource, MALIGP2_REGISTER_ADDRESS_SPACE_SIZE)) + { + _mali_osk_errcode_t ret; + + mali_group_lock(group); + ret = mali_gp_reset(core); + mali_group_unlock(group); + + if (_MALI_OSK_ERR_OK == ret) + { + /* Setup IRQ handlers (which will do IRQ probing if needed) */ + core->irq = _mali_osk_irq_init(resource->irq, + mali_gp_upper_half, + mali_gp_bottom_half, + mali_gp_irq_probe_trigger, + mali_gp_irq_probe_ack, + core, + "mali_gp_irq_handlers"); + if (NULL != core->irq) + { + /* Initialise the timeout timer */ + core->timeout_timer = _mali_osk_timer_init(); + if(NULL != core->timeout_timer) + { + _mali_osk_timer_setcallback(core->timeout_timer, mali_gp_timeout, (void *)core); + MALI_DEBUG_PRINT(4, ("Mali GP: set global gp core from 0x%08X to 0x%08X\n", mali_global_gp_core, core)); + mali_global_gp_core = core; + + return core; + } + else + { + MALI_PRINT_ERROR(("Failed to setup timeout timer for GP core %s\n", core->hw_core.description)); + /* Release IRQ handlers */ + _mali_osk_irq_term(core->irq); + } + } + else + { + MALI_PRINT_ERROR(("Failed to setup interrupt handlers for GP core %s\n", core->hw_core.description)); + } + } + mali_hw_core_delete(&core->hw_core); + } + + _mali_osk_free(core); + } + else + { + MALI_PRINT_ERROR(("Failed to allocate memory for GP core\n")); + } + + return NULL; +} + +void mali_gp_delete(struct mali_gp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + + _mali_osk_timer_term(core->timeout_timer); + _mali_osk_irq_term(core->irq); + mali_hw_core_delete(&core->hw_core); + mali_global_gp_core = NULL; + _mali_osk_free(core); +} + +void mali_gp_stop_bus(struct mali_gp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_STOP_BUS); +} + +_mali_osk_errcode_t mali_gp_stop_bus_wait(struct mali_gp_core *core) +{ + int i; + const int request_loop_count = 20; + + MALI_DEBUG_ASSERT_POINTER(core); + + /* Send the stop bus command. */ + mali_gp_stop_bus(core); + + /* Wait for bus to be stopped */ + for (i = 0; i < request_loop_count; i++) + { + if (mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_STATUS) & MALIGP2_REG_VAL_STATUS_BUS_STOPPED) + { + break; + } + _mali_osk_time_ubusydelay(10); + } + + if (request_loop_count == i) + { + MALI_PRINT_ERROR(("Mali GP: Failed to stop bus on %s\n", core->hw_core.description)); + return _MALI_OSK_ERR_FAULT; + } + return _MALI_OSK_ERR_OK; +} + +void mali_gp_hard_reset(struct mali_gp_core *core) +{ + const int reset_finished_loop_count = 15; + const u32 reset_wait_target_register = MALIGP2_REG_ADDR_MGMT_WRITE_BOUND_LOW; + const u32 reset_invalid_value = 0xC0FFE000; + const u32 reset_check_value = 0xC01A0000; + const u32 reset_default_value = 0; + int i; + + MALI_DEBUG_ASSERT_POINTER(core); + MALI_DEBUG_PRINT(4, ("Mali GP: Hard reset of core %s\n", core->hw_core.description)); + MALI_ASSERT_GROUP_LOCKED(core->group); + + mali_gp_post_process_job(core, MALI_FALSE); + + mali_hw_core_register_write(&core->hw_core, reset_wait_target_register, reset_invalid_value); + + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_RESET); + + for (i = 0; i < reset_finished_loop_count; i++) + { + mali_hw_core_register_write(&core->hw_core, reset_wait_target_register, reset_check_value); + if (reset_check_value == mali_hw_core_register_read(&core->hw_core, reset_wait_target_register)) + { + break; + } + } + + if (i == reset_finished_loop_count) + { + MALI_PRINT_ERROR(("Mali GP: The hard reset loop didn't work, unable to recover\n")); + } + + mali_hw_core_register_write(&core->hw_core, reset_wait_target_register, reset_default_value); /* set it back to the default */ + /* Re-enable interrupts */ + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_MASK_ALL); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED); + +} + +_mali_osk_errcode_t mali_gp_reset(struct mali_gp_core *core) +{ + int i; + const int request_loop_count = 20; + + MALI_DEBUG_ASSERT_POINTER(core); + MALI_DEBUG_PRINT(4, ("Mali GP: Reset of core %s\n", core->hw_core.description)); + MALI_ASSERT_GROUP_LOCKED(core->group); + + mali_gp_post_process_job(core, MALI_FALSE); + + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, 0); /* disable the IRQs */ + +#if defined(USING_MALI200) + + /* On Mali-200, stop the bus, then do a hard reset of the core */ + + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_STOP_BUS); + + for (i = 0; i < request_loop_count; i++) + { + if (mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_STATUS) & MALIGP2_REG_VAL_STATUS_BUS_STOPPED) + { + break; + } + _mali_osk_time_ubusydelay(10); + } + + if (request_loop_count == i) + { + MALI_PRINT_ERROR(("Mali GP: Failed to stop bus for core %s, unable to recover\n", core->hw_core.description)); + return _MALI_OSK_ERR_FAULT; + } + + /* the bus was stopped OK, do the hard reset */ + mali_gp_hard_reset(core); + +#elif defined(USING_MALI400) + + /* Mali-300 and Mali-400 have a safe reset command which we use */ + + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALI400GP_REG_VAL_IRQ_RESET_COMPLETED); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALI400GP_REG_VAL_CMD_SOFT_RESET); + + for (i = 0; i < request_loop_count; i++) + { + if (mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT) & MALI400GP_REG_VAL_IRQ_RESET_COMPLETED) + { + break; + } + _mali_osk_time_ubusydelay(10); + } + + if (request_loop_count == i) + { + MALI_PRINT_ERROR(("Mali GP: Failed to reset core %s, unable to recover\n", core->hw_core.description)); + return _MALI_OSK_ERR_FAULT; + } +#else +#error "no supported mali core defined" +#endif + + /* Re-enable interrupts */ + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_MASK_ALL); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED); + + return _MALI_OSK_ERR_OK; +} + +void mali_gp_job_start(struct mali_gp_core *core, struct mali_gp_job *job) +{ + u32 startcmd = 0; + u32 *frame_registers = mali_gp_job_get_frame_registers(job); + core->counter_src0_used = core->counter_src0; + core->counter_src1_used = core->counter_src1; + + MALI_DEBUG_ASSERT_POINTER(core); + MALI_ASSERT_GROUP_LOCKED(core->group); + + if (mali_gp_job_has_vs_job(job)) + { + startcmd |= (u32) MALIGP2_REG_VAL_CMD_START_VS; + } + + if (mali_gp_job_has_plbu_job(job)) + { + startcmd |= (u32) MALIGP2_REG_VAL_CMD_START_PLBU; + } + + MALI_DEBUG_ASSERT(0 != startcmd); + + mali_hw_core_register_write_array_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_VSCL_START_ADDR, frame_registers, MALIGP2_NUM_REGS_FRAME); + + /* This selects which performance counters we are reading */ + if (MALI_HW_CORE_NO_COUNTER != core->counter_src0_used || MALI_HW_CORE_NO_COUNTER != core->counter_src0_used) + { + /* global_config has enabled HW counters, this will override anything specified by user space */ + if (MALI_HW_CORE_NO_COUNTER != core->counter_src0_used) + { + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_SRC, core->counter_src0_used); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_ENABLE, MALIGP2_REG_VAL_PERF_CNT_ENABLE); + } + if (MALI_HW_CORE_NO_COUNTER != core->counter_src1_used) + { + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_SRC, core->counter_src1_used); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_ENABLE, MALIGP2_REG_VAL_PERF_CNT_ENABLE); + } + } + else + { + /* Use HW counters from job object, if any */ + u32 perf_counter_flag = mali_gp_job_get_perf_counter_flag(job); + if (0 != perf_counter_flag) + { + if (perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE) + { + core->counter_src0_used = mali_gp_job_get_perf_counter_src0(job); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_SRC, core->counter_src0_used); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_ENABLE, MALIGP2_REG_VAL_PERF_CNT_ENABLE); + } + + if (perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE) + { + core->counter_src1_used = mali_gp_job_get_perf_counter_src1(job); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_SRC, core->counter_src1_used); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_ENABLE, MALIGP2_REG_VAL_PERF_CNT_ENABLE); + } + } + } + + MALI_DEBUG_PRINT(3, ("Mali GP: Starting job (0x%08x) on core %s with command 0x%08X\n", job, core->hw_core.description, startcmd)); + + /* Barrier to make sure the previous register write is finished */ + _mali_osk_write_mem_barrier(); + + /* This is the command that starts the core. */ + mali_hw_core_register_write_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, startcmd); + + /* Barrier to make sure the previous register write is finished */ + _mali_osk_write_mem_barrier(); + + /* Setup the timeout timer value and save the job id for the job running on the gp core */ + + _mali_osk_timer_add(core->timeout_timer, _mali_osk_time_mstoticks(mali_max_job_runtime)); + core->timeout_job_id = mali_gp_job_get_id(job); + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE | MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(0) | MALI_PROFILING_EVENT_REASON_SINGLE_HW_FLUSH, + job->frame_builder_id, job->flush_id, 0, 0, 0); + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_START|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(0), job->pid, job->tid, 0, 0, 0); +#endif + + core->running_job = job; +} + +void mali_gp_resume_with_new_heap(struct mali_gp_core *core, u32 start_addr, u32 end_addr) +{ + u32 irq_readout; + + MALI_DEBUG_ASSERT_POINTER(core); + MALI_ASSERT_GROUP_LOCKED(core->group); + + irq_readout = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT); + + if (irq_readout & MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM) + { + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, (MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM | MALIGP2_REG_VAL_IRQ_HANG)); + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED); /* re-enable interrupts */ + mali_hw_core_register_write_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR, start_addr); + mali_hw_core_register_write_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_END_ADDR, end_addr); + + MALI_DEBUG_PRINT(3, ("Mali GP: Resuming job\n")); + + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_UPDATE_PLBU_ALLOC); + _mali_osk_write_mem_barrier(); + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_RESUME|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(0), 0, 0, 0, 0, 0); +#endif + } + /* + * else: core has been reset between PLBU_OUT_OF_MEM interrupt and this new heap response. + * A timeout or a page fault on Mali-200 PP core can cause this behaviour. + */ +} + +void mali_gp_abort_job(struct mali_gp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + MALI_ASSERT_GROUP_LOCKED(core->group); + + if (_MALI_OSK_ERR_FAULT != mali_gp_reset(core)) + { + _mali_osk_timer_del(core->timeout_timer); + } +} + +u32 mali_gp_core_get_version(struct mali_gp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + return mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_VERSION); +} + +mali_bool mali_gp_core_set_counter_src0(struct mali_gp_core *core, u32 counter) +{ + MALI_DEBUG_ASSERT_POINTER(core); + + core->counter_src0 = counter; + return MALI_TRUE; +} + +mali_bool mali_gp_core_set_counter_src1(struct mali_gp_core *core, u32 counter) +{ + MALI_DEBUG_ASSERT_POINTER(core); + + core->counter_src1 = counter; + return MALI_TRUE; +} + +u32 mali_gp_core_get_counter_src0(struct mali_gp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + return core->counter_src0; +} + +u32 mali_gp_core_get_counter_src1(struct mali_gp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + return core->counter_src1; +} + +struct mali_gp_core *mali_gp_get_global_gp_core(void) +{ + return mali_global_gp_core; +} + +/* ------------- interrupt handling below ------------------ */ +static _mali_osk_errcode_t mali_gp_upper_half(void *data) +{ + struct mali_gp_core *core = (struct mali_gp_core *)data; + u32 irq_readout; + + irq_readout = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_STAT); + if (MALIGP2_REG_VAL_IRQ_MASK_NONE != irq_readout) + { + /* Mask out all IRQs from this core until IRQ is handled */ + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_NONE); + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(0)|MALI_PROFILING_EVENT_REASON_SINGLE_HW_INTERRUPT, irq_readout, 0, 0, 0, 0); +#endif + + /* We do need to handle this in a bottom half */ + _mali_osk_irq_schedulework(core->irq); + return _MALI_OSK_ERR_OK; + } + + return _MALI_OSK_ERR_FAULT; +} + +static void mali_gp_bottom_half(void *data) +{ + struct mali_gp_core *core = (struct mali_gp_core *)data; + u32 irq_readout; + u32 irq_errors; + +#if MALI_TIMELINE_PROFILING_ENABLED +#if 0 /* Bottom half TLP logging is currently not supported */ + _mali_osk_profiling_add_event( MALI_PROFILING_EVENT_TYPE_START| MALI_PROFILING_EVENT_CHANNEL_SOFTWARE , _mali_osk_get_pid(), _mali_osk_get_tid()+11000, 0, 0, 0); +#endif +#endif + + mali_group_lock(core->group); /* Group lock grabbed in core handlers, but released in common group handler */ + + if ( MALI_FALSE == mali_group_power_is_on(core->group) ) + { + MALI_PRINT_ERROR(("Interrupt bottom half of %s when core is OFF.", core->hw_core.description)); + mali_group_unlock(core->group); + return; + } + + irq_readout = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT) & MALIGP2_REG_VAL_IRQ_MASK_USED; + MALI_DEBUG_PRINT(4, ("Mali GP: Bottom half IRQ 0x%08X from core %s\n", irq_readout, core->hw_core.description)); + + if (irq_readout & (MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST|MALIGP2_REG_VAL_IRQ_PLBU_END_CMD_LST)) + { + u32 core_status = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_STATUS); + if (0 == (core_status & MALIGP2_REG_VAL_STATUS_MASK_ACTIVE)) + { + mali_gp_post_process_job(core, MALI_FALSE); + MALI_DEBUG_PRINT(4, ("Mali GP: Job completed, calling group handler\n")); + mali_group_bottom_half(core->group, GROUP_EVENT_GP_JOB_COMPLETED); /* Will release group lock */ + return; + } + } + + /* + * Now lets look at the possible error cases (IRQ indicating error or timeout) + * END_CMD_LST, HANG and PLBU_OOM interrupts are not considered error. + */ + irq_errors = irq_readout & ~(MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST|MALIGP2_REG_VAL_IRQ_PLBU_END_CMD_LST|MALIGP2_REG_VAL_IRQ_HANG|MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM); + if (0 != irq_errors) + { + mali_gp_post_process_job(core, MALI_FALSE); + MALI_PRINT_ERROR(("Mali GP: Unknown interrupt 0x%08X from core %s, aborting job\n", irq_readout, core->hw_core.description)); + mali_group_bottom_half(core->group, GROUP_EVENT_GP_JOB_FAILED); /* Will release group lock */ + return; + } + else if (MALI_TRUE == core->core_timed_out) /* SW timeout */ + { + if (core->timeout_job_id == mali_gp_job_get_id(core->running_job)) + { + mali_gp_post_process_job(core, MALI_FALSE); + MALI_DEBUG_PRINT(2, ("Mali GP: Job %d timed out\n", mali_gp_job_get_id(core->running_job))); + mali_group_bottom_half(core->group, GROUP_EVENT_GP_JOB_TIMED_OUT); + } + core->core_timed_out = MALI_FALSE; + return; + } + else if (irq_readout & MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM) + { + /* GP wants more memory in order to continue. + * + * This must be handled prior to HANG because this actually can + * generate a HANG while waiting for more memory. + * And it must be handled before the completion interrupts, + * since the PLBU can run out of memory after VS is complete; + * in which case the OOM must be handled before to complete the + * PLBU work. + */ + mali_gp_post_process_job(core, MALI_TRUE); + MALI_DEBUG_PRINT(3, ("Mali GP: PLBU needs more heap memory\n")); + mali_group_bottom_half(core->group, GROUP_EVENT_GP_OOM); /* Will release group lock */ + return; + } + else if (irq_readout & MALIGP2_REG_VAL_IRQ_HANG) + { + /* Just ignore hang interrupts, the job timer will detect hanging jobs anyways */ + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_HANG); + } + + /* + * The only way to get here is if we got a HANG interrupt, which we ignore, or only one of two needed END_CMD_LST interrupts. + * Re-enable interrupts and let core continue to run. + */ + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED); + mali_group_unlock(core->group); + +#if MALI_TIMELINE_PROFILING_ENABLED +#if 0 /* Bottom half TLP logging is currently not supported */ + _mali_osk_profiling_add_event( MALI_PROFILING_EVENT_TYPE_STOP| MALI_PROFILING_EVENT_CHANNEL_SOFTWARE , _mali_osk_get_pid(), _mali_osk_get_tid()+11000, 0, 0, 0); +#endif +#endif +} + +static void mali_gp_irq_probe_trigger(void *data) +{ + struct mali_gp_core *core = (struct mali_gp_core *)data; + + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED); /* @@@@ This should not be needed */ + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT, MALIGP2_REG_VAL_CMD_FORCE_HANG); + _mali_osk_mem_barrier(); +} + +static _mali_osk_errcode_t mali_gp_irq_probe_ack(void *data) +{ + struct mali_gp_core *core = (struct mali_gp_core *)data; + u32 irq_readout; + + irq_readout = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_STAT); + if (MALIGP2_REG_VAL_IRQ_FORCE_HANG & irq_readout) + { + mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_FORCE_HANG); + _mali_osk_mem_barrier(); + return _MALI_OSK_ERR_OK; + } + + return _MALI_OSK_ERR_FAULT; +} + +/* ------ local helper functions below --------- */ + +static void mali_gp_post_process_job(struct mali_gp_core *core, mali_bool suspend) +{ + MALI_ASSERT_GROUP_LOCKED(core->group); + + if (NULL != core->running_job) + { + u32 val0 = 0; + u32 val1 = 0; +#if MALI_TIMELINE_PROFILING_ENABLED + u32 event_id; +#endif + + if (MALI_HW_CORE_NO_COUNTER != core->counter_src0_used) + { + val0 = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_VALUE); + if (mali_gp_job_get_perf_counter_flag(core->running_job) && + _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE && mali_gp_job_get_perf_counter_src0(core->running_job) == core->counter_src0_used) + { + /* We retrieved the counter that user space asked for, so return the value through the job object */ + mali_gp_job_set_perf_counter_value0(core->running_job, val0); + } + else + { + /* User space asked for a counter, but this is not what we retrived (overridden by counter src set on core) */ + mali_gp_job_set_perf_counter_value0(core->running_job, MALI_HW_CORE_INVALID_VALUE); + } + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_report_hw_counter(COUNTER_VP_C0, val0); +#endif + + } + + if (MALI_HW_CORE_NO_COUNTER != core->counter_src1_used) + { + val1 = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE); + if (mali_gp_job_get_perf_counter_flag(core->running_job) && + _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE && mali_gp_job_get_perf_counter_src1(core->running_job) == core->counter_src1_used) + { + /* We retrieved the counter that user space asked for, so return the value through the job object */ + mali_gp_job_set_perf_counter_value1(core->running_job, val1); + } + else + { + /* User space asked for a counter, but this is not what we retrieved (overridden by counter src set on core) */ + mali_gp_job_set_perf_counter_value1(core->running_job, MALI_HW_CORE_INVALID_VALUE); + } + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_report_hw_counter(COUNTER_VP_C1, val1); +#endif + } + +#if MALI_TIMELINE_PROFILING_ENABLED + if (MALI_TRUE == suspend) + { + event_id = MALI_PROFILING_EVENT_TYPE_SUSPEND|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(0); + } + else + { + event_id = MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(0); + } + _mali_osk_profiling_add_event(event_id, val0, val1, core->counter_src0_used | (core->counter_src1_used << 8), 0, 0); +#endif + + mali_gp_job_set_current_heap_addr(core->running_job, + mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR)); + + if (MALI_TRUE != suspend) + { + /* We are no longer running a job... */ + core->running_job = NULL; + _mali_osk_timer_del(core->timeout_timer); + } + } +} + +/* callback function for gp core timeout */ +static void mali_gp_timeout(void *data) +{ + struct mali_gp_core * core = ((struct mali_gp_core *)data); + + MALI_DEBUG_PRINT(3, ("Mali GP: TIMEOUT callback \n")); + core->core_timed_out = MALI_TRUE; + _mali_osk_irq_schedulework(core->irq); +} + +#if 0 +void mali_gp_print_state(struct mali_gp_core *core) +{ + MALI_DEBUG_PRINT(2, ("Mali GP: State: 0x%08x\n", mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_STATUS) )); +} +#endif + +#if MALI_STATE_TRACKING +u32 mali_gp_dump_state(struct mali_gp_core *core, char *buf, u32 size) +{ + int n = 0; + + n += _mali_osk_snprintf(buf + n, size - n, "\tGP: %s\n", core->hw_core.description); + + return n; +} +#endif diff --git a/drivers/media/video/samsung/mali/common/mali_gp.h b/drivers/media/video/samsung/mali/common/mali_gp.h new file mode 100644 index 0000000..3175b75 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_gp.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MALI_GP_H__ +#define __MALI_GP_H__ + +#include "mali_osk.h" +#include "mali_gp_job.h" + +struct mali_gp_core; +struct mali_group; + +_mali_osk_errcode_t mali_gp_initialize(void); +void mali_gp_terminate(void); + +struct mali_gp_core *mali_gp_create(const _mali_osk_resource_t * resource, struct mali_group *group); +void mali_gp_delete(struct mali_gp_core *core); + +void mali_gp_stop_bus(struct mali_gp_core *core); +_mali_osk_errcode_t mali_gp_stop_bus_wait(struct mali_gp_core *core); +void mali_gp_hard_reset(struct mali_gp_core *core); +_mali_osk_errcode_t mali_gp_reset(struct mali_gp_core *core); + +void mali_gp_job_start(struct mali_gp_core *core, struct mali_gp_job *job); +void mali_gp_resume_with_new_heap(struct mali_gp_core *core, u32 start_addr, u32 end_addr); + +void mali_gp_abort_job(struct mali_gp_core *core); + +u32 mali_gp_core_get_version(struct mali_gp_core *core); + +mali_bool mali_gp_core_set_counter_src0(struct mali_gp_core *core, u32 counter); +mali_bool mali_gp_core_set_counter_src1(struct mali_gp_core *core, u32 counter); +u32 mali_gp_core_get_counter_src0(struct mali_gp_core *core); +u32 mali_gp_core_get_counter_src1(struct mali_gp_core *core); +struct mali_gp_core *mali_gp_get_global_gp_core(void); + +u32 mali_gp_dump_state(struct mali_gp_core *core, char *buf, u32 size); + +#endif /* __MALI_GP_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_gp_job.c b/drivers/media/video/samsung/mali/common/mali_gp_job.c new file mode 100644 index 0000000..abe1d93 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_gp_job.c @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mali_gp_job.h" +#include "mali_osk.h" +#include "mali_osk_list.h" +#include "mali_uk_types.h" + +struct mali_gp_job *mali_gp_job_create(struct mali_session_data *session, _mali_uk_gp_start_job_s *args, u32 id) +{ + struct mali_gp_job *job; + + job = _mali_osk_malloc(sizeof(struct mali_gp_job)); + if (NULL != job) + { + _mali_osk_list_init(&job->list); + job->session = session; + job->id = id; + job->user_id = args->user_job_ptr; + _mali_osk_memcpy(job->frame_registers, args->frame_registers, sizeof(job->frame_registers)); + job->heap_current_addr = args->frame_registers[4]; + job->perf_counter_flag = args->perf_counter_flag; + job->perf_counter_src0 = args->perf_counter_src0; + job->perf_counter_src1 = args->perf_counter_src1; + job->perf_counter_value0 = 0; + job->perf_counter_value1 = 0; + + job->pid = _mali_osk_get_pid(); + job->tid = _mali_osk_get_tid(); + job->frame_builder_id = args->frame_builder_id; + job->flush_id = args->flush_id; + + return job; + } + + return NULL; +} + +void mali_gp_job_delete(struct mali_gp_job *job) +{ + _mali_osk_free(job); +} diff --git a/drivers/media/video/samsung/mali/common/mali_gp_job.h b/drivers/media/video/samsung/mali/common/mali_gp_job.h new file mode 100644 index 0000000..9c29f1c --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_gp_job.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MALI_GP_JOB_H__ +#define __MALI_GP_JOB_H__ + +#include "mali_osk.h" +#include "mali_osk_list.h" +#include "mali_uk_types.h" +#include "mali_session.h" + +/** + * The structure represends a GP job, including all sub-jobs + * (This struct unfortunatly needs to be public because of how the _mali_osk_list_* + * mechanism works) + */ +struct mali_gp_job +{ + _mali_osk_list_t list; /**< Used to link jobs together in the scheduler queue */ + struct mali_session_data *session; /**< Session which submitted this job */ + u32 id; /**< identifier for this job in kernel space (sequential numbering) */ + u32 user_id; /**< identifier for the job in user space */ + u32 frame_registers[MALIGP2_NUM_REGS_FRAME]; /**< core specific registers associated with this job, see ARM DDI0415A */ + u32 heap_current_addr; /**< Holds the current HEAP address when the job has completed */ + u32 perf_counter_flag; /**< bitmask indicating which performance counters to enable, see \ref _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE and related macro definitions */ + u32 perf_counter_src0; /**< source id for performance counter 0 (see ARM DDI0415A, Table 3-60) */ + u32 perf_counter_src1; /**< source id for performance counter 1 (see ARM DDI0415A, Table 3-60) */ + u32 perf_counter_value0; /**< Value of performance counter 0 (to be returned to user space) */ + u32 perf_counter_value1; /**< Value of performance counter 1 (to be returned to user space) */ + u32 pid; /**< Process ID of submitting process */ + u32 tid; /**< Thread ID of submitting thread */ + u32 frame_builder_id; /**< id of the originating frame builder */ + u32 flush_id; /**< flush id within the originating frame builder */ +}; + +struct mali_gp_job *mali_gp_job_create(struct mali_session_data *session, _mali_uk_gp_start_job_s *args, u32 id); +void mali_gp_job_delete(struct mali_gp_job *job); + +MALI_STATIC_INLINE u32 mali_gp_job_get_id(struct mali_gp_job *job) +{ + return (NULL == job) ? 0 : job->id; +} + +MALI_STATIC_INLINE u32 mali_gp_job_get_user_id(struct mali_gp_job *job) +{ + return job->user_id; +} + +MALI_STATIC_INLINE u32 mali_gp_job_get_frame_builder_id(struct mali_gp_job *job) +{ + return job->frame_builder_id; +} + +MALI_STATIC_INLINE u32 mali_gp_job_get_flush_id(struct mali_gp_job *job) +{ + return job->flush_id; +} + +MALI_STATIC_INLINE u32* mali_gp_job_get_frame_registers(struct mali_gp_job *job) +{ + return job->frame_registers; +} + +MALI_STATIC_INLINE struct mali_session_data *mali_gp_job_get_session(struct mali_gp_job *job) +{ + return job->session; +} + +MALI_STATIC_INLINE mali_bool mali_gp_job_has_vs_job(struct mali_gp_job *job) +{ + return (job->frame_registers[0] != job->frame_registers[1]) ? MALI_TRUE : MALI_FALSE; +} + +MALI_STATIC_INLINE mali_bool mali_gp_job_has_plbu_job(struct mali_gp_job *job) +{ + return (job->frame_registers[2] != job->frame_registers[3]) ? MALI_TRUE : MALI_FALSE; +} + +MALI_STATIC_INLINE u32 mali_gp_job_get_current_heap_addr(struct mali_gp_job *job) +{ + return job->heap_current_addr; +} + +MALI_STATIC_INLINE void mali_gp_job_set_current_heap_addr(struct mali_gp_job *job, u32 heap_addr) +{ + job->heap_current_addr = heap_addr; +} + +MALI_STATIC_INLINE u32 mali_gp_job_get_perf_counter_flag(struct mali_gp_job *job) +{ + return job->perf_counter_flag; +} + +MALI_STATIC_INLINE u32 mali_gp_job_get_perf_counter_src0(struct mali_gp_job *job) +{ + return job->perf_counter_src0; +} + +MALI_STATIC_INLINE u32 mali_gp_job_get_perf_counter_src1(struct mali_gp_job *job) +{ + return job->perf_counter_src1; +} + +MALI_STATIC_INLINE u32 mali_gp_job_get_perf_counter_value0(struct mali_gp_job *job) +{ + return job->perf_counter_value0; +} + +MALI_STATIC_INLINE u32 mali_gp_job_get_perf_counter_value1(struct mali_gp_job *job) +{ + return job->perf_counter_value1; +} + +MALI_STATIC_INLINE void mali_gp_job_set_perf_counter_value0(struct mali_gp_job *job, u32 value) +{ + job->perf_counter_value0 = value; +} + +MALI_STATIC_INLINE void mali_gp_job_set_perf_counter_value1(struct mali_gp_job *job, u32 value) +{ + job->perf_counter_value1 = value; +} + +#endif /* __MALI_GP_JOB_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_gp_scheduler.c b/drivers/media/video/samsung/mali/common/mali_gp_scheduler.c new file mode 100644 index 0000000..05f00fc --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_gp_scheduler.c @@ -0,0 +1,438 @@ +/* + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mali_gp_scheduler.h" +#include "mali_kernel_common.h" +#include "mali_osk.h" +#include "mali_osk_list.h" +#include "mali_scheduler.h" +#include "mali_gp.h" +#include "mali_gp_job.h" +#include "mali_group.h" +#include "mali_cluster.h" + +enum mali_gp_slot_state +{ + MALI_GP_SLOT_STATE_IDLE, + MALI_GP_SLOT_STATE_WORKING, +}; + +/* A render slot is an entity which jobs can be scheduled onto */ +struct mali_gp_slot +{ + struct mali_group *group; + /* + * We keep track of the state here as well as in the group object + * so we don't need to take the group lock so often (and also avoid clutter with the working lock) + */ + enum mali_gp_slot_state state; + u32 returned_cookie; +}; + +static u32 gp_version = 0; +static _MALI_OSK_LIST_HEAD(job_queue); /* List of jobs with some unscheduled work */ +static struct mali_gp_slot slot; + +/* Variables to allow safe pausing of the scheduler */ +static _mali_osk_wait_queue_t *gp_scheduler_working_wait_queue = NULL; +static u32 pause_count = 0; + +static mali_bool mali_gp_scheduler_is_suspended(void); + +static _mali_osk_lock_t *gp_scheduler_lock = NULL; +/* Contains tid of thread that locked the scheduler or 0, if not locked */ + +_mali_osk_errcode_t mali_gp_scheduler_initialize(void) +{ + u32 i; + + _MALI_OSK_INIT_LIST_HEAD(&job_queue); + + gp_scheduler_lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_SCHEDULER); + gp_scheduler_working_wait_queue = _mali_osk_wait_queue_init(); + + if (NULL == gp_scheduler_lock) + { + return _MALI_OSK_ERR_NOMEM; + } + + if (NULL == gp_scheduler_working_wait_queue) + { + _mali_osk_lock_term(gp_scheduler_lock); + return _MALI_OSK_ERR_NOMEM; + } + + /* Find all the available GP cores */ + for (i = 0; i < mali_cluster_get_glob_num_clusters(); i++) + { + u32 group_id = 0; + struct mali_cluster *curr_cluster = mali_cluster_get_global_cluster(i); + struct mali_group *group = mali_cluster_get_group(curr_cluster, group_id); + while (NULL != group) + { + struct mali_gp_core *gp_core = mali_group_get_gp_core(group); + if (NULL != gp_core) + { + if (0 == gp_version) + { + /* Retrieve GP version */ + gp_version = mali_gp_core_get_version(gp_core); + } + slot.group = group; + slot.state = MALI_GP_SLOT_STATE_IDLE; + break; /* There are only one GP, no point in looking for more */ + } + group_id++; + group = mali_cluster_get_group(curr_cluster, group_id); + } + } + + return _MALI_OSK_ERR_OK; +} + +void mali_gp_scheduler_terminate(void) +{ + _mali_osk_wait_queue_term(gp_scheduler_working_wait_queue); + _mali_osk_lock_term(gp_scheduler_lock); +} + +MALI_STATIC_INLINE void mali_gp_scheduler_lock(void) +{ + if(_MALI_OSK_ERR_OK != _mali_osk_lock_wait(gp_scheduler_lock, _MALI_OSK_LOCKMODE_RW)) + { + /* Non-interruptable lock failed: this should never happen. */ + MALI_DEBUG_ASSERT(0); + } + MALI_DEBUG_PRINT(5, ("Mali GP scheduler: GP scheduler lock taken\n")); +} + +MALI_STATIC_INLINE void mali_gp_scheduler_unlock(void) +{ + MALI_DEBUG_PRINT(5, ("Mali GP scheduler: Releasing GP scheduler lock\n")); + _mali_osk_lock_signal(gp_scheduler_lock, _MALI_OSK_LOCKMODE_RW); +} + +#ifdef DEBUG +MALI_STATIC_INLINE void mali_gp_scheduler_assert_locked(void) +{ + MALI_DEBUG_ASSERT_LOCK_HELD(gp_scheduler_lock); +} +#define MALI_ASSERT_GP_SCHEDULER_LOCKED() mali_gp_scheduler_assert_locked() +#else +#define MALI_ASSERT_GP_SCHEDULER_LOCKED() +#endif + +static void mali_gp_scheduler_schedule(void) +{ + struct mali_gp_job *job; + + MALI_ASSERT_GP_SCHEDULER_LOCKED(); + + if (0 < pause_count || MALI_GP_SLOT_STATE_IDLE != slot.state || _mali_osk_list_empty(&job_queue)) + { + MALI_DEBUG_PRINT(4, ("Mali GP scheduler: Nothing to schedule (paused=%u, idle slots=%u)\n", + pause_count, MALI_GP_SLOT_STATE_IDLE == slot.state ? 1 : 0)); + return; /* Nothing to do, so early out */ + } + + job = _MALI_OSK_LIST_ENTRY(job_queue.next, struct mali_gp_job, list); + + MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Starting job %u (0x%08X)\n", mali_gp_job_get_id(job), job)); + if (_MALI_OSK_ERR_OK == mali_group_start_gp_job(slot.group, job)) + { + /* Mark slot as busy */ + slot.state = MALI_GP_SLOT_STATE_WORKING; + + /* Remove from queue of unscheduled jobs */ + _mali_osk_list_del(&job->list); + } + else + { + MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Failed to start GP job\n")); + } +} + +static void mali_gp_scheduler_return_job_to_user(struct mali_gp_job *job, mali_bool success) +{ + _mali_osk_notification_t *notobj = _mali_osk_notification_create(_MALI_NOTIFICATION_GP_FINISHED, sizeof(_mali_uk_gp_job_finished_s)); + if (NULL != notobj) + { + _mali_uk_gp_job_finished_s *jobres = notobj->result_buffer; + _mali_osk_memset(jobres, 0, sizeof(_mali_uk_gp_job_finished_s)); /* @@@@ can be removed once we initialize all members in this struct */ + jobres->user_job_ptr = mali_gp_job_get_user_id(job); + if (MALI_TRUE == success) + { + jobres->status = _MALI_UK_JOB_STATUS_END_SUCCESS; + } + else + { + jobres->status = _MALI_UK_JOB_STATUS_END_UNKNOWN_ERR; + } + + jobres->heap_current_addr = mali_gp_job_get_current_heap_addr(job); + jobres->perf_counter0 = mali_gp_job_get_perf_counter_value0(job); + jobres->perf_counter1 = mali_gp_job_get_perf_counter_value1(job); + + mali_session_send_notification(mali_gp_job_get_session(job), notobj); + } + else + { + MALI_PRINT_ERROR(("Mali GP scheduler: Unable to allocate notification object\n")); + } + + mali_gp_job_delete(job); +} + + +void mali_gp_scheduler_do_schedule(void) +{ + mali_gp_scheduler_lock(); + + mali_gp_scheduler_schedule(); + + mali_gp_scheduler_unlock(); +} + +void mali_gp_scheduler_job_done(struct mali_group *group, struct mali_gp_job *job, mali_bool success) +{ + MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Job %u (0x%08X) completed (%s)\n", mali_gp_job_get_id(job), job, success ? "success" : "failure")); + + mali_gp_scheduler_lock(); + + /* Mark slot as idle again */ + slot.state = MALI_GP_SLOT_STATE_IDLE; + + /* If paused, then this was the last job, so wake up sleeping workers */ + if (pause_count > 0) + { + _mali_osk_wait_queue_wake_up(gp_scheduler_working_wait_queue); + } + else + { + mali_gp_scheduler_schedule(); + } + + mali_gp_scheduler_unlock(); + + mali_gp_scheduler_return_job_to_user(job, success); +} + +void mali_gp_scheduler_oom(struct mali_group *group, struct mali_gp_job *job) +{ + _mali_osk_notification_t *notobj; + + notobj = _mali_osk_notification_create(_MALI_NOTIFICATION_GP_STALLED, sizeof(_mali_uk_gp_job_suspended_s)); + + if (NULL != notobj) + { + _mali_uk_gp_job_suspended_s * jobres; + + mali_gp_scheduler_lock(); + + jobres = (_mali_uk_gp_job_suspended_s *)notobj->result_buffer; + + jobres->user_job_ptr = mali_gp_job_get_user_id(job); + jobres->reason = _MALIGP_JOB_SUSPENDED_OUT_OF_MEMORY; + jobres->cookie = mali_gp_job_get_id(job); + slot.returned_cookie = jobres->cookie; + + mali_session_send_notification(mali_gp_job_get_session(job), notobj); + + mali_gp_scheduler_unlock(); + } + + /* + * If this function failed, then we could return the job to user space right away, + * but there is a job timer anyway that will do that eventually. + * This is not exactly a common case anyway. + */ +} + +void mali_gp_scheduler_suspend(void) +{ + mali_gp_scheduler_lock(); + pause_count++; /* Increment the pause_count so that no more jobs will be scheduled */ + mali_gp_scheduler_unlock(); + + _mali_osk_wait_queue_wait_event(gp_scheduler_working_wait_queue, mali_gp_scheduler_is_suspended); +} + +void mali_gp_scheduler_resume(void) +{ + mali_gp_scheduler_lock(); + pause_count--; /* Decrement pause_count to allow scheduling again (if it reaches 0) */ + if (0 == pause_count) + { + mali_gp_scheduler_schedule(); + } + mali_gp_scheduler_unlock(); +} + +_mali_osk_errcode_t _mali_ukk_gp_start_job(_mali_uk_gp_start_job_s *args) +{ + struct mali_session_data *session; + struct mali_gp_job *job; + + MALI_DEBUG_ASSERT_POINTER(args); + + if (NULL == args->ctx) + { + return _MALI_OSK_ERR_INVALID_ARGS; + } + + session = (struct mali_session_data*)args->ctx; + if (NULL == session) + { + return _MALI_OSK_ERR_FAULT; + } + + job = mali_gp_job_create(session, args, mali_scheduler_get_new_id()); + if (NULL == job) + { + return _MALI_OSK_ERR_NOMEM; + } + + mali_gp_scheduler_lock(); + + _mali_osk_list_addtail(&job->list, &job_queue); + + MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Job %u (0x%08X) queued\n", mali_gp_job_get_id(job), job)); + + mali_gp_scheduler_schedule(); + + mali_gp_scheduler_unlock(); + + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t _mali_ukk_get_gp_number_of_cores(_mali_uk_get_gp_number_of_cores_s *args) +{ + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + args->number_of_cores = 1; + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t _mali_ukk_get_gp_core_version(_mali_uk_get_gp_core_version_s *args) +{ + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + args->version = gp_version; + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t _mali_ukk_gp_suspend_response(_mali_uk_gp_suspend_response_s *args) +{ + struct mali_session_data *session; + _mali_osk_errcode_t ret = _MALI_OSK_ERR_FAULT; + + MALI_DEBUG_ASSERT_POINTER(args); + + if (NULL == args->ctx) + { + return _MALI_OSK_ERR_INVALID_ARGS; + } + + session = (struct mali_session_data*)args->ctx; + if (NULL == session) + { + return _MALI_OSK_ERR_FAULT; + } + + mali_gp_scheduler_lock(); + + /* Make sure that the cookie returned by user space is the same as we provided in the first place */ + if (args->cookie != slot.returned_cookie) + { + MALI_DEBUG_PRINT(2, ("Mali GP scheduler: Got an illegal cookie from user space, expected %u but got %u (job id)\n", slot.returned_cookie, args->cookie)) ; + mali_gp_scheduler_unlock(); + return _MALI_OSK_ERR_FAULT; + } + + mali_gp_scheduler_unlock(); + + switch (args->code) + { + case _MALIGP_JOB_RESUME_WITH_NEW_HEAP: + MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Resuming job %u with new heap; 0x%08X - 0x%08X\n", args->cookie, args->arguments[0], args->arguments[1])); + mali_group_resume_gp_with_new_heap(slot.group, args->cookie, args->arguments[0], args->arguments[1]); + ret = _MALI_OSK_ERR_OK; + break; + + case _MALIGP_JOB_ABORT: + MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Aborting job %u, no new heap provided\n", args->cookie)); + mali_group_abort_gp_job(slot.group, args->cookie); + ret = _MALI_OSK_ERR_OK; + break; + + default: + MALI_PRINT_ERROR(("Mali GP scheduler: Wrong suspend response from user space\n")); + ret = _MALI_OSK_ERR_FAULT; + break; + } + + return ret; + +} + +void mali_gp_scheduler_abort_session(struct mali_session_data *session) +{ + struct mali_gp_job *job, *tmp; + + mali_gp_scheduler_lock(); + MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Aborting all jobs from session 0x%08x\n", session)); + + /* Check queue for jobs and remove */ + _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &job_queue, struct mali_gp_job, list) + { + if (mali_gp_job_get_session(job) == session) + { + MALI_DEBUG_PRINT(4, ("Mali GP scheduler: Removing GP job 0x%08x from queue\n", job)); + _mali_osk_list_del(&(job->list)); + mali_gp_job_delete(job); + } + } + + mali_gp_scheduler_unlock(); + + /* Abort running jobs from this session. It is safe to do this outside + * the scheduler lock as there is only one GP core, and the queue has + * already been emptied, as long as there are no new jobs coming in + * from user space. */ + mali_group_abort_session(slot.group, session); +} + +static mali_bool mali_gp_scheduler_is_suspended(void) +{ + mali_bool ret; + + mali_gp_scheduler_lock(); + ret = pause_count > 0 && slot.state == MALI_GP_SLOT_STATE_IDLE; + mali_gp_scheduler_unlock(); + + return ret; +} + + +#if MALI_STATE_TRACKING +u32 mali_gp_scheduler_dump_state(char *buf, u32 size) +{ + int n = 0; + + n += _mali_osk_snprintf(buf + n, size - n, "GP\n"); + n += _mali_osk_snprintf(buf + n, size - n, "\tQueue is %s\n", _mali_osk_list_empty(&job_queue) ? "empty" : "not empty"); + + n += mali_group_dump_state(slot.group, buf + n, size - n); + n += _mali_osk_snprintf(buf + n, size - n, "\t\tState: %d\n", mali_group_gp_state(slot.group)); + n += _mali_osk_snprintf(buf + n, size - n, "\n"); + + return n; +} +#endif diff --git a/drivers/media/video/samsung/mali/common/mali_gp_scheduler.h b/drivers/media/video/samsung/mali/common/mali_gp_scheduler.h new file mode 100644 index 0000000..ef58509 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_gp_scheduler.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MALI_GP_SCHEDULER_H__ +#define __MALI_GP_SCHEDULER_H__ + +#include "mali_osk.h" +#include "mali_cluster.h" +#include "mali_gp_job.h" + +_mali_osk_errcode_t mali_gp_scheduler_initialize(void); +void mali_gp_scheduler_terminate(void); + +void mali_gp_scheduler_do_schedule(void); +void mali_gp_scheduler_job_done(struct mali_group *group, struct mali_gp_job *job, mali_bool success); +void mali_gp_scheduler_oom(struct mali_group *group, struct mali_gp_job *job); +void mali_gp_scheduler_abort_session(struct mali_session_data *session); +u32 mali_gp_scheduler_dump_state(char *buf, u32 size); + +void mali_gp_scheduler_suspend(void); +void mali_gp_scheduler_resume(void); + +#endif /* __MALI_GP_SCHEDULER_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_group.c b/drivers/media/video/samsung/mali/common/mali_group.c new file mode 100644 index 0000000..9202bc1 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_group.c @@ -0,0 +1,841 @@ +/* + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mali_kernel_common.h" +#include "mali_group.h" +#include "mali_osk.h" +#include "mali_cluster.h" +#include "mali_gp.h" +#include "mali_pp.h" +#include "mali_mmu.h" +#include "mali_gp_scheduler.h" +#include "mali_pp_scheduler.h" +#include "mali_pm.h" + +/* + * The group object is the most important object in the device driver, + * and acts as the center of many HW operations. + * The reason for this is that operations on the MMU will affect all + * cores connected to this MMU (a group is defined by the MMU and the + * cores which are connected to this). + * The group lock is thus the most important lock, followed by the + * GP and PP scheduler locks. They must be taken in the following + * order: + * GP/PP lock first, then group lock(s). + */ + +/** + * The structure represents a render group + * A render group is defined by all the cores that share the same Mali MMU + */ + +struct mali_group +{ + struct mali_cluster *cluster; + + struct mali_mmu_core *mmu; + struct mali_session_data *session; + int page_dir_ref_count; + mali_bool power_is_on; +#if defined(USING_MALI200) + mali_bool pagedir_activation_failed; +#endif + + struct mali_gp_core *gp_core; + enum mali_group_core_state gp_state; + struct mali_gp_job *gp_running_job; + + struct mali_pp_core *pp_core; + enum mali_group_core_state pp_state; + struct mali_pp_job *pp_running_job; + u32 pp_running_sub_job; + + _mali_osk_lock_t *lock; +}; + +static struct mali_group *mali_global_groups[MALI_MAX_NUMBER_OF_GROUPS]; +static u32 mali_global_num_groups = 0; + +enum mali_group_activate_pd_status +{ + MALI_GROUP_ACTIVATE_PD_STATUS_FAILED, + MALI_GROUP_ACTIVATE_PD_STATUS_OK_KEPT_PD, + MALI_GROUP_ACTIVATE_PD_STATUS_OK_SWITCHED_PD, +}; + +/* local helper functions */ +static enum mali_group_activate_pd_status mali_group_activate_page_directory(struct mali_group *group, struct mali_session_data *session); +static void mali_group_deactivate_page_directory(struct mali_group *group, struct mali_session_data *session); +static void mali_group_recovery_reset(struct mali_group *group); +static void mali_group_complete_jobs(struct mali_group *group, mali_bool complete_gp, mali_bool complete_pp, bool success); + +void mali_group_lock(struct mali_group *group) +{ + if(_MALI_OSK_ERR_OK != _mali_osk_lock_wait(group->lock, _MALI_OSK_LOCKMODE_RW)) + { + /* Non-interruptable lock failed: this should never happen. */ + MALI_DEBUG_ASSERT(0); + } + MALI_DEBUG_PRINT(5, ("Mali group: Group lock taken 0x%08X\n", group)); +} + +void mali_group_unlock(struct mali_group *group) +{ + MALI_DEBUG_PRINT(5, ("Mali group: Releasing group lock 0x%08X\n", group)); + _mali_osk_lock_signal(group->lock, _MALI_OSK_LOCKMODE_RW); +} + +#ifdef DEBUG +void mali_group_assert_locked(struct mali_group *group) +{ + MALI_DEBUG_ASSERT_LOCK_HELD(group->lock); +} +#endif + + +struct mali_group *mali_group_create(struct mali_cluster *cluster, struct mali_mmu_core *mmu) +{ + struct mali_group *group = NULL; + + if (mali_global_num_groups >= MALI_MAX_NUMBER_OF_GROUPS) + { + MALI_PRINT_ERROR(("Mali group: Too many group objects created\n")); + return NULL; + } + + group = _mali_osk_malloc(sizeof(struct mali_group)); + if (NULL != group) + { + _mali_osk_memset(group, 0, sizeof(struct mali_group)); + group->lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ |_MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_GROUP); + if (NULL != group->lock) + { + group->cluster = cluster; + group->mmu = mmu; /* This group object now owns the MMU object */ + group->session = NULL; + group->page_dir_ref_count = 0; + group->power_is_on = MALI_TRUE; + + group->gp_state = MALI_GROUP_CORE_STATE_IDLE; + group->pp_state = MALI_GROUP_CORE_STATE_IDLE; +#if defined(USING_MALI200) + group->pagedir_activation_failed = MALI_FALSE; +#endif + mali_global_groups[mali_global_num_groups] = group; + mali_global_num_groups++; + + return group; + } + _mali_osk_free(group); + } + + return NULL; +} + +void mali_group_add_gp_core(struct mali_group *group, struct mali_gp_core* gp_core) +{ + /* This group object now owns the GP core object */ + group->gp_core = gp_core; +} + +void mali_group_add_pp_core(struct mali_group *group, struct mali_pp_core* pp_core) +{ + /* This group object now owns the PP core object */ + group->pp_core = pp_core; +} + +void mali_group_delete(struct mali_group *group) +{ + u32 i; + + /* Delete the resources that this group owns */ + if (NULL != group->gp_core) + { + mali_gp_delete(group->gp_core); + } + + if (NULL != group->pp_core) + { + mali_pp_delete(group->pp_core); + } + + if (NULL != group->mmu) + { + mali_mmu_delete(group->mmu); + } + + for (i = 0; i < mali_global_num_groups; i++) + { + if (mali_global_groups[i] == group) + { + mali_global_groups[i] = NULL; + mali_global_num_groups--; + break; + } + } + + _mali_osk_lock_term(group->lock); + + _mali_osk_free(group); +} + +/* Called from mali_cluster_reset() when the system is re-turned on */ +void mali_group_reset(struct mali_group *group) +{ + mali_group_lock(group); + + group->session = NULL; + + if (NULL != group->mmu) + { + mali_mmu_reset(group->mmu); + } + + if (NULL != group->gp_core) + { + mali_gp_reset(group->gp_core); + } + + if (NULL != group->pp_core) + { + mali_pp_reset(group->pp_core); + } + + mali_group_unlock(group); +} + +struct mali_gp_core* mali_group_get_gp_core(struct mali_group *group) +{ + return group->gp_core; +} + +struct mali_pp_core* mali_group_get_pp_core(struct mali_group *group) +{ + return group->pp_core; +} + +_mali_osk_errcode_t mali_group_start_gp_job(struct mali_group *group, struct mali_gp_job *job) +{ + struct mali_session_data *session; + enum mali_group_activate_pd_status activate_status; + + MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->gp_state); + + mali_pm_core_event(MALI_CORE_EVENT_GP_START); + + session = mali_gp_job_get_session(job); + + mali_group_lock(group); + + mali_cluster_l2_cache_invalidate_all(group->cluster, mali_gp_job_get_id(job)); + + activate_status = mali_group_activate_page_directory(group, session); + if (MALI_GROUP_ACTIVATE_PD_STATUS_FAILED != activate_status) + { + /* if session is NOT kept Zapping is done as part of session switch */ + if (MALI_GROUP_ACTIVATE_PD_STATUS_OK_KEPT_PD == activate_status) + { + mali_mmu_zap_tlb_without_stall(group->mmu); + } + mali_gp_job_start(group->gp_core, job); + group->gp_running_job = job; + group->gp_state = MALI_GROUP_CORE_STATE_WORKING; + + mali_group_unlock(group); + + return _MALI_OSK_ERR_OK; + } + +#if defined(USING_MALI200) + group->pagedir_activation_failed = MALI_TRUE; +#endif + + mali_group_unlock(group); + + mali_pm_core_event(MALI_CORE_EVENT_GP_STOP); /* Failed to start, so "cancel" the MALI_CORE_EVENT_GP_START */ + return _MALI_OSK_ERR_FAULT; +} + +_mali_osk_errcode_t mali_group_start_pp_job(struct mali_group *group, struct mali_pp_job *job, u32 sub_job) +{ + struct mali_session_data *session; + enum mali_group_activate_pd_status activate_status; + + MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->pp_state); + + mali_pm_core_event(MALI_CORE_EVENT_PP_START); + + session = mali_pp_job_get_session(job); + + mali_group_lock(group); + + mali_cluster_l2_cache_invalidate_all(group->cluster, mali_pp_job_get_id(job)); + + activate_status = mali_group_activate_page_directory(group, session); + if (MALI_GROUP_ACTIVATE_PD_STATUS_FAILED != activate_status) + { + /* if session is NOT kept Zapping is done as part of session switch */ + if (MALI_GROUP_ACTIVATE_PD_STATUS_OK_KEPT_PD == activate_status) + { + MALI_DEBUG_PRINT(3, ("PP starting job PD_Switch 0 Flush 1 Zap 1\n")); + mali_mmu_zap_tlb_without_stall(group->mmu); + } + mali_pp_job_start(group->pp_core, job, sub_job); + group->pp_running_job = job; + group->pp_running_sub_job = sub_job; + group->pp_state = MALI_GROUP_CORE_STATE_WORKING; + + mali_group_unlock(group); + + return _MALI_OSK_ERR_OK; + } + +#if defined(USING_MALI200) + group->pagedir_activation_failed = MALI_TRUE; +#endif + + mali_group_unlock(group); + + mali_pm_core_event(MALI_CORE_EVENT_PP_STOP); /* Failed to start, so "cancel" the MALI_CORE_EVENT_PP_START */ + return _MALI_OSK_ERR_FAULT; +} + +void mali_group_resume_gp_with_new_heap(struct mali_group *group, u32 job_id, u32 start_addr, u32 end_addr) +{ + mali_group_lock(group); + + if (group->gp_state != MALI_GROUP_CORE_STATE_OOM || + mali_gp_job_get_id(group->gp_running_job) != job_id) + { + mali_group_unlock(group); + return; /* Illegal request or job has already been aborted */ + } + + mali_cluster_l2_cache_invalidate_all_force(group->cluster); + mali_mmu_zap_tlb_without_stall(group->mmu); + + mali_gp_resume_with_new_heap(group->gp_core, start_addr, end_addr); + group->gp_state = MALI_GROUP_CORE_STATE_WORKING; + + mali_group_unlock(group); +} + +void mali_group_abort_gp_job(struct mali_group *group, u32 job_id) +{ + mali_group_lock(group); + + if (group->gp_state == MALI_GROUP_CORE_STATE_IDLE || + mali_gp_job_get_id(group->gp_running_job) != job_id) + { + mali_group_unlock(group); + return; /* No need to cancel or job has already been aborted or completed */ + } + + mali_group_complete_jobs(group, MALI_TRUE, MALI_FALSE, MALI_FALSE); /* Will release group lock */ +} + +void mali_group_abort_pp_job(struct mali_group *group, u32 job_id) +{ + mali_group_lock(group); + + if (group->pp_state == MALI_GROUP_CORE_STATE_IDLE || + mali_pp_job_get_id(group->pp_running_job) != job_id) + { + mali_group_unlock(group); + return; /* No need to cancel or job has already been aborted or completed */ + } + + mali_group_complete_jobs(group, MALI_FALSE, MALI_TRUE, MALI_FALSE); /* Will release group lock */ +} + +void mali_group_abort_session(struct mali_group *group, struct mali_session_data *session) +{ + struct mali_gp_job *gp_job; + struct mali_pp_job *pp_job; + u32 gp_job_id = 0; + u32 pp_job_id = 0; + mali_bool abort_pp = MALI_FALSE; + mali_bool abort_gp = MALI_FALSE; + + mali_group_lock(group); + + gp_job = group->gp_running_job; + pp_job = group->pp_running_job; + + if (gp_job && mali_gp_job_get_session(gp_job) == session) + { + MALI_DEBUG_PRINT(4, ("Aborting GP job 0x%08x from session 0x%08x\n", gp_job, session)); + + gp_job_id = mali_gp_job_get_id(gp_job); + abort_gp = MALI_TRUE; + } + + if (pp_job && mali_pp_job_get_session(pp_job) == session) + { + MALI_DEBUG_PRINT(4, ("Mali group: Aborting PP job 0x%08x from session 0x%08x\n", pp_job, session)); + + pp_job_id = mali_pp_job_get_id(pp_job); + abort_pp = MALI_TRUE; + } + + mali_group_unlock(group); + + /* These functions takes and releases the group lock */ + if (0 != abort_gp) + { + mali_group_abort_gp_job(group, gp_job_id); + } + if (0 != abort_pp) + { + mali_group_abort_pp_job(group, pp_job_id); + } + + mali_group_lock(group); + mali_group_remove_session_if_unused(group, session); + mali_group_unlock(group); +} + +enum mali_group_core_state mali_group_gp_state(struct mali_group *group) +{ + return group->gp_state; +} + +enum mali_group_core_state mali_group_pp_state(struct mali_group *group) +{ + return group->pp_state; +} + +/* group lock need to be taken before calling mali_group_bottom_half */ +void mali_group_bottom_half(struct mali_group *group, enum mali_group_event_t event) +{ + MALI_ASSERT_GROUP_LOCKED(group); + + switch (event) + { + case GROUP_EVENT_PP_JOB_COMPLETED: + mali_group_complete_jobs(group, MALI_FALSE, MALI_TRUE, MALI_TRUE); /* PP job SUCCESS */ + /* group lock is released by mali_group_complete_jobs() call above */ + break; + case GROUP_EVENT_PP_JOB_FAILED: + mali_group_complete_jobs(group, MALI_FALSE, MALI_TRUE, MALI_FALSE); /* PP job FAIL */ + /* group lock is released by mali_group_complete_jobs() call above */ + break; + case GROUP_EVENT_PP_JOB_TIMED_OUT: + mali_group_complete_jobs(group, MALI_FALSE, MALI_TRUE, MALI_FALSE); /* PP job TIMEOUT */ + /* group lock is released by mali_group_complete_jobs() call above */ + break; + case GROUP_EVENT_GP_JOB_COMPLETED: + mali_group_complete_jobs(group, MALI_TRUE, MALI_FALSE, MALI_TRUE); /* GP job SUCCESS */ + /* group lock is released by mali_group_complete_jobs() call above */ + break; + case GROUP_EVENT_GP_JOB_FAILED: + mali_group_complete_jobs(group, MALI_TRUE, MALI_FALSE, MALI_FALSE); /* GP job FAIL */ + /* group lock is released by mali_group_complete_jobs() call above */ + break; + case GROUP_EVENT_GP_JOB_TIMED_OUT: + mali_group_complete_jobs(group, MALI_TRUE, MALI_FALSE, MALI_FALSE); /* GP job TIMEOUT */ + /* group lock is released by mali_group_complete_jobs() call above */ + break; + case GROUP_EVENT_GP_OOM: + group->gp_state = MALI_GROUP_CORE_STATE_OOM; + mali_group_unlock(group); /* Nothing to do on the HW side, so just release group lock right away */ + mali_gp_scheduler_oom(group, group->gp_running_job); + break; + case GROUP_EVENT_MMU_PAGE_FAULT: + mali_group_complete_jobs(group, MALI_TRUE, MALI_TRUE, MALI_FALSE); /* GP and PP job FAIL */ + /* group lock is released by mali_group_complete_jobs() call above */ + break; + default: + break; + } +} + +struct mali_mmu_core *mali_group_get_mmu(struct mali_group *group) +{ + return group->mmu; +} + +struct mali_session_data *mali_group_get_session(struct mali_group *group) +{ + return group->session; +} + +struct mali_group *mali_group_get_glob_group(u32 index) +{ + if(mali_global_num_groups > index) + { + return mali_global_groups[index]; + } + + return NULL; +} + +u32 mali_group_get_glob_num_groups(void) +{ + return mali_global_num_groups; +} + +/* Used to check if scheduler for the other core type needs to be called on job completion. + * + * Used only for Mali-200, where job start may fail if the only MMU is busy + * with another session's address space. + */ +static inline mali_bool mali_group_other_reschedule_needed(struct mali_group *group) +{ + MALI_ASSERT_GROUP_LOCKED(group); + +#if defined(USING_MALI200) + if (group->pagedir_activation_failed) + { + group->pagedir_activation_failed = MALI_FALSE; + return MALI_TRUE; + } + else +#endif + { + return MALI_FALSE; + } +} + +static enum mali_group_activate_pd_status mali_group_activate_page_directory(struct mali_group *group, struct mali_session_data *session) +{ + enum mali_group_activate_pd_status retval; + MALI_ASSERT_GROUP_LOCKED(group); + + MALI_DEBUG_PRINT(5, ("Mali group: Activating page directory 0x%08X from session 0x%08X on group 0x%08X\n", mali_session_get_page_directory(session), session, group)); + MALI_DEBUG_ASSERT(0 <= group->page_dir_ref_count); + + if (0 != group->page_dir_ref_count) + { + if (group->session != session) + { + MALI_DEBUG_PRINT(4, ("Mali group: Activating session FAILED: 0x%08x on group 0x%08X. Existing session: 0x%08x\n", session, group, group->session)); + return MALI_GROUP_ACTIVATE_PD_STATUS_FAILED; + } + else + { + MALI_DEBUG_PRINT(4, ("Mali group: Activating session already activated: 0x%08x on group 0x%08X. New Ref: %d\n", session, group, 1+group->page_dir_ref_count)); + retval = MALI_GROUP_ACTIVATE_PD_STATUS_OK_KEPT_PD; + + } + } + else + { + /* There might be another session here, but it is ok to overwrite it since group->page_dir_ref_count==0 */ + if (group->session != session) + { + mali_bool activate_success; + MALI_DEBUG_PRINT(5, ("Mali group: Activate session: %08x previous: %08x on group 0x%08X. Ref: %d\n", session, group->session, group, 1+group->page_dir_ref_count)); + + activate_success = mali_mmu_activate_page_directory(group->mmu, mali_session_get_page_directory(session)); + MALI_DEBUG_ASSERT(activate_success); + if ( MALI_FALSE== activate_success ) return MALI_FALSE; + group->session = session; + retval = MALI_GROUP_ACTIVATE_PD_STATUS_OK_SWITCHED_PD; + } + else + { + MALI_DEBUG_PRINT(4, ("Mali group: Activate existing session 0x%08X on group 0x%08X. Ref: %d\n", session->page_directory, group, 1+group->page_dir_ref_count)); + retval = MALI_GROUP_ACTIVATE_PD_STATUS_OK_KEPT_PD; + } + } + + group->page_dir_ref_count++; + return retval; +} + +static void mali_group_deactivate_page_directory(struct mali_group *group, struct mali_session_data *session) +{ + MALI_ASSERT_GROUP_LOCKED(group); + + MALI_DEBUG_ASSERT(0 < group->page_dir_ref_count); + MALI_DEBUG_ASSERT(session == group->session); + + group->page_dir_ref_count--; + + /* As an optimization, the MMU still points to the group->session even if (0 == group->page_dir_ref_count), + and we do not call mali_mmu_activate_empty_page_directory(group->mmu); */ + MALI_DEBUG_ASSERT(0 <= group->page_dir_ref_count); +} + +void mali_group_remove_session_if_unused(struct mali_group *group, struct mali_session_data *session) +{ + MALI_ASSERT_GROUP_LOCKED(group); + + if (0 == group->page_dir_ref_count) + { + MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->gp_state); + MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->pp_state); + + if (group->session == session) + { + MALI_DEBUG_ASSERT(MALI_TRUE == group->power_is_on); + MALI_DEBUG_PRINT(3, ("Mali group: Deactivating unused session 0x%08X on group %08X\n", session, group)); + mali_mmu_activate_empty_page_directory(group->mmu); + group->session = NULL; + } + } +} + +void mali_group_power_on(void) +{ + int i; + for (i = 0; i < mali_global_num_groups; i++) + { + struct mali_group *group = mali_global_groups[i]; + mali_group_lock(group); + MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->gp_state); + MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->pp_state); + MALI_DEBUG_ASSERT_POINTER(group->cluster); + group->power_is_on = MALI_TRUE; + mali_cluster_power_is_enabled_set(group->cluster, MALI_TRUE); + mali_group_unlock(group); + } + MALI_DEBUG_PRINT(3,("group: POWER ON\n")); +} + +mali_bool mali_group_power_is_on(struct mali_group *group) +{ + MALI_ASSERT_GROUP_LOCKED(group); + return group->power_is_on; +} + +void mali_group_power_off(void) +{ + int i; + /* It is necessary to set group->session = NULL; so that the powered off MMU is not written to on map /unmap */ + /* It is necessary to set group->power_is_on=MALI_FALSE so that pending bottom_halves does not access powered off cores. */ + for (i = 0; i < mali_global_num_groups; i++) + { + struct mali_group *group = mali_global_groups[i]; + mali_group_lock(group); + MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->gp_state); + MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->pp_state); + MALI_DEBUG_ASSERT_POINTER(group->cluster); + group->session = NULL; + MALI_DEBUG_ASSERT(MALI_TRUE == group->power_is_on); + group->power_is_on = MALI_FALSE; + mali_cluster_power_is_enabled_set(group->cluster, MALI_FALSE); + mali_group_unlock(group); + } + MALI_DEBUG_PRINT(3,("group: POWER OFF\n")); +} + + +static void mali_group_recovery_reset(struct mali_group *group) +{ + MALI_ASSERT_GROUP_LOCKED(group); + + /* Stop cores, bus stop */ + if (NULL != group->pp_core) + { + mali_pp_stop_bus(group->pp_core); + } + if (NULL != group->gp_core) + { + mali_gp_stop_bus(group->gp_core); + } + + /* Flush MMU */ + mali_mmu_activate_fault_flush_page_directory(group->mmu); + mali_mmu_page_fault_done(group->mmu); + + /* Wait for cores to stop bus */ + if (NULL != group->pp_core) + { + mali_pp_stop_bus_wait(group->pp_core); + } + if (NULL != group->gp_core) + { + mali_gp_stop_bus_wait(group->gp_core); + } + + /* Reset cores */ + if (NULL != group->pp_core) + { + mali_pp_hard_reset(group->pp_core); + } + if (NULL != group->gp_core) + { + mali_gp_hard_reset(group->gp_core); + } + + /* Reset MMU */ + mali_mmu_reset(group->mmu); + group->session = NULL; +} + +/* Group lock need to be taken before calling mali_group_complete_jobs. Will release the lock here. */ +static void mali_group_complete_jobs(struct mali_group *group, mali_bool complete_gp, mali_bool complete_pp, bool success) +{ + mali_bool need_group_reset = MALI_FALSE; + mali_bool gp_success = success; + mali_bool pp_success = success; + + MALI_ASSERT_GROUP_LOCKED(group); + + if (complete_gp && !complete_pp) + { + MALI_DEBUG_ASSERT_POINTER(group->gp_core); + if (_MALI_OSK_ERR_OK == mali_gp_reset(group->gp_core)) + { + struct mali_gp_job *gp_job_to_return = group->gp_running_job; + group->gp_state = MALI_GROUP_CORE_STATE_IDLE; + group->gp_running_job = NULL; + + MALI_DEBUG_ASSERT_POINTER(gp_job_to_return); + + mali_group_deactivate_page_directory(group, mali_gp_job_get_session(gp_job_to_return)); + + if(mali_group_other_reschedule_needed(group)) + { + mali_group_unlock(group); + mali_pp_scheduler_do_schedule(); + } + else + { + mali_group_unlock(group); + } + + mali_gp_scheduler_job_done(group, gp_job_to_return, gp_success); + mali_pm_core_event(MALI_CORE_EVENT_GP_STOP); /* It is ok to do this after schedule, since START/STOP is simply ++ and -- anyways */ + + return; + } + else + { + need_group_reset = MALI_TRUE; + MALI_DEBUG_PRINT(3, ("Mali group: Failed to reset GP, need to reset entire group\n")); + pp_success = MALI_FALSE; /* This might kill PP as well, so this should fail */ + } + } + if (complete_pp && !complete_gp) + { + MALI_DEBUG_ASSERT_POINTER(group->pp_core); + if (_MALI_OSK_ERR_OK == mali_pp_reset(group->pp_core)) + { + struct mali_pp_job *pp_job_to_return = group->pp_running_job; + u32 pp_sub_job_to_return = group->pp_running_sub_job; + group->pp_state = MALI_GROUP_CORE_STATE_IDLE; + group->pp_running_job = NULL; + + MALI_DEBUG_ASSERT_POINTER(pp_job_to_return); + + mali_group_deactivate_page_directory(group, mali_pp_job_get_session(pp_job_to_return)); + + if(mali_group_other_reschedule_needed(group)) + { + mali_group_unlock(group); + mali_gp_scheduler_do_schedule(); + } + else + { + mali_group_unlock(group); + } + + mali_pp_scheduler_job_done(group, pp_job_to_return, pp_sub_job_to_return, pp_success); + mali_pm_core_event(MALI_CORE_EVENT_PP_STOP); /* It is ok to do this after schedule, since START/STOP is simply ++ and -- anyways */ + + return; + } + else + { + need_group_reset = MALI_TRUE; + MALI_DEBUG_PRINT(3, ("Mali group: Failed to reset PP, need to reset entire group\n")); + gp_success = MALI_FALSE; /* This might kill GP as well, so this should fail */ + } + } + else if (complete_gp && complete_pp) + { + need_group_reset = MALI_TRUE; + } + + if (MALI_TRUE == need_group_reset) + { + struct mali_gp_job *gp_job_to_return = group->gp_running_job; + struct mali_pp_job *pp_job_to_return = group->pp_running_job; + u32 pp_sub_job_to_return = group->pp_running_sub_job; + mali_bool schedule_other = MALI_FALSE; + + MALI_DEBUG_PRINT(3, ("Mali group: Resetting entire group\n")); + + group->gp_state = MALI_GROUP_CORE_STATE_IDLE; + group->gp_running_job = NULL; + if (NULL != gp_job_to_return) + { + mali_group_deactivate_page_directory(group, mali_gp_job_get_session(gp_job_to_return)); + } + + group->pp_state = MALI_GROUP_CORE_STATE_IDLE; + group->pp_running_job = NULL; + if (NULL != pp_job_to_return) + { + mali_group_deactivate_page_directory(group, mali_pp_job_get_session(pp_job_to_return)); + } + + /* The reset has to be done after mali_group_deactivate_page_directory() */ + mali_group_recovery_reset(group); + + if (mali_group_other_reschedule_needed(group) && (NULL == gp_job_to_return || NULL == pp_job_to_return)) + { + schedule_other = MALI_TRUE; + } + + mali_group_unlock(group); + + if (NULL != gp_job_to_return) + { + mali_gp_scheduler_job_done(group, gp_job_to_return, gp_success); + mali_pm_core_event(MALI_CORE_EVENT_GP_STOP); /* It is ok to do this after schedule, since START/STOP is simply ++ and -- anyways */ + } + else if (schedule_other) + { + mali_pp_scheduler_do_schedule(); + } + + if (NULL != pp_job_to_return) + { + mali_pp_scheduler_job_done(group, pp_job_to_return, pp_sub_job_to_return, pp_success); + mali_pm_core_event(MALI_CORE_EVENT_PP_STOP); /* It is ok to do this after schedule, since START/STOP is simply ++ and -- anyways */ + } + else if (schedule_other) + { + mali_gp_scheduler_do_schedule(); + } + + return; + } + + mali_group_unlock(group); +} + +#if MALI_STATE_TRACKING +u32 mali_group_dump_state(struct mali_group *group, char *buf, u32 size) +{ + int n = 0; + + n += _mali_osk_snprintf(buf + n, size - n, "Group: %p\n", group); + if (group->gp_core) + { + n += mali_gp_dump_state(group->gp_core, buf + n, size - n); + n += _mali_osk_snprintf(buf + n, size - n, "\tGP state: %d\n", group->gp_state); + n += _mali_osk_snprintf(buf + n, size - n, "\tGP job: %p\n", group->gp_running_job); + } + if (group->pp_core) + { + n += mali_pp_dump_state(group->pp_core, buf + n, size - n); + n += _mali_osk_snprintf(buf + n, size - n, "\tPP state: %d\n", group->pp_state); + n += _mali_osk_snprintf(buf + n, size - n, "\tPP job: %p, subjob %d \n", + group->pp_running_job, group->pp_running_sub_job); + } + + return n; +} +#endif diff --git a/drivers/media/video/samsung/mali/common/mali_group.h b/drivers/media/video/samsung/mali/common/mali_group.h new file mode 100644 index 0000000..3533d13 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_group.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MALI_GROUP_H__ +#define __MALI_GROUP_H__ + +#include "linux/jiffies.h" +#include "mali_osk.h" +#include "mali_cluster.h" +#include "mali_mmu.h" +#include "mali_gp.h" +#include "mali_pp.h" +#include "mali_session.h" + +/* max runtime [ms] for a core job - used by timeout timers */ +#define MAX_RUNTIME 5000 +/** @brief A mali group object represents a MMU and a PP and/or a GP core. + * + */ +#define MALI_MAX_NUMBER_OF_GROUPS 9 + +struct mali_group; + +enum mali_group_event_t +{ + GROUP_EVENT_PP_JOB_COMPLETED, /**< PP job completed successfully */ + GROUP_EVENT_PP_JOB_FAILED, /**< PP job completed with failure */ + GROUP_EVENT_PP_JOB_TIMED_OUT, /**< PP job reached max runtime */ + GROUP_EVENT_GP_JOB_COMPLETED, /**< GP job completed successfully */ + GROUP_EVENT_GP_JOB_FAILED, /**< GP job completed with failure */ + GROUP_EVENT_GP_JOB_TIMED_OUT, /**< GP job reached max runtime */ + GROUP_EVENT_GP_OOM, /**< GP job ran out of heap memory */ + GROUP_EVENT_MMU_PAGE_FAULT, /**< MMU page fault */ +}; + +enum mali_group_core_state +{ + MALI_GROUP_CORE_STATE_IDLE, + MALI_GROUP_CORE_STATE_WORKING, + MALI_GROUP_CORE_STATE_OOM +}; + +/** @brief Create a new Mali group object + * + * @param cluster Pointer to the cluster to which the group is connected. + * @param mmu Pointer to the MMU that defines this group + * @return A pointer to a new group object + */ +struct mali_group *mali_group_create(struct mali_cluster *cluster, struct mali_mmu_core *mmu); +void mali_group_add_gp_core(struct mali_group *group, struct mali_gp_core* gp_core); +void mali_group_add_pp_core(struct mali_group *group, struct mali_pp_core* pp_core); +void mali_group_delete(struct mali_group *group); + +/** @brief Reset group + * + * This function will reset the entire group, including all the cores present in the group. + * + * @param group Pointer to the group to reset + */ +void mali_group_reset(struct mali_group *group); + +/** @brief Get pointer to GP core object + */ +struct mali_gp_core* mali_group_get_gp_core(struct mali_group *group); + +/** @brief Get pointer to PP core object + */ +struct mali_pp_core* mali_group_get_pp_core(struct mali_group *group); + +/** @brief Lock group object + * + * Most group functions will lock the group object themselves. The expection is + * the group_bottom_half which requires the group to be locked on entry. + * + * @param group Pointer to group to lock + */ +void mali_group_lock(struct mali_group *group); + +/** @brief Unlock group object + * + * @param group Pointer to group to unlock + */ +void mali_group_unlock(struct mali_group *group); +#ifdef DEBUG +void mali_group_assert_locked(struct mali_group *group); +#define MALI_ASSERT_GROUP_LOCKED(group) mali_group_assert_locked(group) +#else +#define MALI_ASSERT_GROUP_LOCKED(group) +#endif + +/** @brief Start GP job + */ +_mali_osk_errcode_t mali_group_start_gp_job(struct mali_group *group, struct mali_gp_job *job); +/** @brief Start fragment of PP job + */ +_mali_osk_errcode_t mali_group_start_pp_job(struct mali_group *group, struct mali_pp_job *job, u32 sub_job); + +/** @brief Resume GP job that suspended waiting for more heap memory + */ +void mali_group_resume_gp_with_new_heap(struct mali_group *group, u32 job_id, u32 start_addr, u32 end_addr); +/** @brief Abort GP job + * + * Used to abort suspended OOM jobs when user space failed to allocte more memory. + */ +void mali_group_abort_gp_job(struct mali_group *group, u32 job_id); +/** @brief Abort all GP jobs from \a session + * + * Used on session close when terminating all running and queued jobs from \a session. + */ +void mali_group_abort_session(struct mali_group *group, struct mali_session_data *session); + +enum mali_group_core_state mali_group_gp_state(struct mali_group *group); +enum mali_group_core_state mali_group_pp_state(struct mali_group *group); + +/** @brief The common group bottom half interrupt handler + * + * This is only called from the GP and PP bottom halves. + * + * The action taken is dictated by the \a event. + * + * @param event The event code + */ +void mali_group_bottom_half(struct mali_group *group, enum mali_group_event_t event); + +struct mali_mmu_core *mali_group_get_mmu(struct mali_group *group); +struct mali_session_data *mali_group_get_session(struct mali_group *group); + +void mali_group_remove_session_if_unused(struct mali_group *group, struct mali_session_data *session_data); + +void mali_group_power_on(void); +void mali_group_power_off(void); +mali_bool mali_group_power_is_on(struct mali_group *group); + +struct mali_group *mali_group_get_glob_group(u32 index); +u32 mali_group_get_glob_num_groups(void); + +u32 mali_group_dump_state(struct mali_group *group, char *buf, u32 size); + +#endif /* __MALI_GROUP_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_hw_core.c b/drivers/media/video/samsung/mali/common/mali_hw_core.c new file mode 100644 index 0000000..0b08622 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_hw_core.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mali_hw_core.h" +#include "mali_osk.h" +#include "mali_kernel_common.h" + +_mali_osk_errcode_t mali_hw_core_create(struct mali_hw_core *core, const _mali_osk_resource_t *resource, u32 reg_size) +{ + core->phys_addr = resource->base; + core->description = resource->description; + core->size = reg_size; + if (_MALI_OSK_ERR_OK == _mali_osk_mem_reqregion(core->phys_addr, core->size, core->description)) + { + core->mapped_registers = _mali_osk_mem_mapioregion(core->phys_addr, core->size, core->description); + if (NULL != core->mapped_registers) + { + return _MALI_OSK_ERR_OK; + } + else + { + MALI_PRINT_ERROR(("Failed to map memory region for core %s at phys_addr 0x%08X\n", core->description, core->phys_addr)); + } + _mali_osk_mem_unreqregion(core->phys_addr, core->size); + } + else + { + MALI_PRINT_ERROR(("Failed to request memory region for core %s at phys_addr 0x%08X\n", core->description, core->phys_addr)); + } + + return _MALI_OSK_ERR_FAULT; +} + +void mali_hw_core_delete(struct mali_hw_core *core) +{ + _mali_osk_mem_unmapioregion(core->phys_addr, core->size, core->mapped_registers); + core->mapped_registers = NULL; + _mali_osk_mem_unreqregion(core->phys_addr, core->size); +} diff --git a/drivers/media/video/samsung/mali/common/mali_hw_core.h b/drivers/media/video/samsung/mali/common/mali_hw_core.h new file mode 100644 index 0000000..c797804 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_hw_core.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MALI_HW_CORE_H__ +#define __MALI_HW_CORE_H__ + +#include "mali_osk.h" +#include "mali_kernel_common.h" + +/** + * The common parts for all Mali HW cores (GP, PP, MMU, L2 and PMU) + * This struct is embedded inside all core specific structs. + */ +struct mali_hw_core +{ + u32 phys_addr; /**< Physical address of the registers */ + u32 size; /**< Size of registers */ + mali_io_address mapped_registers; /**< Virtual mapping of the registers */ + const char* description; /**< Name of unit (as specified in device configuration) */ +}; + +#define MALI_HW_CORE_NO_COUNTER ((u32)-1) +#define MALI_HW_CORE_INVALID_VALUE ((u32)-1) + +_mali_osk_errcode_t mali_hw_core_create(struct mali_hw_core *core, const _mali_osk_resource_t *resource, u32 reg_size); +void mali_hw_core_delete(struct mali_hw_core *core); + +MALI_STATIC_INLINE u32 mali_hw_core_register_read(struct mali_hw_core *core, u32 relative_address) +{ + u32 read_val; + read_val = _mali_osk_mem_ioread32(core->mapped_registers, relative_address); + MALI_DEBUG_PRINT(6, ("register_read for core %s, relative addr=0x%04X, val=0x%08X\n", + core->description, relative_address, read_val)); + return read_val; +} + +MALI_STATIC_INLINE void mali_hw_core_register_write_relaxed(struct mali_hw_core *core, u32 relative_address, u32 new_val) +{ + MALI_DEBUG_PRINT(6, ("register_write_relaxed for core %s, relative addr=0x%04X, val=0x%08X\n", + core->description, relative_address, new_val)); + _mali_osk_mem_iowrite32_relaxed(core->mapped_registers, relative_address, new_val); +} + +MALI_STATIC_INLINE void mali_hw_core_register_write(struct mali_hw_core *core, u32 relative_address, u32 new_val) +{ + MALI_DEBUG_PRINT(6, ("register_write for core %s, relative addr=0x%04X, val=0x%08X\n", + core->description, relative_address, new_val)); + _mali_osk_mem_iowrite32(core->mapped_registers, relative_address, new_val); +} + +MALI_STATIC_INLINE void mali_hw_core_register_write_array_relaxed(struct mali_hw_core *core, u32 relative_address, u32 *write_array, u32 nr_of_regs) +{ + u32 i; + MALI_DEBUG_PRINT(6, ("register_write_array: for core %s, relative addr=0x%04X, nr of regs=%u\n", + core->description,relative_address, nr_of_regs)); + + /* Do not use burst writes against the registers */ + for (i = 0; i< nr_of_regs; i++) + { + mali_hw_core_register_write_relaxed(core, relative_address + i*4, write_array[i]); + } +} + +#endif /* __MALI_HW_CORE_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_GP2.c b/drivers/media/video/samsung/mali/common/mali_kernel_GP2.c deleted file mode 100644 index cfd70f4..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_GP2.c +++ /dev/null @@ -1,1493 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -//added for SPI -#include <linux/kernel.h> - -#include "mali_kernel_common.h" -#include "mali_kernel_core.h" -#include "mali_kernel_subsystem.h" -#include "regs/mali_gp_regs.h" -#include "mali_kernel_rendercore.h" -#include "mali_osk.h" -#include "mali_osk_list.h" -#if MALI_TIMELINE_PROFILING_ENABLED -#include "mali_kernel_profiling.h" -#endif -#if defined(USING_MALI400_L2_CACHE) -#include "mali_kernel_l2_cache.h" -#endif -#if USING_MMU -#include "mali_kernel_mem_mmu.h" /* Needed for mali_kernel_mmu_force_bus_reset() */ -#endif - -#if defined(USING_MALI200) -#define MALI_GP_SUBSYSTEM_NAME "MaliGP2" -#define MALI_GP_CORE_TYPE _MALI_GP2 -#elif defined(USING_MALI400) -#define MALI_GP_SUBSYSTEM_NAME "Mali-400 GP" -#define MALI_GP_CORE_TYPE _MALI_400_GP -#else -#error "No supported mali core defined" -#endif - -#define GET_JOB_EMBEDDED_PTR(job) (&((job)->embedded_core_job)) -#define GET_JOBGP2_PTR(job_extern) _MALI_OSK_CONTAINER_OF(job_extern, maligp_job, embedded_core_job) - -/* Initialized when this subsystem is initialized. This is determined by the - * position in subsystems[], and so the value used to initialize this is - * determined at compile time */ -static mali_kernel_subsystem_identifier mali_subsystem_gp_id = -1; - -static mali_core_renderunit * last_gp_core_cookie = NULL; - -/* Describing a maligp job settings */ -typedef struct maligp_job -{ - /* The general job struct common for all mali cores */ - mali_core_job embedded_core_job; - _mali_uk_gp_start_job_s user_input; - - u32 irq_status; - u32 status_reg_on_stop; - u32 perf_counter0; - u32 perf_counter1; - u32 vscl_stop_addr; - u32 plbcl_stop_addr; - u32 heap_current_addr; - - /* The data we will return back to the user */ - _mali_osk_notification_t *notification_obj; - - int is_stalled_waiting_for_more_memory; - - u32 active_mask; - /* progress checking */ - u32 last_vscl; - u32 last_plbcl; - /* extended progress checking, only enabled when we can use one of the performance counters */ - u32 have_extended_progress_checking; - u32 vertices; - -#if defined(USING_MALI400_L2_CACHE) - u32 perf_counter_l2_src0; - u32 perf_counter_l2_src1; - u32 perf_counter_l2_val0; - u32 perf_counter_l2_val1; -#endif - -#if MALI_TIMELINE_PROFILING_ENABLED - u32 pid; - u32 tid; -#endif -} maligp_job; - -/*Functions Exposed to the General External System through - function pointers.*/ - -static _mali_osk_errcode_t maligp_subsystem_startup(mali_kernel_subsystem_identifier id); -#if USING_MMU -static _mali_osk_errcode_t maligp_subsystem_mmu_connect(mali_kernel_subsystem_identifier id); -#endif -static void maligp_subsystem_terminate(mali_kernel_subsystem_identifier id); -static _mali_osk_errcode_t maligp_subsystem_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue); -static void maligp_subsystem_session_end(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot); -static _mali_osk_errcode_t maligp_subsystem_core_system_info_fill(_mali_system_info* info); -static _mali_osk_errcode_t maligp_renderunit_create(_mali_osk_resource_t * resource); -#if USING_MMU -static void maligp_subsystem_broadcast_notification(mali_core_notification_message message, u32 data); -#endif -#if MALI_STATE_TRACKING -u32 maligp_subsystem_dump_state(char *buf, u32 size); -#endif - -/* Internal support functions */ -static _mali_osk_errcode_t maligp_core_version_legal( mali_core_renderunit *core ); -static void maligp_raw_reset( mali_core_renderunit *core); -static void maligp_reset_hard(struct mali_core_renderunit * core); -static void maligp_reset(mali_core_renderunit *core); -static void maligp_initialize_registers_mgmt(mali_core_renderunit *core ); - -#ifdef DEBUG -static void maligp_print_regs(int debug_level, mali_core_renderunit *core); -#endif - -/* Functions exposed to mali_core system through functionpointers - in the subsystem struct. */ -static _mali_osk_errcode_t subsystem_maligp_start_job(mali_core_job * job, mali_core_renderunit * core); -static u32 subsystem_maligp_irq_handler_upper_half(mali_core_renderunit * core); -static int subsystem_maligp_irq_handler_bottom_half(mali_core_renderunit* core); -static _mali_osk_errcode_t subsystem_maligp_get_new_job_from_user(struct mali_core_session * session, void * argument); -static _mali_osk_errcode_t subsystem_maligp_suspend_response(struct mali_core_session * session, void * argument); -static void subsystem_maligp_return_job_to_user(mali_core_job * job, mali_subsystem_job_end_code end_status); -static void subsystem_maligp_renderunit_delete(mali_core_renderunit * core); -static void subsystem_maligp_renderunit_reset_core(struct mali_core_renderunit * core, mali_core_reset_style style ); -static void subsystem_maligp_renderunit_probe_core_irq_trigger(struct mali_core_renderunit* core); -static _mali_osk_errcode_t subsystem_maligp_renderunit_probe_core_irq_finished(struct mali_core_renderunit* core); -static void subsystem_maligp_renderunit_stop_bus(struct mali_core_renderunit* core); - -/* Variables */ -static register_address_and_value default_mgmt_regs[] = -{ - { MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED } -}; - - -/* This will be one of the subsystems in the array of subsystems: - static struct mali_kernel_subsystem * subsystems[]; - found in file: mali_kernel_core.c -*/ - -struct mali_kernel_subsystem mali_subsystem_gp2= -{ - maligp_subsystem_startup, /* startup */ - NULL, /*maligp_subsystem_terminate,*/ /* shutdown */ -#if USING_MMU - maligp_subsystem_mmu_connect, /* load_complete */ -#else - NULL, -#endif - maligp_subsystem_core_system_info_fill, /* system_info_fill */ - maligp_subsystem_session_begin, /* session_begin */ - maligp_subsystem_session_end, /* session_end */ -#if USING_MMU - maligp_subsystem_broadcast_notification, /* broadcast_notification */ -#else - NULL, -#endif -#if MALI_STATE_TRACKING - maligp_subsystem_dump_state, /* dump_state */ -#endif -} ; - -static mali_core_subsystem subsystem_maligp ; - -static _mali_osk_errcode_t maligp_subsystem_startup(mali_kernel_subsystem_identifier id) -{ - mali_core_subsystem * subsystem; - - MALI_DEBUG_PRINT(3, ("Mali GP: maligp_subsystem_startup\n") ) ; - - mali_subsystem_gp_id = id; - - /* All values get 0 as default */ - _mali_osk_memset(&subsystem_maligp, 0, sizeof(*subsystem)); - - subsystem = &subsystem_maligp; - subsystem->start_job = &subsystem_maligp_start_job; - subsystem->irq_handler_upper_half = &subsystem_maligp_irq_handler_upper_half; - subsystem->irq_handler_bottom_half = &subsystem_maligp_irq_handler_bottom_half; - subsystem->get_new_job_from_user = &subsystem_maligp_get_new_job_from_user; - subsystem->suspend_response = &subsystem_maligp_suspend_response; - subsystem->return_job_to_user = &subsystem_maligp_return_job_to_user; - subsystem->renderunit_delete = &subsystem_maligp_renderunit_delete; - subsystem->reset_core = &subsystem_maligp_renderunit_reset_core; - subsystem->stop_bus = &subsystem_maligp_renderunit_stop_bus; - subsystem->probe_core_irq_trigger = &subsystem_maligp_renderunit_probe_core_irq_trigger; - subsystem->probe_core_irq_acknowledge = &subsystem_maligp_renderunit_probe_core_irq_finished; - - /* Setting variables in the general core part of the subsystem.*/ - subsystem->name = MALI_GP_SUBSYSTEM_NAME; - subsystem->core_type = MALI_GP_CORE_TYPE; - subsystem->id = id; - - /* Initiates the rest of the general core part of the subsystem */ - MALI_CHECK_NO_ERROR(mali_core_subsystem_init( subsystem )); - - /* This will register the function for adding MALIGP2 cores to the subsystem */ -#if defined(USING_MALI200) - MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(MALIGP2, maligp_renderunit_create)); -#endif -#if defined(USING_MALI400) - MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(MALI400GP, maligp_renderunit_create)); -#endif - - MALI_DEBUG_PRINT(6, ("Mali GP: maligp_subsystem_startup\n") ) ; - - MALI_SUCCESS; -} - -#if USING_MMU -static _mali_osk_errcode_t maligp_subsystem_mmu_connect(mali_kernel_subsystem_identifier id) -{ - mali_core_subsystem_attach_mmu(&subsystem_maligp); - MALI_SUCCESS; /* OK */ -} -#endif - -static void maligp_subsystem_terminate(mali_kernel_subsystem_identifier id) -{ - MALI_DEBUG_PRINT(3, ("Mali GP: maligp_subsystem_terminate\n") ) ; - mali_core_subsystem_cleanup(&subsystem_maligp); -} - -static _mali_osk_errcode_t maligp_subsystem_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue) -{ - mali_core_session * session; - - MALI_DEBUG_PRINT(3, ("Mali GP: maligp_subsystem_session_begin\n") ) ; - MALI_CHECK_NON_NULL(session = _mali_osk_malloc( sizeof(*session) ), _MALI_OSK_ERR_FAULT); - - _mali_osk_memset(session, 0, sizeof(*session) ); - *slot = (mali_kernel_subsystem_session_slot)session; - - session->subsystem = &subsystem_maligp; - - session->notification_queue = queue; - -#if USING_MMU - session->mmu_session = mali_session_data; -#endif - - mali_core_session_begin(session); - - MALI_DEBUG_PRINT(6, ("Mali GP: maligp_subsystem_session_begin\n") ) ; - - MALI_SUCCESS; -} - -static void maligp_subsystem_session_end(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot) -{ - mali_core_session * session; - /** @note mali_session_data not needed here */ - - MALI_DEBUG_PRINT(3, ("Mali GP: maligp_subsystem_session_end\n") ) ; - if ( NULL==slot || NULL==*slot) - { - MALI_PRINT_ERROR(("Input slot==NULL")); - return; - } - session = (mali_core_session *)*slot; - mali_core_session_close(session); - - _mali_osk_free(session); - *slot = NULL; - - MALI_DEBUG_PRINT(6, ("Mali GP: maligp_subsystem_session_end\n") ) ; -} - -/** - * We fill in info about all the cores we have - * @param info Pointer to system info struct to update - * @return _MALI_OSK_ERR_OK on success, or another _mali_osk_errcode_t for errors. - */ -static _mali_osk_errcode_t maligp_subsystem_core_system_info_fill(_mali_system_info* info) -{ - return mali_core_subsystem_system_info_fill(&subsystem_maligp, info); -} - -static _mali_osk_errcode_t maligp_renderunit_create(_mali_osk_resource_t * resource) -{ - mali_core_renderunit *core; - int err; - - MALI_DEBUG_PRINT(3, ("Mali GP: maligp_renderunit_create\n") ) ; - /* Checking that the resource settings are correct */ -#if defined(USING_MALI200) - if(MALIGP2 != resource->type) - { - MALI_PRINT_ERROR(("Can not register this resource as a " MALI_GP_SUBSYSTEM_NAME " core.")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } -#elif defined(USING_MALI400) - if(MALI400GP != resource->type) - { - MALI_PRINT_ERROR(("Can not register this resource as a " MALI_GP_SUBSYSTEM_NAME " core.")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } -#endif - if ( 0 != resource->size ) - { - MALI_PRINT_ERROR(("Memory size set to " MALI_GP_SUBSYSTEM_NAME " core should be zero.")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - if ( NULL == resource->description ) - { - MALI_PRINT_ERROR(("A " MALI_GP_SUBSYSTEM_NAME " core needs a unique description field")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* Create a new core object */ - core = (mali_core_renderunit*) _mali_osk_malloc(sizeof(*core)); - if ( NULL == core ) - { - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* Variables set to be able to open and register the core */ - core->subsystem = &subsystem_maligp ; - core->registers_base_addr = resource->base ; - core->size = MALIGP2_REGISTER_ADDRESS_SPACE_SIZE ; - core->description = resource->description; - core->irq_nr = resource->irq ; -#if USING_MMU - core->mmu_id = resource->mmu_id; - core->mmu = NULL; -#endif -#if USING_MALI_PMM - /* Set up core's PMM id */ - core->pmm_id = MALI_PMM_CORE_GP; -#endif - - err = mali_core_renderunit_init( core ); - if (_MALI_OSK_ERR_OK != err) - { - MALI_DEBUG_PRINT(1, ("Failed to initialize renderunit\n")); - goto exit_on_error0; - } - - /* Map the new core object, setting: core->registers_mapped */ - err = mali_core_renderunit_map_registers(core); - if (_MALI_OSK_ERR_OK != err) goto exit_on_error1; - - /* Check that the register mapping of the core works. - Return 0 if maligp core is present and accessible. */ - if (mali_benchmark) { - core->core_version = MALI_GP_PRODUCT_ID << 16; - } else { - core->core_version = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_VERSION); - } - - err = maligp_core_version_legal(core); - if (_MALI_OSK_ERR_OK != err) goto exit_on_error2; - - /* Reset the core. Put the core into a state where it can start to render. */ - maligp_reset(core); - - /* Registering IRQ, init the work_queue_irq_handle */ - /* Adding this core as an available renderunit in the subsystem. */ - err = mali_core_subsystem_register_renderunit(&subsystem_maligp, core); - if (_MALI_OSK_ERR_OK != err) goto exit_on_error2; - -#ifdef DEBUG - MALI_DEBUG_PRINT(4, ("Mali GP: Initial Register settings:\n")); - maligp_print_regs(4, core); -#endif - - MALI_DEBUG_PRINT(6, ("Mali GP: maligp_renderunit_create\n") ) ; - - MALI_SUCCESS; - -exit_on_error2: - mali_core_renderunit_unmap_registers(core); -exit_on_error1: - mali_core_renderunit_term(core); -exit_on_error0: - _mali_osk_free( core ) ; - MALI_PRINT_ERROR(("Renderunit NOT created.")); - MALI_ERROR((_mali_osk_errcode_t)err); -} - -#if USING_MMU -/* Used currently only for signalling when MMU has a pagefault */ -static void maligp_subsystem_broadcast_notification(mali_core_notification_message message, u32 data) -{ - mali_core_subsystem_broadcast_notification(&subsystem_maligp, message, data); -} -#endif - -#ifdef DEBUG -static void maligp_print_regs(int debug_level, mali_core_renderunit *core) -{ - if (debug_level <= mali_debug_level) - { - MALI_DEBUG_PRINT(1, (" VS 0x%08X 0x%08X, PLBU 0x%08X 0x%08X ALLOC 0x%08X 0x%08X\n", - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_VSCL_START_ADDR), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_VSCL_END_ADDR), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBUCL_START_ADDR), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBUCL_END_ADDR), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_END_ADDR)) - ); - MALI_DEBUG_PRINT(1, (" IntRaw 0x%08X IntMask 0x%08X, Status 0x%02X Ver: 0x%08X \n", - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_INT_MASK), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_STATUS), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_VERSION))); - - MALI_DEBUG_PRINT(1, (" PERF_CNT Enbl:%d %d Src: %02d %02d VAL: 0x%08X 0x%08X\n", - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_ENABLE), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_ENABLE), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_SRC), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_SRC), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_VALUE), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE))); - - MALI_DEBUG_PRINT(1, (" VS_START 0x%08X PLBU_START 0x%08X AXI_ERR 0x%08X\n", - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_VSCL_START_ADDR_READ), - mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBCL_START_ADDR_READ), - mali_core_renderunit_register_read(core, MALIGP2_CONTR_AXI_BUS_ERROR_STAT))); - } -} -#endif - -static _mali_osk_errcode_t maligp_core_version_legal( mali_core_renderunit *core ) -{ - u32 mali_type; - - mali_type = core->core_version >> 16; - -#if defined(USING_MALI400) - if ( MALI400_GP_PRODUCT_ID != mali_type && MALI300_GP_PRODUCT_ID != mali_type ) -#else - if ( MALI_GP_PRODUCT_ID != mali_type ) -#endif - { - MALI_PRINT_ERROR(("Error: reading this from maligp version register: 0x%x\n", core->core_version)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - MALI_DEBUG_PRINT(3, ("Mali GP: core_version_legal: Reads correct mali version: %d\n", core->core_version )) ; - MALI_SUCCESS; -} - -static void subsystem_maligp_renderunit_stop_bus(struct mali_core_renderunit* core) -{ - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_STOP_BUS); -} - -static void maligp_reset( mali_core_renderunit *core ) -{ - if (!mali_benchmark) { - maligp_raw_reset(core); - maligp_initialize_registers_mgmt(core); - } -} - - -static void maligp_reset_hard( mali_core_renderunit *core ) -{ - const int reset_finished_loop_count = 15; - const u32 reset_wait_target_register = MALIGP2_REG_ADDR_MGMT_WRITE_BOUND_LOW; - const u32 reset_invalid_value = 0xC0FFE000; - const u32 reset_check_value = 0xC01A0000; - const u32 reset_default_value = 0; - int i; - - mali_core_renderunit_register_write(core, reset_wait_target_register, reset_invalid_value); - - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_RESET); - - for (i = 0; i < reset_finished_loop_count; i++) - { - mali_core_renderunit_register_write(core, reset_wait_target_register, reset_check_value); - if (reset_check_value == mali_core_renderunit_register_read(core, reset_wait_target_register)) - { - MALI_DEBUG_PRINT(5, ("Reset loop exiting after %d iterations\n", i)); - break; - } - } - - if (i == reset_finished_loop_count) - { - MALI_DEBUG_PRINT(1, ("The reset loop didn't work\n")); - } - - mali_core_renderunit_register_write(core, reset_wait_target_register, reset_default_value); /* set it back to the default */ - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_MASK_ALL); - - -} - -static void maligp_raw_reset( mali_core_renderunit *core ) -{ - int i; - const int request_loop_count = 20; - - MALI_DEBUG_PRINT(4, ("Mali GP: maligp_raw_reset: %s\n", core->description)) ; - if (mali_benchmark) return; - - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_MASK, 0); /* disable the IRQs */ - -#if defined(USING_MALI200) - - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_STOP_BUS); - - for (i = 0; i < request_loop_count; i++) - { - if (mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_STATUS) & MALIGP2_REG_VAL_STATUS_BUS_STOPPED) break; - _mali_osk_time_ubusydelay(10); - } - - MALI_DEBUG_PRINT_IF(1, request_loop_count == i, ("Mali GP: Bus was never stopped during core reset\n")); - - if (request_loop_count==i) - { - /* Could not stop bus connections from core, probably because some of the already pending - bus request has had a page fault, and therefore can not complete before the MMU does PageFault - handling. This can be treated as a heavier reset function - which unfortunately reset all - the cores on this MMU in addition to the MMU itself */ -#if USING_MMU - if ((NULL!=core->mmu) && (MALI_FALSE == core->error_recovery)) - { - MALI_DEBUG_PRINT(1, ("Mali GP: Forcing MMU bus reset\n")); - mali_kernel_mmu_force_bus_reset(core->mmu); - return; - } -#endif - MALI_PRINT(("A MMU reset did not allow GP to stop its bus, system failure, unable to recover\n")); - return; - } - - /* the bus was stopped OK, complete the reset */ - /* use the hard reset routine to do the actual reset */ - maligp_reset_hard(core); - -#elif defined(USING_MALI400) - - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALI400GP_REG_VAL_IRQ_RESET_COMPLETED); - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_CMD, MALI400GP_REG_VAL_CMD_SOFT_RESET); - - for (i = 0; i < request_loop_count; i++) - { - if (mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT) & /*Bitwise OR*/ - MALI400GP_REG_VAL_IRQ_RESET_COMPLETED) break; - _mali_osk_time_ubusydelay(10); - } - - if ( request_loop_count==i ) - { -#if USING_MMU - /* Could not stop bus connections from core, probably because some of the already pending - bus request has had a page fault, and therefore can not complete before the MMU does PageFault - handling. This can be treated as a heavier reset function - which unfortunately reset all - the cores on this MMU in addition to the MMU itself */ - if ((NULL!=core->mmu) && (MALI_FALSE == core->error_recovery)) - { - MALI_DEBUG_PRINT(1, ("Mali GP: Forcing Bus reset\n")); - mali_kernel_mmu_force_bus_reset(core->mmu); - return; - } -#endif - MALI_PRINT(("A MMU reset did not allow GP to stop its bus, system failure, unable to recover\n")); - } - else - { - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_MASK_ALL); - } - -#else -#error "no supported mali core defined" -#endif -} - -/* Sets the registers on maligp according to the const default_mgmt_regs array. */ -static void maligp_initialize_registers_mgmt(mali_core_renderunit *core ) -{ - int i; - - MALI_DEBUG_PRINT(6, ("Mali GP: maligp_initialize_registers_mgmt: %s\n", core->description)) ; - for(i=0 ; i< (sizeof(default_mgmt_regs)/sizeof(*default_mgmt_regs)) ; ++i) - { - mali_core_renderunit_register_write_relaxed(core, default_mgmt_regs[i].address, default_mgmt_regs[i].value); - } - _mali_osk_write_mem_barrier(); -} - - -/* Start this job on this core. Return MALI_TRUE if the job was started. */ -static _mali_osk_errcode_t subsystem_maligp_start_job(mali_core_job * job, mali_core_renderunit * core) -{ - maligp_job *jobgp; - u32 startcmd; - /* The local extended version of the general structs */ - jobgp = _MALI_OSK_CONTAINER_OF(job, maligp_job, embedded_core_job); - - startcmd = 0; - if ( jobgp->user_input.frame_registers[0] != jobgp->user_input.frame_registers[1] ) - { - startcmd |= (u32) MALIGP2_REG_VAL_CMD_START_VS; - } - - if ( jobgp->user_input.frame_registers[2] != jobgp->user_input.frame_registers[3] ) - { - startcmd |= (u32) MALIGP2_REG_VAL_CMD_START_PLBU; - } - - if(0 == startcmd) - { - MALI_DEBUG_PRINT(4, ("Mali GP: Job: 0x%08x WILL NOT START SINCE JOB HAS ILLEGAL ADDRESSES\n", - (u32)jobgp->user_input.user_job_ptr)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - -#ifdef DEBUG - MALI_DEBUG_PRINT(4, ("Mali GP: Registers Start\n")); - maligp_print_regs(4, core); -#endif - - - mali_core_renderunit_register_write_array( - core, - MALIGP2_REG_ADDR_MGMT_VSCL_START_ADDR, - &(jobgp->user_input.frame_registers[0]), - sizeof(jobgp->user_input.frame_registers)/sizeof(jobgp->user_input.frame_registers[0])); - -#if MALI_TRACEPOINTS_ENABLED - jobgp->user_input.perf_counter_flag = 0; - - if( counter_table[7] != 0xFFFFFFFF ) { - jobgp->user_input.perf_counter_flag |= _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE; - jobgp->user_input.perf_counter_src0 = counter_table[7]; - } - if( counter_table[8] != 0xFFFFFFFF ) { - jobgp->user_input.perf_counter_flag |= _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE; - jobgp->user_input.perf_counter_src1 = counter_table[8]; - } -#endif - - /* This selects which performance counters we are reading */ - if ( 0 != jobgp->user_input.perf_counter_flag ) - { - if ( jobgp->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE) - { - mali_core_renderunit_register_write_relaxed( - core, - MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_SRC, - jobgp->user_input.perf_counter_src0); - - mali_core_renderunit_register_write_relaxed( - core, - MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_ENABLE, - MALIGP2_REG_VAL_PERF_CNT_ENABLE); - } - - if ( jobgp->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE) - { - mali_core_renderunit_register_write_relaxed( - core, - MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_SRC, - jobgp->user_input.perf_counter_src1); - - mali_core_renderunit_register_write_relaxed( - core, - MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_ENABLE, - MALIGP2_REG_VAL_PERF_CNT_ENABLE); - } - -#if defined(USING_MALI400_L2_CACHE) - if ( jobgp->user_input.perf_counter_flag & (_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE|_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE) ) - { - int force_reset = ( jobgp->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_L2_RESET ) ? 1 : 0; - u32 src0 = 0; - u32 src1 = 0; - - if ( jobgp->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE ) - { - src0 = jobgp->user_input.perf_counter_l2_src0; - } - if ( jobgp->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE ) - { - src1 = jobgp->user_input.perf_counter_l2_src1; - } - - mali_kernel_l2_cache_set_perf_counters(src0, src1, force_reset); /* will activate and possibly reset counters */ - - /* Now, retrieve the current values, so we can substract them when the job has completed */ - mali_kernel_l2_cache_get_perf_counters(&jobgp->perf_counter_l2_src0, - &jobgp->perf_counter_l2_val0, - &jobgp->perf_counter_l2_src1, - &jobgp->perf_counter_l2_val1); - } -#endif - } - - if ( 0 == (jobgp->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE)) - { - /* extended progress checking can be enabled */ - - jobgp->have_extended_progress_checking = 1; - - mali_core_renderunit_register_write_relaxed( - core, - MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_SRC, - MALIGP2_REG_VAL_PERF_CNT1_SRC_NUMBER_OF_VERTICES_PROCESSED - ); - - mali_core_renderunit_register_write_relaxed( - core, - MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_ENABLE, - MALIGP2_REG_VAL_PERF_CNT_ENABLE); - } - - subsystem_flush_mapped_mem_cache(); - - MALI_DEBUG_PRINT(4, ("Mali GP: STARTING GP WITH CMD: 0x%x\n", startcmd)); -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&job->session->jobs_started); -#endif - - /* This is the command that starts the Core */ - mali_core_renderunit_register_write(core, - MALIGP2_REG_ADDR_MGMT_CMD, - startcmd); - _mali_osk_write_mem_barrier(); - - pr_debug("SPI_GPU_GP Start\n"); -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE | MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(core->core_number) | MALI_PROFILING_EVENT_REASON_SINGLE_HW_FLUSH, - jobgp->user_input.frame_builder_id, jobgp->user_input.flush_id, 0, 0, 0); - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_START|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(core->core_number), jobgp->pid, jobgp->tid, 0, 0, 0); -#endif - - MALI_SUCCESS; -} - -/* Check if given core has an interrupt pending. Return MALI_TRUE and set mask to 0 if pending */ - -static u32 subsystem_maligp_irq_handler_upper_half(mali_core_renderunit * core) -{ - u32 irq_readout; - - if (mali_benchmark) { - return (core->current_job ? 1 : 0); /* simulate irq is pending when a job is pending */ - } - - irq_readout = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_INT_STAT); - - MALI_DEBUG_PRINT(5, ("Mali GP: IRQ: %04x\n", irq_readout)) ; - - if ( MALIGP2_REG_VAL_IRQ_MASK_NONE != irq_readout ) - { - /* Mask out all IRQs from this core until IRQ is handled */ - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_NONE); - -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(core->core_number)|MALI_PROFILING_EVENT_REASON_SINGLE_HW_INTERRUPT, irq_readout, 0, 0, 0, 0); -#endif - - /* We do need to handle this in a bottom half, return 1 */ - return 1; - } - return 0; -} - -/* This function should check if the interrupt indicates that job was finished. -If so it should update the job-struct, reset the core registers, and return MALI_TRUE, . -If the job is still working after this function it should return MALI_FALSE. -The function must also enable the bits in the interrupt mask for the core. -Called by the bottom half interrupt function. */ -static int subsystem_maligp_irq_handler_bottom_half(mali_core_renderunit* core) -{ - mali_core_job * job; - maligp_job * jobgp; - u32 irq_readout; - u32 core_status; - u32 vscl; - u32 plbcl; - - job = core->current_job; - - if (mali_benchmark) { - MALI_DEBUG_PRINT(3, ("MaliGP: Job: Benchmark\n") ); - irq_readout = MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST | MALIGP2_REG_VAL_IRQ_PLBU_END_CMD_LST; - core_status = 0; - } else { - irq_readout = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT) & MALIGP2_REG_VAL_IRQ_MASK_USED; - core_status = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_STATUS); - } - - if (NULL == job) - { - MALI_DEBUG_ASSERT(CORE_IDLE==core->state); - if ( 0 != irq_readout ) - { - MALI_PRINT_ERROR(("Interrupt from a core not running a job. IRQ: 0x%04x Status: 0x%04x", irq_readout, core_status)); - } - return JOB_STATUS_END_UNKNOWN_ERR; - } - MALI_DEBUG_ASSERT(CORE_IDLE!=core->state); - - jobgp = GET_JOBGP2_PTR(job); - - jobgp->heap_current_addr = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR); - - vscl = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_VSCL_START_ADDR); - plbcl = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBUCL_START_ADDR); - - MALI_DEBUG_PRINT(3, ("Mali GP: Job: 0x%08x IRQ RECEIVED Rawstat: 0x%x Status: 0x%x\n", - (u32)jobgp->user_input.user_job_ptr, irq_readout , core_status )) ; - - jobgp->irq_status |= irq_readout; - jobgp->status_reg_on_stop = core_status; - - if ( 0 != jobgp->is_stalled_waiting_for_more_memory ) - { - /* Readback the performance counters */ - if (jobgp->user_input.perf_counter_flag & (_MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE|_MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE) ) - { - jobgp->perf_counter0 = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_VALUE); - jobgp->perf_counter1 = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE); - -#if MALI_TRACEPOINTS_ENABLED - //TODO magic numbers should come from mali_linux_trace.h instead - _mali_profiling_add_counter(7, jobgp->perf_counter0); - _mali_profiling_add_counter(8, jobgp->perf_counter1); -#endif - } - -#if defined(USING_MALI400_L2_CACHE) - if (jobgp->user_input.perf_counter_flag & (_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE|_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE) ) - { - u32 src0; - u32 val0; - u32 src1; - u32 val1; - mali_kernel_l2_cache_get_perf_counters(&src0, &val0, &src1, &val1); - - if (jobgp->perf_counter_l2_src0 == src0) - { - jobgp->perf_counter_l2_val0 = val0 - jobgp->perf_counter_l2_val0; - } - else - { - jobgp->perf_counter_l2_val0 = 0; - } - - if (jobgp->perf_counter_l2_src1 == src1) - { - jobgp->perf_counter_l2_val1 = val1 - jobgp->perf_counter_l2_val1; - } - else - { - jobgp->perf_counter_l2_val1 = 0; - } - } -#endif - -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(core->core_number), 0, 0, 0, 0, 0); /* add GP and L2 counters and return status? */ -#endif - - MALI_DEBUG_PRINT(2, ("Mali GP: Job aborted - userspace would not provide more heap memory.\n")); -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&job->session->jobs_ended); -#endif - return JOB_STATUS_END_OOM; /* Core is ready for more jobs.*/ - } - /* finished ? */ - else if (0 == (core_status & MALIGP2_REG_VAL_STATUS_MASK_ACTIVE)) - { -#ifdef DEBUG - MALI_DEBUG_PRINT(4, ("Mali GP: Registers On job end:\n")); - maligp_print_regs(4, core); -#endif - MALI_DEBUG_PRINT_IF(5, irq_readout & 0x04, ("OOM when done, ignoring (reg.current = 0x%x, reg.end = 0x%x)\n", - (void*)mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR), - (void*)mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_END_ADDR)) - ); - - - if (0 != jobgp->user_input.perf_counter_flag ) - { - /* Readback the performance counters */ - if (jobgp->user_input.perf_counter_flag & (_MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE|_MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE) ) - { - jobgp->perf_counter0 = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_VALUE); - jobgp->perf_counter1 = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE); - -#if MALI_TRACEPOINTS_ENABLED - //TODO magic numbers should come from mali_linux_trace.h instead - _mali_profiling_add_counter(7, jobgp->perf_counter0); - _mali_profiling_add_counter(8, jobgp->perf_counter1); -#endif - } - -#if defined(USING_MALI400_L2_CACHE) - if (jobgp->user_input.perf_counter_flag & (_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE|_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE) ) - { - u32 src0; - u32 val0; - u32 src1; - u32 val1; - mali_kernel_l2_cache_get_perf_counters(&src0, &val0, &src1, &val1); - - if (jobgp->perf_counter_l2_src0 == src0) - { - jobgp->perf_counter_l2_val0 = val0 - jobgp->perf_counter_l2_val0; - } - else - { - jobgp->perf_counter_l2_val0 = 0; - } - - if (jobgp->perf_counter_l2_src1 == src1) - { - jobgp->perf_counter_l2_val1 = val1 - jobgp->perf_counter_l2_val1; - } - else - { - jobgp->perf_counter_l2_val1 = 0; - } - } -#endif - } - -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(core->core_number), - jobgp->perf_counter0, jobgp->perf_counter1, - jobgp->user_input.perf_counter_src0 | (jobgp->user_input.perf_counter_src1 << 8) -#if defined(USING_MALI400_L2_CACHE) - | (jobgp->user_input.perf_counter_l2_src0 << 16) | (jobgp->user_input.perf_counter_l2_src1 << 24), - jobgp->perf_counter_l2_val0, - jobgp->perf_counter_l2_val1 -#else - ,0, 0 -#endif - ); -#endif - - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_MASK_ALL); - -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&job->session->jobs_ended); -#endif - pr_debug("SPI_GPU_GP Idle\n"); - return JOB_STATUS_END_SUCCESS; /* core idle */ - } - /* sw watchdog timeout handling or time to do hang checking ? */ - else if ( - (CORE_WATCHDOG_TIMEOUT == core->state) || - ( - (CORE_HANG_CHECK_TIMEOUT == core->state) && - ( - (jobgp->have_extended_progress_checking ? (mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE) == jobgp->vertices) : 1/*TRUE*/) && - ((core_status & MALIGP2_REG_VAL_STATUS_VS_ACTIVE) ? (vscl == jobgp->last_vscl) : 1/*TRUE*/) && - ((core_status & MALIGP2_REG_VAL_STATUS_PLBU_ACTIVE) ? (plbcl == jobgp->last_plbcl) : 1/*TRUE*/) - ) - ) - ) - { - /* no progress detected, killed by the watchdog */ - -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(core->core_number), 0, 0, 0, 0, 0); /* add GP and L2 counters and return status? */ -#endif - - MALI_PRINT( ("Mali GP: SW-Timeout.\n")); - if (core_status & MALIGP2_REG_VAL_STATUS_VS_ACTIVE) MALI_DEBUG_PRINT(1, ("vscl current = 0x%x last = 0x%x\n", (void*)vscl, (void*)jobgp->last_vscl)); - if (core_status & MALIGP2_REG_VAL_STATUS_PLBU_ACTIVE) MALI_DEBUG_PRINT(1, ("plbcl current = 0x%x last = 0x%x\n", (void*)plbcl, (void*)jobgp->last_plbcl)); - if (jobgp->have_extended_progress_checking) MALI_DEBUG_PRINT(1, ("vertices processed = %d, last = %d\n", mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE), - jobgp->vertices)); -#ifdef DEBUG - maligp_print_regs(2, core); -#endif - -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&job->session->jobs_ended); -#endif - MALI_PANIC("%s Watchdog timeout\n", MALI_GP_SUBSYSTEM_NAME); - return JOB_STATUS_END_HANG; - } - /* if hang timeout checking was enabled and we detected progress, will be fall down to this check */ - /* check for PLBU OOM before the hang check to avoid the race condition of the hw wd trigging while waiting for us to handle the OOM interrupt */ - else if ( 0 != (irq_readout & MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM)) - { - mali_core_session *session; - _mali_osk_notification_t *notific; - _mali_uk_gp_job_suspended_s * suspended_job; - -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SUSPEND|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(core->core_number), 0, 0, 0, 0, 0); /* add GP and L2 counters and return status? */ -#endif - - session = job->session; - - MALI_DEBUG_PRINT(4, ("OOM, new heap requested by GP\n")); - MALI_DEBUG_PRINT(4, ("Status when OOM: current = 0x%x, end = 0x%x\n", - (void*)mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR), - (void*)mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_END_ADDR)) - ); - - notific = _mali_osk_notification_create( - - _MALI_NOTIFICATION_GP_STALLED, - sizeof( _mali_uk_gp_job_suspended_s ) - ); - if ( NULL == notific) - { - MALI_PRINT_ERROR( ("Mali GP: Could not get notification object\n")) ; - return JOB_STATUS_END_OOM; /* Core is ready for more jobs.*/ - } - - core->state = CORE_WORKING; - jobgp->is_stalled_waiting_for_more_memory = 1; - suspended_job = (_mali_uk_gp_job_suspended_s *)notific->result_buffer; /* this is ok - result_buffer was malloc'd */ - - suspended_job->user_job_ptr = jobgp->user_input.user_job_ptr; - suspended_job->reason = _MALIGP_JOB_SUSPENDED_OUT_OF_MEMORY ; - suspended_job->cookie = (u32) core; - last_gp_core_cookie = core; - - _mali_osk_notification_queue_send( session->notification_queue, notific); - -#ifdef DEBUG - maligp_print_regs(4, core); -#endif - - /* stop all active timers */ - _mali_osk_timer_del( core->timer); - _mali_osk_timer_del( core->timer_hang_detection); - MALI_DEBUG_PRINT(4, ("Mali GP: PLBU heap empty, sending memory request to userspace\n")); - /* save to watchdog_jiffies what was remaining WD timeout value when OOM was triggered */ - job->watchdog_jiffies = (long)job->watchdog_jiffies - (long)_mali_osk_time_tickcount(); - /* reuse core->timer as the userspace response timeout handler */ - _mali_osk_timer_add( core->timer, _mali_osk_time_mstoticks(1000) ); /* wait max 1 sec for userspace to respond */ - return JOB_STATUS_CONTINUE_RUN; /* The core is NOT available for new jobs. */ - } - /* hw watchdog is reporting a new hang or an existing progress-during-hang check passed? */ - else if ((CORE_HANG_CHECK_TIMEOUT == core->state) || (irq_readout & jobgp->active_mask & MALIGP2_REG_VAL_IRQ_HANG)) - { - /* check interval in ms */ - u32 timeout = mali_core_hang_check_timeout_get(); - MALI_DEBUG_PRINT(3, ("Mali GP: HW/SW Watchdog triggered, checking for progress in %d ms\n", timeout)); - core->state = CORE_WORKING; - - /* save state for the progress checking */ - jobgp->last_vscl = vscl; - jobgp->last_plbcl = plbcl; - if (jobgp->have_extended_progress_checking) - { - jobgp->vertices = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE); - } - /* hw watchdog triggered, set up a progress checker every HANGCHECK ms */ - _mali_osk_timer_add( core->timer_hang_detection, _mali_osk_time_mstoticks(timeout)); - jobgp->active_mask &= ~MALIGP2_REG_VAL_IRQ_HANG; /* ignore the hw watchdog from now on */ - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, irq_readout); - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_MASK, jobgp->active_mask); - return JOB_STATUS_CONTINUE_RUN; /* not finihsed */ } - /* no errors, but still working */ - else if ( ( 0 == (core_status & MALIGP2_REG_VAL_STATUS_MASK_ERROR)) && - ( 0 != (core_status & MALIGP2_REG_VAL_STATUS_MASK_ACTIVE )) - ) - { - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, irq_readout); - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_MASK, jobgp->active_mask); - return JOB_STATUS_CONTINUE_RUN; - } - /* Else there must be some error */ - else - { -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(core->core_number), 0, 0, 0, 0, 0); /* add GP and L2 counters and return status? */ -#endif - - MALI_PRINT( ("Mali GP: Core crashed? *IRQ: 0x%x Status: 0x%x\n", irq_readout, core_status )); - #ifdef DEBUG - MALI_DEBUG_PRINT(1, ("Mali GP: Registers Before reset:\n")); - maligp_print_regs(1, core); - #endif -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&job->session->jobs_ended); -#endif - return JOB_STATUS_END_UNKNOWN_ERR; - } -} - - -/* This function is called from the ioctl function and should return a mali_core_job pointer -to a created mali_core_job object with the data given from userspace */ -static _mali_osk_errcode_t subsystem_maligp_get_new_job_from_user(struct mali_core_session * session, void * argument) -{ - maligp_job *jobgp; - mali_core_job *job = NULL; - mali_core_job *previous_replaced_job; - _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; - _mali_uk_gp_start_job_s * user_ptr_job_input; - - user_ptr_job_input = (_mali_uk_gp_start_job_s *)argument; - - MALI_CHECK_NON_NULL(jobgp = (maligp_job *) _mali_osk_calloc(1, sizeof(maligp_job)), _MALI_OSK_ERR_FAULT); - - /* Copy the job data from the U/K interface */ - if ( NULL == _mali_osk_memcpy(&jobgp->user_input, user_ptr_job_input, sizeof(_mali_uk_gp_start_job_s) ) ) - { - MALI_PRINT_ERROR( ("Mali GP: Could not copy data from U/K interface.\n")) ; - err = _MALI_OSK_ERR_FAULT; - goto function_exit; - } - - MALI_DEBUG_PRINT(3, ("Mali GP: subsystem_maligp_get_new_job_from_user 0x%x\n", (void*)jobgp->user_input.user_job_ptr)); - - MALI_DEBUG_PRINT(3, ("Mali GP: Job Regs: 0x%08X 0x%08X, 0x%08X 0x%08X 0x%08X 0x%08X\n", - jobgp->user_input.frame_registers[0], - jobgp->user_input.frame_registers[1], - jobgp->user_input.frame_registers[2], - jobgp->user_input.frame_registers[3], - jobgp->user_input.frame_registers[4], - jobgp->user_input.frame_registers[5]) ); - - - job = GET_JOB_EMBEDDED_PTR(jobgp); - - job->session = session; - job->flags = MALI_UK_START_JOB_FLAG_DEFAULT; /* Current flags only make sence for PP jobs */ - job_priority_set(job, jobgp->user_input.priority); - job_watchdog_set(job, jobgp->user_input.watchdog_msecs ); - jobgp->heap_current_addr = jobgp->user_input.frame_registers[4]; - - job->abort_id = jobgp->user_input.abort_id; - - jobgp->is_stalled_waiting_for_more_memory = 0; - -#if MALI_TIMELINE_PROFILING_ENABLED - jobgp->pid = _mali_osk_get_pid(); - jobgp->tid = _mali_osk_get_tid(); -#endif - - if (mali_job_queue_full(session)) - { - /* Cause jobgp to free: */ - user_ptr_job_input->status = _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE; - goto function_exit; - } - - /* We now know that we have a job, and a slot to put it in */ - - jobgp->active_mask = MALIGP2_REG_VAL_IRQ_MASK_USED; - - /* Allocating User Return Data */ - jobgp->notification_obj = _mali_osk_notification_create( - _MALI_NOTIFICATION_GP_FINISHED, - sizeof(_mali_uk_gp_job_finished_s) ); - - if ( NULL == jobgp->notification_obj ) - { - MALI_PRINT_ERROR( ("Mali GP: Could not get notification_obj.\n")) ; - err = _MALI_OSK_ERR_NOMEM; - goto function_exit; - } - - _MALI_OSK_INIT_LIST_HEAD( &(job->list) ) ; - - MALI_DEBUG_PRINT(4, ("Mali GP: Job: 0x%08x INPUT from user.\n", (u32)jobgp->user_input.user_job_ptr)) ; - - /* This should not happen since we have the checking of priority above */ - err = mali_core_session_add_job(session, job, &previous_replaced_job); - if ( _MALI_OSK_ERR_OK != err ) - { - MALI_PRINT_ERROR( ("Mali GP: Internal error\n")) ; - /* Cause jobgp to free: */ - user_ptr_job_input->status = _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE; - _mali_osk_notification_delete( jobgp->notification_obj ); - goto function_exit; - } - - /* If MALI_TRUE: This session had a job with lower priority which were removed. - This replaced job is given back to userspace. */ - if ( NULL != previous_replaced_job ) - { - maligp_job *previous_replaced_jobgp; - - previous_replaced_jobgp = GET_JOBGP2_PTR(previous_replaced_job); - - MALI_DEBUG_PRINT(4, ("Mali GP: Replacing job: 0x%08x\n", (u32)previous_replaced_jobgp->user_input.user_job_ptr)) ; - - /* Copy to the input data (which also is output data) the - pointer to the job that were replaced, so that the userspace - driver can put this job in the front of its job-queue */ - user_ptr_job_input->returned_user_job_ptr = previous_replaced_jobgp->user_input.user_job_ptr; - - /** @note failure to 'copy to user' at this point must not free jobgp, - * and so no transaction rollback required in the U/K interface */ - - /* This does not cause jobgp to free: */ - user_ptr_job_input->status = _MALI_UK_START_JOB_STARTED_LOW_PRI_JOB_RETURNED; - MALI_DEBUG_PRINT(5, ("subsystem_maligp_get_new_job_from_user: Job added, prev returned\n")) ; - } - else - { - /* This does not cause jobgp to free: */ - user_ptr_job_input->status = _MALI_UK_START_JOB_STARTED; - MALI_DEBUG_PRINT(5, ("subsystem_maligp_get_new_job_from_user: Job added\n")) ; - } - -function_exit: - if ( _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE == user_ptr_job_input->status - || _MALI_OSK_ERR_OK != err ) - { - _mali_osk_free(jobgp); - } -#if MALI_STATE_TRACKING - if (_MALI_UK_START_JOB_STARTED==user_ptr_job_input->status) - { - if(job) - { - job->job_nr=_mali_osk_atomic_inc_return(&session->jobs_received); - } - } -#endif - - MALI_ERROR(err); -} - - -static _mali_osk_errcode_t subsystem_maligp_suspend_response(struct mali_core_session * session, void * argument) -{ - mali_core_renderunit *core; - maligp_job *jobgp; - mali_core_job *job; - - _mali_uk_gp_suspend_response_s * suspend_response; - - MALI_DEBUG_PRINT(5, ("subsystem_maligp_suspend_response\n")); - - suspend_response = (_mali_uk_gp_suspend_response_s *)argument; - - /* We read job data from User */ - /* On a single mali_gp system we can only have one Stalled GP, - and therefore one stalled request with a cookie. This checks - that we get the correct cookie */ - if ( last_gp_core_cookie != (mali_core_renderunit *)suspend_response->cookie ) - { - MALI_DEBUG_PRINT(2, ("Mali GP: Got an illegal cookie from Userspace.\n")) ; - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - core = (mali_core_renderunit *)suspend_response->cookie; - last_gp_core_cookie = NULL; - job = core->current_job; - jobgp = GET_JOBGP2_PTR(job); - - switch( suspend_response->code ) - { - case _MALIGP_JOB_RESUME_WITH_NEW_HEAP : - MALI_DEBUG_PRINT(5, ("MALIGP_JOB_RESUME_WITH_NEW_HEAP jiffies: %li\n", _mali_osk_time_tickcount())); - MALI_DEBUG_PRINT(4, ("New Heap addr 0x%08x - 0x%08x\n", suspend_response->arguments[0], suspend_response->arguments[1])); - - jobgp->is_stalled_waiting_for_more_memory = 0; - job->watchdog_jiffies += _mali_osk_time_tickcount(); /* convert to absolute time again */ - _mali_osk_timer_mod( core->timer, job->watchdog_jiffies); /* update the timer */ - - - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, (MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM | MALIGP2_REG_VAL_IRQ_HANG)); - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_MASK, jobgp->active_mask); - mali_core_renderunit_register_write_relaxed(core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR, suspend_response->arguments[0]); - mali_core_renderunit_register_write_relaxed(core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_END_ADDR, suspend_response->arguments[1]); - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_UPDATE_PLBU_ALLOC); - _mali_osk_write_mem_barrier(); - -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_RESUME|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(core->core_number), 0, 0, 0, 0, 0); -#endif - - MALI_DEBUG_PRINT(4, ("GP resumed with new heap\n")); - - break; - - case _MALIGP_JOB_ABORT: - MALI_DEBUG_PRINT(3, ("MALIGP_JOB_ABORT on heap extend request\n")); - _mali_osk_irq_schedulework( core->irq ); - break; - - default: - MALI_PRINT_ERROR(("Wrong Suspend response from userspace\n")); - } - MALI_SUCCESS; -} - -/* This function is called from the ioctl function and should write the necessary data -to userspace telling which job was finished and the status and debuginfo for this job. -The function must also free and cleanup the input job object. */ -static void subsystem_maligp_return_job_to_user( mali_core_job * job, mali_subsystem_job_end_code end_status ) -{ - maligp_job *jobgp; - _mali_uk_gp_job_finished_s * job_out; - _mali_uk_gp_start_job_s* job_input; - mali_core_session *session; - - - jobgp = _MALI_OSK_CONTAINER_OF(job, maligp_job, embedded_core_job); - job_out = (_mali_uk_gp_job_finished_s *)jobgp->notification_obj->result_buffer; /* OK - this should've been malloc'd */ - job_input= &(jobgp->user_input); - session = job->session; - - MALI_DEBUG_PRINT(5, ("Mali GP: Job: 0x%08x OUTPUT to user. Runtime: %d us, irq readout %x\n", - (u32)jobgp->user_input.user_job_ptr, - job->render_time_usecs, - jobgp->irq_status)) ; - - _mali_osk_memset(job_out, 0 , sizeof(_mali_uk_gp_job_finished_s)); - - job_out->user_job_ptr = job_input->user_job_ptr; - - switch( end_status ) - { - case JOB_STATUS_CONTINUE_RUN: - case JOB_STATUS_END_SUCCESS: - case JOB_STATUS_END_OOM: - case JOB_STATUS_END_ABORT: - case JOB_STATUS_END_TIMEOUT_SW: - case JOB_STATUS_END_HANG: - case JOB_STATUS_END_SEG_FAULT: - case JOB_STATUS_END_ILLEGAL_JOB: - case JOB_STATUS_END_UNKNOWN_ERR: - case JOB_STATUS_END_SHUTDOWN: - case JOB_STATUS_END_SYSTEM_UNUSABLE: - job_out->status = (mali_subsystem_job_end_code) end_status; - break; - default: - job_out->status = JOB_STATUS_END_UNKNOWN_ERR ; - } - - job_out->irq_status = jobgp->irq_status; - job_out->status_reg_on_stop = jobgp->status_reg_on_stop; - job_out->vscl_stop_addr = 0; - job_out->plbcl_stop_addr = 0; - job_out->heap_current_addr = jobgp->heap_current_addr; - job_out->perf_counter0 = jobgp->perf_counter0; - job_out->perf_counter1 = jobgp->perf_counter1; - job_out->perf_counter_src0 = jobgp->user_input.perf_counter_src0 ; - job_out->perf_counter_src1 = jobgp->user_input.perf_counter_src1 ; - job_out->render_time = job->render_time_usecs; -#if defined(USING_MALI400_L2_CACHE) - job_out->perf_counter_l2_src0 = jobgp->perf_counter_l2_src0; - job_out->perf_counter_l2_src1 = jobgp->perf_counter_l2_src1; - job_out->perf_counter_l2_val0 = jobgp->perf_counter_l2_val0; - job_out->perf_counter_l2_val1 = jobgp->perf_counter_l2_val1; -#endif - -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&session->jobs_returned); -#endif - _mali_osk_notification_queue_send( session->notification_queue, jobgp->notification_obj); - jobgp->notification_obj = NULL; - - _mali_osk_free(jobgp); - - last_gp_core_cookie = NULL; -} - -static void subsystem_maligp_renderunit_delete(mali_core_renderunit * core) -{ - MALI_DEBUG_PRINT(5, ("Mali GP: maligp_renderunit_delete\n")); - _mali_osk_free(core); -} - -static void subsystem_maligp_renderunit_reset_core(struct mali_core_renderunit * core, mali_core_reset_style style) -{ - MALI_DEBUG_PRINT(5, ("Mali GP: renderunit_reset_core\n")); - - switch (style) - { - case MALI_CORE_RESET_STYLE_RUNABLE: - maligp_reset(core); - break; - case MALI_CORE_RESET_STYLE_DISABLE: - maligp_raw_reset(core); /* do the raw reset */ - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_MASK, 0); /* then disable the IRQs */ - break; - case MALI_CORE_RESET_STYLE_HARD: - maligp_reset_hard(core); - maligp_initialize_registers_mgmt(core); - break; - default: - MALI_DEBUG_PRINT(1, ("Unknown reset type %d\n", style)); - break; - } -} - -static void subsystem_maligp_renderunit_probe_core_irq_trigger(struct mali_core_renderunit* core) -{ - mali_core_renderunit_register_write(core , MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED); - mali_core_renderunit_register_write(core , MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT, MALIGP2_REG_VAL_CMD_FORCE_HANG ); - _mali_osk_mem_barrier(); -} - -static _mali_osk_errcode_t subsystem_maligp_renderunit_probe_core_irq_finished(struct mali_core_renderunit* core) -{ - u32 irq_readout; - - irq_readout = mali_core_renderunit_register_read(core, MALIGP2_REG_ADDR_MGMT_INT_STAT); - - if ( MALIGP2_REG_VAL_IRQ_FORCE_HANG & irq_readout ) - { - mali_core_renderunit_register_write(core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_FORCE_HANG); - _mali_osk_mem_barrier(); - MALI_SUCCESS; - } - - MALI_ERROR(_MALI_OSK_ERR_FAULT); -} - -_mali_osk_errcode_t _mali_ukk_gp_start_job( _mali_uk_gp_start_job_s *args ) -{ - mali_core_session * session; - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - session = (mali_core_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_gp_id); - MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_FAULT); - return mali_core_subsystem_ioctl_start_job(session, args); -} - -_mali_osk_errcode_t _mali_ukk_get_gp_number_of_cores( _mali_uk_get_gp_number_of_cores_s *args ) -{ - mali_core_session * session; - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - session = (mali_core_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_gp_id); - MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_FAULT); - return mali_core_subsystem_ioctl_number_of_cores_get(session, &args->number_of_cores); -} - -_mali_osk_errcode_t _mali_ukk_get_gp_core_version( _mali_uk_get_gp_core_version_s *args ) -{ - mali_core_session * session; - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - session = (mali_core_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_gp_id); - MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_FAULT); - return mali_core_subsystem_ioctl_core_version_get(session, &args->version); -} - -_mali_osk_errcode_t _mali_ukk_gp_suspend_response( _mali_uk_gp_suspend_response_s *args ) -{ - mali_core_session * session; - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - session = (mali_core_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_gp_id); - MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_FAULT); - return mali_core_subsystem_ioctl_suspend_response(session, args); -} - -void _mali_ukk_gp_abort_job( _mali_uk_gp_abort_job_s * args) -{ - mali_core_session * session; - MALI_DEBUG_ASSERT_POINTER(args); - if (NULL == args->ctx) return; - session = (mali_core_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_gp_id); - if (NULL == session) return; - mali_core_subsystem_ioctl_abort_job(session, args->abort_id); - -} - -#if USING_MALI_PMM - -_mali_osk_errcode_t maligp_signal_power_up( mali_bool queue_only ) -{ - MALI_DEBUG_PRINT(4, ("Mali GP: signal power up core - queue_only: %d\n", queue_only )); - - return( mali_core_subsystem_signal_power_up( &subsystem_maligp, 0, queue_only ) ); -} - -_mali_osk_errcode_t maligp_signal_power_down( mali_bool immediate_only ) -{ - MALI_DEBUG_PRINT(4, ("Mali GP: signal power down core - immediate_only: %d\n", immediate_only )); - - return( mali_core_subsystem_signal_power_down( &subsystem_maligp, 0, immediate_only ) ); -} - -#endif - -#if MALI_STATE_TRACKING -u32 maligp_subsystem_dump_state(char *buf, u32 size) -{ - return mali_core_renderunit_dump_state(&subsystem_maligp, buf, size); -} -#endif diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_MALI200.c b/drivers/media/video/samsung/mali/common/mali_kernel_MALI200.c deleted file mode 100644 index 0f5ebd0..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_MALI200.c +++ /dev/null @@ -1,1304 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -//added for SPI -#include <linux/kernel.h> - -#include "mali_kernel_common.h" -#include "mali_osk.h" -#include "mali_kernel_pp.h" -#include "mali_kernel_subsystem.h" -#include "mali_kernel_core.h" -#include "regs/mali_200_regs.h" -#include "mali_kernel_rendercore.h" -#if MALI_TIMELINE_PROFILING_ENABLED -#include "mali_kernel_profiling.h" -#endif -#ifdef USING_MALI400_L2_CACHE -#include "mali_kernel_l2_cache.h" -#endif -#if USING_MMU -#include "mali_kernel_mem_mmu.h" /* Needed for mali_kernel_mmu_force_bus_reset() */ -#endif - -#include "mali_osk_list.h" - -#if defined(USING_MALI200) -#define MALI_PP_SUBSYSTEM_NAME "Mali200" -#define MALI_PP_CORE_TYPE _MALI_200 -#elif defined(USING_MALI400) -#define MALI_PP_SUBSYSTEM_NAME "Mali-400 PP" -#define MALI_PP_CORE_TYPE _MALI_400_PP -#else -#error "No supported mali core defined" -#endif - -#define GET_JOB_EMBEDDED_PTR(job) (&((job)->embedded_core_job)) -#define GET_JOB200_PTR(job_extern) _MALI_OSK_CONTAINER_OF(job_extern, mali200_job, embedded_core_job) - -/* Initialized when this subsystem is initialized. This is determined by the - * position in subsystems[], and so the value used to initialize this is - * determined at compile time */ -static mali_kernel_subsystem_identifier mali_subsystem_mali200_id = -1; - -/* Describing a mali200 job settings */ -typedef struct mali200_job -{ - /* The general job struct common for all mali cores */ - mali_core_job embedded_core_job; - _mali_uk_pp_start_job_s user_input; - - u32 irq_status; - u32 perf_counter0; - u32 perf_counter1; - u32 last_tile_list_addr; /* Neccessary to continue a stopped job */ - - u32 active_mask; - - /* The data we will return back to the user */ - _mali_osk_notification_t *notification_obj; - -#if defined(USING_MALI400_L2_CACHE) - u32 perf_counter_l2_src0; - u32 perf_counter_l2_src1; - u32 perf_counter_l2_val0; - u32 perf_counter_l2_val1; - u32 perf_counter_l2_val0_raw; - u32 perf_counter_l2_val1_raw; -#endif - -#if MALI_TIMELINE_PROFILING_ENABLED - u32 pid; - u32 tid; -#endif -} mali200_job; - - -/*Functions Exposed to the General External System through - funciont pointers.*/ - -static _mali_osk_errcode_t mali200_subsystem_startup(mali_kernel_subsystem_identifier id); -#if USING_MMU -static _mali_osk_errcode_t mali200_subsystem_mmu_connect(mali_kernel_subsystem_identifier id); -#endif -static void mali200_subsystem_terminate(mali_kernel_subsystem_identifier id); -static _mali_osk_errcode_t mali200_subsystem_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue); -static void mali200_subsystem_session_end(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot); -static _mali_osk_errcode_t mali200_subsystem_core_system_info_fill(_mali_system_info* info); -static _mali_osk_errcode_t mali200_renderunit_create(_mali_osk_resource_t * resource); -#if USING_MMU -static void mali200_subsystem_broadcast_notification(mali_core_notification_message message, u32 data); -#endif -#if MALI_STATE_TRACKING -u32 mali200_subsystem_dump_state(char *buf, u32 size); -#endif - -/* Internal support functions */ -static _mali_osk_errcode_t mali200_core_version_legal( mali_core_renderunit *core ); -static void mali200_reset(mali_core_renderunit *core); -static void mali200_reset_hard(struct mali_core_renderunit * core); -static void mali200_raw_reset(mali_core_renderunit * core); -static void mali200_initialize_registers_mgmt(mali_core_renderunit *core ); - -/* Functions exposed to mali_core system through functionpointers - in the subsystem struct. */ -static _mali_osk_errcode_t subsystem_mali200_start_job(mali_core_job * job, mali_core_renderunit * core); -static _mali_osk_errcode_t subsystem_mali200_get_new_job_from_user(struct mali_core_session * session, void * argument); -static void subsystem_mali200_return_job_to_user( mali_core_job * job, mali_subsystem_job_end_code end_status); -static void subsystem_mali200_renderunit_delete(mali_core_renderunit * core); -static void subsystem_mali200_renderunit_reset_core(struct mali_core_renderunit * core, mali_core_reset_style style); -static void subsystem_mali200_renderunit_probe_core_irq_trigger(struct mali_core_renderunit* core); -static _mali_osk_errcode_t subsystem_mali200_renderunit_probe_core_irq_finished(struct mali_core_renderunit* core); - -static void subsystem_mali200_renderunit_stop_bus(struct mali_core_renderunit* core); -static u32 subsystem_mali200_irq_handler_upper_half(struct mali_core_renderunit * core); -static int subsystem_mali200_irq_handler_bottom_half(struct mali_core_renderunit* core); - -/* This will be one of the subsystems in the array of subsystems: - static struct mali_kernel_subsystem * subsystems[]; - found in file: mali_kernel_core.c -*/ - -struct mali_kernel_subsystem mali_subsystem_mali200= -{ - mali200_subsystem_startup, /* startup */ - NULL, /*mali200_subsystem_terminate,*/ /* shutdown */ -#if USING_MMU - mali200_subsystem_mmu_connect, /* load_complete */ -#else - NULL, -#endif - mali200_subsystem_core_system_info_fill, /* system_info_fill */ - mali200_subsystem_session_begin, /* session_begin */ - mali200_subsystem_session_end, /* session_end */ -#if USING_MMU - mali200_subsystem_broadcast_notification, /* broadcast_notification */ -#else - NULL, -#endif -#if MALI_STATE_TRACKING - mali200_subsystem_dump_state, /* dump_state */ -#endif -} ; - -static mali_core_subsystem subsystem_mali200 ; - -static _mali_osk_errcode_t mali200_subsystem_startup(mali_kernel_subsystem_identifier id) -{ - mali_core_subsystem * subsystem; - - MALI_DEBUG_PRINT(3, ("Mali PP: mali200_subsystem_startup\n") ) ; - - mali_subsystem_mali200_id = id; - - /* All values get 0 as default */ - _mali_osk_memset(&subsystem_mali200, 0, sizeof(subsystem_mali200)); - - subsystem = &subsystem_mali200; - subsystem->start_job = &subsystem_mali200_start_job; - subsystem->irq_handler_upper_half = &subsystem_mali200_irq_handler_upper_half; - subsystem->irq_handler_bottom_half = &subsystem_mali200_irq_handler_bottom_half; - subsystem->get_new_job_from_user = &subsystem_mali200_get_new_job_from_user; - subsystem->return_job_to_user = &subsystem_mali200_return_job_to_user; - subsystem->renderunit_delete = &subsystem_mali200_renderunit_delete; - subsystem->reset_core = &subsystem_mali200_renderunit_reset_core; - subsystem->stop_bus = &subsystem_mali200_renderunit_stop_bus; - subsystem->probe_core_irq_trigger = &subsystem_mali200_renderunit_probe_core_irq_trigger; - subsystem->probe_core_irq_acknowledge = &subsystem_mali200_renderunit_probe_core_irq_finished; - - /* Setting variables in the general core part of the subsystem.*/ - subsystem->name = MALI_PP_SUBSYSTEM_NAME; - subsystem->core_type = MALI_PP_CORE_TYPE; - subsystem->id = id; - - /* Initiates the rest of the general core part of the subsystem */ - MALI_CHECK_NO_ERROR(mali_core_subsystem_init( subsystem )); - - /* This will register the function for adding MALI200 cores to the subsystem */ -#if defined(USING_MALI200) - MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(MALI200, mali200_renderunit_create)); -#endif -#if defined(USING_MALI400) - MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(MALI400PP, mali200_renderunit_create)); -#endif - - MALI_DEBUG_PRINT(6, ("Mali PP: mali200_subsystem_startup\n") ) ; - - MALI_SUCCESS; -} - -#if USING_MMU -static _mali_osk_errcode_t mali200_subsystem_mmu_connect(mali_kernel_subsystem_identifier id) -{ - mali_core_subsystem_attach_mmu(&subsystem_mali200); - MALI_SUCCESS; /* OK */ -} -#endif - -static void mali200_subsystem_terminate(mali_kernel_subsystem_identifier id) -{ - MALI_DEBUG_PRINT(3, ("Mali PP: mali200_subsystem_terminate\n") ) ; - mali_core_subsystem_cleanup(&subsystem_mali200); -} - -static _mali_osk_errcode_t mali200_subsystem_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue) -{ - mali_core_session * session; - - MALI_DEBUG_PRINT(3, ("Mali PP: mali200_subsystem_session_begin\n") ) ; - MALI_CHECK_NON_NULL(session = _mali_osk_malloc( sizeof(mali_core_session) ), _MALI_OSK_ERR_NOMEM); - - _mali_osk_memset(session, 0, sizeof(*session) ); - *slot = (mali_kernel_subsystem_session_slot)session; - - session->subsystem = &subsystem_mali200; - - session->notification_queue = queue; - -#if USING_MMU - session->mmu_session = mali_session_data; -#endif - - mali_core_session_begin(session); - - MALI_DEBUG_PRINT(6, ("Mali PP: mali200_subsystem_session_begin\n") ) ; - - MALI_SUCCESS; -} - -static void mali200_subsystem_session_end(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot) -{ - mali_core_session * session; - - MALI_DEBUG_PRINT(3, ("Mali PP: mali200_subsystem_session_end\n") ) ; - if ( NULL==slot || NULL==*slot) - { - MALI_PRINT_ERROR(("Input slot==NULL")); - return; - } - session = (mali_core_session*) *slot; - mali_core_session_close(session); - - _mali_osk_free(session); - *slot = NULL; - - MALI_DEBUG_PRINT(6, ("Mali PP: mali200_subsystem_session_end\n") ) ; -} - -/** - * We fill in info about all the cores we have - * @param info Pointer to system info struct to update - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali200_subsystem_core_system_info_fill(_mali_system_info* info) -{ - return mali_core_subsystem_system_info_fill(&subsystem_mali200, info); -} - - -static _mali_osk_errcode_t mali200_renderunit_create(_mali_osk_resource_t * resource) -{ - mali_core_renderunit *core; - _mali_osk_errcode_t err; - - MALI_DEBUG_PRINT(3, ("Mali PP: mali200_renderunit_create\n") ) ; - /* Checking that the resource settings are correct */ -#if defined(USING_MALI200) - if(MALI200 != resource->type) - { - MALI_PRINT_ERROR(("Can not register this resource as a " MALI_PP_SUBSYSTEM_NAME " core.")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } -#elif defined(USING_MALI400) - if(MALI400PP != resource->type) - { - MALI_PRINT_ERROR(("Can not register this resource as a " MALI_PP_SUBSYSTEM_NAME " core.")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } -#endif - if ( 0 != resource->size ) - { - MALI_PRINT_ERROR(("Memory size set to " MALI_PP_SUBSYSTEM_NAME " core should be zero.")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - if ( NULL == resource->description ) - { - MALI_PRINT_ERROR(("A " MALI_PP_SUBSYSTEM_NAME " core needs a unique description field")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* Create a new core object */ - core = (mali_core_renderunit*) _mali_osk_malloc(sizeof(*core)); - if ( NULL == core ) - { - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - /* Variables set to be able to open and register the core */ - core->subsystem = &subsystem_mali200 ; - core->registers_base_addr = resource->base ; - core->size = MALI200_REG_SIZEOF_REGISTER_BANK ; - core->irq_nr = resource->irq ; - core->description = resource->description; -#if USING_MMU - core->mmu_id = resource->mmu_id; - core->mmu = NULL; -#endif -#if USING_MALI_PMM - /* Set up core's PMM id */ - switch( subsystem_mali200.number_of_cores ) - { - case 0: - core->pmm_id = MALI_PMM_CORE_PP0; - break; - case 1: - core->pmm_id = MALI_PMM_CORE_PP1; - break; - case 2: - core->pmm_id = MALI_PMM_CORE_PP2; - break; - case 3: - core->pmm_id = MALI_PMM_CORE_PP3; - break; - default: - MALI_DEBUG_PRINT(1, ("Unknown supported core for PMM\n")); - err = _MALI_OSK_ERR_FAULT; - goto exit_on_error0; - } -#endif - - err = mali_core_renderunit_init( core ); - if (_MALI_OSK_ERR_OK != err) - { - MALI_DEBUG_PRINT(1, ("Failed to initialize renderunit\n")); - goto exit_on_error0; - } - - /* Map the new core object, setting: core->registers_mapped */ - err = mali_core_renderunit_map_registers(core); - if (_MALI_OSK_ERR_OK != err) - { - MALI_DEBUG_PRINT(1, ("Failed to map register\n")); - goto exit_on_error1; - } - - /* Check that the register mapping of the core works. - Return 0 if Mali PP core is present and accessible. */ - if (mali_benchmark) { -#if defined(USING_MALI200) - core->core_version = (((u32)MALI_PP_PRODUCT_ID) << 16) | 5 /* Fake Mali200-r0p5 */; -#elif defined(USING_MALI400) - core->core_version = (((u32)MALI_PP_PRODUCT_ID) << 16) | 0x0101 /* Fake Mali400-r1p1 */; -#else -#error "No supported mali core defined" -#endif - } else { - core->core_version = mali_core_renderunit_register_read( - core, - MALI200_REG_ADDR_MGMT_VERSION); - } - - err = mali200_core_version_legal(core); - if (_MALI_OSK_ERR_OK != err) - { - MALI_DEBUG_PRINT(1, ("Invalid core\n")); - goto exit_on_error2; - } - - /* Reset the core. Put the core into a state where it can start to render. */ - mali200_reset(core); - - /* Registering IRQ, init the work_queue_irq_handle */ - /* Adding this core as an available renderunit in the subsystem. */ - err = mali_core_subsystem_register_renderunit(&subsystem_mali200, core); - if (_MALI_OSK_ERR_OK != err) - { - MALI_DEBUG_PRINT(1, ("Failed to register with core\n")); - goto exit_on_error2; - } - MALI_DEBUG_PRINT(6, ("Mali PP: mali200_renderunit_create\n") ) ; - - MALI_SUCCESS; - -exit_on_error2: - mali_core_renderunit_unmap_registers(core); -exit_on_error1: - mali_core_renderunit_term(core); -exit_on_error0: - _mali_osk_free( core ) ; - MALI_PRINT_ERROR(("Renderunit NOT created.")); - MALI_ERROR(err); -} - -#if USING_MMU -/* Used currently only for signalling when MMU has a pagefault */ -static void mali200_subsystem_broadcast_notification(mali_core_notification_message message, u32 data) -{ - mali_core_subsystem_broadcast_notification(&subsystem_mali200, message, data); -} -#endif - -static _mali_osk_errcode_t mali200_core_version_legal( mali_core_renderunit *core ) -{ - u32 mali_type; - - mali_type = core->core_version >> 16; -#if defined(USING_MALI400) - /* Mali300 and Mali400 is compatible, accept either core. */ - if (MALI400_PP_PRODUCT_ID != mali_type && MALI300_PP_PRODUCT_ID != mali_type) -#else - if (MALI_PP_PRODUCT_ID != mali_type) -#endif - { - MALI_PRINT_ERROR(("Error: reading this from " MALI_PP_SUBSYSTEM_NAME " version register: 0x%x\n", core->core_version)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - MALI_DEBUG_PRINT(3, ("Mali PP: core_version_legal: Reads correct mali version: %d\n", mali_type) ) ; - MALI_SUCCESS; -} - -static void subsystem_mali200_renderunit_stop_bus(struct mali_core_renderunit* core) -{ - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_STOP_BUS); -} - -static void mali200_raw_reset( mali_core_renderunit *core ) -{ - int i; - const int request_loop_count = 20; - - MALI_DEBUG_PRINT(4, ("Mali PP: mali200_raw_reset: %s\n", core->description)); - if (mali_benchmark) return; - - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, 0); /* disable IRQs */ - -#if defined(USING_MALI200) - - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_STOP_BUS); - - for (i = 0; i < request_loop_count; i++) - { - if (mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_STATUS) & MALI200_REG_VAL_STATUS_BUS_STOPPED) break; - _mali_osk_time_ubusydelay(10); - } - - MALI_DEBUG_PRINT_IF(1, request_loop_count == i, ("Mali PP: Bus was never stopped during core reset\n")); - - - if (request_loop_count==i) - { -#if USING_MMU - if ((NULL!=core->mmu) && (MALI_FALSE == core->error_recovery)) - { - /* Could not stop bus connections from core, probably because some of the already pending - bus request has had a page fault, and therefore can not complete before the MMU does PageFault - handling. This can be treated as a heavier reset function - which unfortunately reset all - the cores on this MMU in addition to the MMU itself */ - MALI_DEBUG_PRINT(1, ("Mali PP: Forcing Bus reset\n")); - mali_kernel_mmu_force_bus_reset(core->mmu); - return; - } -#endif - MALI_PRINT(("A MMU reset did not allow PP to stop its bus, system failure, unable to recover\n")); - return; - } - - /* use the hard reset routine to do the actual reset */ - mali200_reset_hard(core); - -#elif defined(USING_MALI400) - - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI400PP_REG_VAL_IRQ_RESET_COMPLETED); - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI400PP_REG_VAL_CTRL_MGMT_SOFT_RESET); - - for (i = 0; i < request_loop_count; i++) - { - if (mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT) & MALI400PP_REG_VAL_IRQ_RESET_COMPLETED) break; - _mali_osk_time_ubusydelay(10); - } - - if (request_loop_count==i) - { -#if USING_MMU - if ((NULL!=core->mmu) && (MALI_FALSE == core->error_recovery)) - { - /* Could not stop bus connections from core, probably because some of the already pending - bus request has had a page fault, and therefore can not complete before the MMU does PageFault - handling. This can be treated as a heavier reset function - which unfortunately reset all - the cores on this MMU in addition to the MMU itself */ - MALI_DEBUG_PRINT(1, ("Mali PP: Forcing Bus reset\n")); - mali_kernel_mmu_force_bus_reset(core->mmu); - return; - } -#endif - MALI_PRINT(("A MMU reset did not allow PP to stop its bus, system failure, unable to recover\n")); - return; - } - else - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI200_REG_VAL_IRQ_MASK_ALL); - -#else -#error "no supported mali core defined" -#endif -} - -static void mali200_reset( mali_core_renderunit *core ) -{ - if (!mali_benchmark) { - mali200_raw_reset(core); - mali200_initialize_registers_mgmt(core); - } -} - -/* Sets the registers on mali200 according to the const default_mgmt_regs array. */ -static void mali200_initialize_registers_mgmt(mali_core_renderunit *core ) -{ - MALI_DEBUG_PRINT(6, ("Mali PP: mali200_initialize_registers_mgmt: %s\n", core->description)) ; - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_USED); -} - -/* Start this job on this core. Return MALI_TRUE if the job was started. */ -static _mali_osk_errcode_t subsystem_mali200_start_job(mali_core_job * job, mali_core_renderunit * core) -{ - mali200_job *job200; - - /* The local extended version of the general structs */ - job200 = _MALI_OSK_CONTAINER_OF(job, mali200_job, embedded_core_job); - - if ( (0 == job200->user_input.frame_registers[0]) || - (0 == job200->user_input.frame_registers[1]) ) - { - MALI_DEBUG_PRINT(4, ("Mali PP: Job: 0x%08x WILL NOT START SINCE JOB HAS ILLEGAL ADDRESSES\n", - (u32)job200->user_input.user_job_ptr)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - MALI_DEBUG_PRINT(4, ("Mali PP: Job: 0x%08x START_RENDER Tile_list: 0x%08x\n", - (u32)job200->user_input.user_job_ptr, - job200->user_input.frame_registers[0])); - MALI_DEBUG_PRINT(6, ("Mali PP: RSW base addr: 0x%08x Vertex base addr: 0x%08x\n", - job200->user_input.frame_registers[1], job200->user_input.frame_registers[2])); - - /* Frame registers. Copy from mem to physical registers */ - mali_core_renderunit_register_write_array( - core, - MALI200_REG_ADDR_FRAME, - &(job200->user_input.frame_registers[0]), - MALI200_NUM_REGS_FRAME); - - /* Write Back unit 0. Copy from mem to physical registers only if the WB unit will be used. */ - if (job200->user_input.wb0_registers[0]) - { - mali_core_renderunit_register_write_array( - core, - MALI200_REG_ADDR_WB0, - &(job200->user_input.wb0_registers[0]), - MALI200_NUM_REGS_WBx); - } - - /* Write Back unit 1. Copy from mem to physical registers only if the WB unit will be used. */ - if (job200->user_input.wb1_registers[0]) - { - mali_core_renderunit_register_write_array( - core, - MALI200_REG_ADDR_WB1, - &(job200->user_input.wb1_registers[0]), - MALI200_NUM_REGS_WBx); - } - - /* Write Back unit 2. Copy from mem to physical registers only if the WB unit will be used. */ - if (job200->user_input.wb2_registers[0]) - { - mali_core_renderunit_register_write_array( - core, - MALI200_REG_ADDR_WB2, - &(job200->user_input.wb2_registers[0]), - MALI200_NUM_REGS_WBx); - } - -#if MALI_TRACEPOINTS_ENABLED - { - int counter = ((core->core_number)*2)+9; /* magic numbers for FP0 are 9 & 10 */ - - //printk("FP core->number = %d\n", core->core_number); - //TODO we are using magic numbers again... these are from gator_events_mali.c - job200->user_input.perf_counter_flag = 0; - - if( counter>=9 && counter<=16) { - - if( counter_table[counter] != 0xFFFFFFFF ) { - job200->user_input.perf_counter_flag |= _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE; - job200->user_input.perf_counter_src0 = counter_table[counter]; - } - if( counter_table[counter+1] != 0xFFFFFFFF ) { - job200->user_input.perf_counter_flag |= _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE; - job200->user_input.perf_counter_src1 = counter_table[counter+1]; - } - - } else { - MALI_DEBUG_PRINT(2, ("core->core_number out of the range (0-3) (%d)\n", core->core_number)); - } - } -#if defined(USING_MALI400_L2_CACHE) - if( counter_table[5] != 0xFFFFFFFF ) { - job200->user_input.perf_counter_flag |= _MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE | _MALI_PERFORMANCE_COUNTER_FLAG_L2_RESET; - job200->user_input.perf_counter_l2_src0 = counter_table[5]; - } - if( counter_table[6] != 0xFFFFFFFF ) { - job200->user_input.perf_counter_flag |= _MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE | _MALI_PERFORMANCE_COUNTER_FLAG_L2_RESET; - job200->user_input.perf_counter_l2_src1 = counter_table[6]; - } -#endif -#endif - - /* This selects which performance counters we are reading */ - if ( 0 != job200->user_input.perf_counter_flag ) - { - if ( job200->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE) - { - mali_core_renderunit_register_write_relaxed( - core, - MALI200_REG_ADDR_MGMT_PERF_CNT_0_ENABLE, - MALI200_REG_VAL_PERF_CNT_ENABLE); - mali_core_renderunit_register_write_relaxed( - core, - MALI200_REG_ADDR_MGMT_PERF_CNT_0_SRC, - job200->user_input.perf_counter_src0); - - } - - if ( job200->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE) - { - mali_core_renderunit_register_write_relaxed( - core, - MALI200_REG_ADDR_MGMT_PERF_CNT_1_ENABLE, - MALI200_REG_VAL_PERF_CNT_ENABLE); - mali_core_renderunit_register_write_relaxed( - core, - MALI200_REG_ADDR_MGMT_PERF_CNT_1_SRC, - job200->user_input.perf_counter_src1); - - } - -#if defined(USING_MALI400_L2_CACHE) - if ( job200->user_input.perf_counter_flag & (_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE|_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE) ) - { - int force_reset = ( job200->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_L2_RESET ) ? 1 : 0; - u32 src0 = 0; - u32 src1 = 0; - - if ( job200->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE ) - { - src0 = job200->user_input.perf_counter_l2_src0; - } - if ( job200->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE ) - { - src1 = job200->user_input.perf_counter_l2_src1; - } - - mali_kernel_l2_cache_set_perf_counters(src0, src1, force_reset); /* will activate and possibly reset counters */ - - /* Now, retrieve the current values, so we can substract them when the job has completed */ - mali_kernel_l2_cache_get_perf_counters(&job200->perf_counter_l2_src0, - &job200->perf_counter_l2_val0, - &job200->perf_counter_l2_src1, - &job200->perf_counter_l2_val1); - } -#endif - } - - subsystem_flush_mapped_mem_cache(); - -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&job->session->jobs_started); -#endif - - /* This is the command that starts the Core */ - mali_core_renderunit_register_write( - core, - MALI200_REG_ADDR_MGMT_CTRL_MGMT, - MALI200_REG_VAL_CTRL_MGMT_START_RENDERING); - _mali_osk_write_mem_barrier(); - - - pr_debug("SPI_GPU_PP%u Start\n", core->core_number); -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE | MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_number) | MALI_PROFILING_EVENT_REASON_SINGLE_HW_FLUSH, job200->user_input.frame_builder_id, job200->user_input.flush_id, 0, 0, 0); - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_START|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_number), job200->pid, job200->tid, -#if defined(USING_MALI400_L2_CACHE) - (job200->user_input.perf_counter_l2_src0 << 16) | (job200->user_input.perf_counter_l2_src1 << 24), - job200->perf_counter_l2_val0, job200->perf_counter_l2_val1 -#else - 0, 0, 0 -#endif - ); -#endif - - MALI_SUCCESS; -} - -static u32 subsystem_mali200_irq_handler_upper_half(mali_core_renderunit * core) -{ - u32 irq_readout; - - if (mali_benchmark) { - return (core->current_job ? 1 : 0); /* simulate irq is pending when a job is pending */ - } - - MALI_DEBUG_PRINT(5, ("Mali PP: subsystem_mali200_irq_handler_upper_half: %s\n", core->description)) ; - irq_readout = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_INT_STATUS); - - if ( MALI200_REG_VAL_IRQ_MASK_NONE != irq_readout ) - { - /* Mask out all IRQs from this core until IRQ is handled */ - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_NONE); - -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_number)|MALI_PROFILING_EVENT_REASON_SINGLE_HW_INTERRUPT, irq_readout, 0, 0, 0, 0); -#endif - - return 1; - } - return 0; -} - -static int subsystem_mali200_irq_handler_bottom_half(struct mali_core_renderunit* core) -{ - u32 irq_readout; - u32 current_tile_addr; - u32 core_status; - mali_core_job * job; - mali200_job * job200; - - job = core->current_job; - job200 = GET_JOB200_PTR(job); - - - if (mali_benchmark) { - irq_readout = MALI200_REG_VAL_IRQ_END_OF_FRAME; - current_tile_addr = 0; - core_status = 0; - } else { - irq_readout = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT) & MALI200_REG_VAL_IRQ_MASK_USED; - current_tile_addr = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_CURRENT_REND_LIST_ADDR); - core_status = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_STATUS); - } - - if (NULL == job) - { - MALI_DEBUG_ASSERT(CORE_IDLE==core->state); - if ( 0 != irq_readout ) - { - MALI_PRINT_ERROR(("Interrupt from a core not running a job. IRQ: 0x%04x Status: 0x%04x", irq_readout, core_status)); - } - return JOB_STATUS_END_UNKNOWN_ERR; - } - MALI_DEBUG_ASSERT(CORE_IDLE!=core->state); - - job200->irq_status |= irq_readout; - - MALI_DEBUG_PRINT_IF( 3, ( 0 != irq_readout ), - ("Mali PP: Job: 0x%08x IRQ RECEIVED Rawstat: 0x%x Tile_addr: 0x%x Status: 0x%x\n", - (u32)job200->user_input.user_job_ptr, irq_readout ,current_tile_addr ,core_status)); - - if ( MALI200_REG_VAL_IRQ_END_OF_FRAME & irq_readout) - { -#if defined(USING_MALI200) - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_FLUSH_CACHES); -#endif - - if (0 != job200->user_input.perf_counter_flag ) - { - if (job200->user_input.perf_counter_flag & (_MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE|_MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE) ) - { -#if MALI_TRACEPOINTS_ENABLED - //TODO magic numbers should come from mali_linux_trace.h instead - unsigned int counter = (core->core_number * 2) + 9; -#endif - - job200->perf_counter0 = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_VALUE); - job200->perf_counter1 = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_VALUE); - -#if MALI_TRACEPOINTS_ENABLED - _mali_profiling_add_counter(counter, job200->perf_counter0); - _mali_profiling_add_counter(counter + 1, job200->perf_counter1); -#endif - - } - -#if defined(USING_MALI400_L2_CACHE) - if (job200->user_input.perf_counter_flag & (_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE|_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE) ) - { - u32 src0; - u32 val0; - u32 src1; - u32 val1; - mali_kernel_l2_cache_get_perf_counters(&src0, &val0, &src1, &val1); - - if (job200->perf_counter_l2_src0 == src0) - { - job200->perf_counter_l2_val0_raw = val0; - job200->perf_counter_l2_val0 = val0 - job200->perf_counter_l2_val0; - } - else - { - job200->perf_counter_l2_val0_raw = 0; - job200->perf_counter_l2_val0 = 0; - } - - if (job200->perf_counter_l2_src1 == src1) - { - job200->perf_counter_l2_val1_raw = val1; - job200->perf_counter_l2_val1 = val1 - job200->perf_counter_l2_val1; - } - else - { - job200->perf_counter_l2_val1_raw = 0; - job200->perf_counter_l2_val1 = 0; - } - -#if MALI_TRACEPOINTS_ENABLED - //TODO magic numbers should come from mali_linux_trace.h instead - _mali_profiling_add_counter(5, val0); - _mali_profiling_add_counter(6, val1); -#endif - } -#endif - - } - -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_number), - job200->perf_counter0, job200->perf_counter1, - job200->user_input.perf_counter_src0 | (job200->user_input.perf_counter_src1 << 8) -#if defined(USING_MALI400_L2_CACHE) - | (job200->user_input.perf_counter_l2_src0 << 16) | (job200->user_input.perf_counter_l2_src1 << 24), - job200->perf_counter_l2_val0, job200->perf_counter_l2_val1 -#else - , 0, 0 -#endif - ); -#endif - - -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&job->session->jobs_ended); -#endif - - pr_debug("SPI_GPU_PP%u Idle\n", core->core_number); - - return JOB_STATUS_END_SUCCESS; /* reschedule */ - } - /* Overall SW watchdog timeout or (time to do hang checking and progress detected)? */ - else if ( - (CORE_WATCHDOG_TIMEOUT == core->state) || - ((CORE_HANG_CHECK_TIMEOUT == core->state) && (current_tile_addr == job200->last_tile_list_addr)) - ) - { -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_number), 0, 0, 0, 0, 0); /* add GP and L2 counters and return status */ -#endif - /* no progress detected, killed by the watchdog */ - MALI_PRINT( ("M200: SW-Timeout Rawstat: 0x%x Tile_addr: 0x%x Status: 0x%x.\n", irq_readout ,current_tile_addr ,core_status) ); - /* In this case will the system outside cleanup and reset the core */ - - MALI_PANIC("%s Watchdog timeout (rawstat: 0x%x tile_addr: 0x%x status: 0x%x)\n", MALI_PP_SUBSYSTEM_NAME, irq_readout, current_tile_addr, core_status); - -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&job->session->jobs_ended); -#endif - - return JOB_STATUS_END_HANG; - } - /* HW watchdog triggered or an existing hang check passed? */ - else if ((CORE_HANG_CHECK_TIMEOUT == core->state) || (irq_readout & job200->active_mask & MALI200_REG_VAL_IRQ_HANG)) - { - /* check interval in ms */ - u32 timeout = mali_core_hang_check_timeout_get(); - MALI_PRINT( ("M200: HW/SW Watchdog triggered, checking for progress in %d ms\n", timeout)); - job200->last_tile_list_addr = current_tile_addr; - /* hw watchdog triggered, set up a progress checker every HANGCHECK ms */ - _mali_osk_timer_add(core->timer_hang_detection, _mali_osk_time_mstoticks(timeout)); - job200->active_mask &= ~MALI200_REG_VAL_IRQ_HANG; /* ignore the hw watchdoig from now on */ - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_CLEAR, irq_readout & ~MALI200_REG_VAL_IRQ_HANG); - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, job200->active_mask); - return JOB_STATUS_CONTINUE_RUN; /* not finished */ - } - /* No irq pending, core still busy */ - else if ((0 == (irq_readout & MALI200_REG_VAL_IRQ_MASK_USED)) && ( 0 != (core_status & MALI200_REG_VAL_STATUS_RENDERING_ACTIVE))) - { - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_CLEAR, irq_readout); - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, job200->active_mask); - return JOB_STATUS_CONTINUE_RUN; /* Not finished */ - } - else - { -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_number), 0, 0, 0, 0, 0); /* add GP and L2 counters and return status */ -#endif - - MALI_PRINT( ("Mali PP: Job: 0x%08x CRASH? Rawstat: 0x%x Tile_addr: 0x%x Status: 0x%x\n", - (u32)job200->user_input.user_job_ptr, irq_readout ,current_tile_addr ,core_status) ) ; - - if (irq_readout & MALI200_REG_VAL_IRQ_BUS_ERROR) - { - u32 bus_error = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_BUS_ERROR_STATUS); - - MALI_PRINT(("Bus error status: 0x%08X\n", bus_error)); - MALI_DEBUG_PRINT_IF(1, (bus_error & 0x01), ("Bus write error from id 0x%02x\n", (bus_error>>2) & 0x0F)); - MALI_DEBUG_PRINT_IF(1, (bus_error & 0x02), ("Bus read error from id 0x%02x\n", (bus_error>>6) & 0x0F)); - MALI_DEBUG_PRINT_IF(1, (0 == (bus_error & 0x03)), ("Bus error but neither read or write was set as the error reason\n")); - (void)bus_error; - } - -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&job->session->jobs_ended); -#endif - return JOB_STATUS_END_UNKNOWN_ERR; /* reschedule */ - } -} - - -/* This function is called from the ioctl function and should return a mali_core_job pointer -to a created mali_core_job object with the data given from userspace */ -static _mali_osk_errcode_t subsystem_mali200_get_new_job_from_user(struct mali_core_session * session, void * argument) -{ - mali200_job *job200; - mali_core_job *job = NULL; - mali_core_job *previous_replaced_job; - _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; - _mali_uk_pp_start_job_s * user_ptr_job_input; - - user_ptr_job_input = (_mali_uk_pp_start_job_s *)argument; - - MALI_CHECK_NON_NULL(job200 = (mali200_job *) _mali_osk_malloc(sizeof(mali200_job)), _MALI_OSK_ERR_NOMEM); - _mali_osk_memset(job200, 0 , sizeof(mali200_job) ); - - /* We read job data from Userspace pointer */ - if ( NULL == _mali_osk_memcpy((void*)&job200->user_input, user_ptr_job_input, sizeof(job200->user_input)) ) - { - MALI_PRINT_ERROR( ("Mali PP: Could not copy data from U/K interface.\n")) ; - err = _MALI_OSK_ERR_FAULT; - goto function_exit; - } - - MALI_DEBUG_PRINT(5, ("Mali PP: subsystem_mali200_get_new_job_from_user 0x%x\n", (void*)job200->user_input.user_job_ptr)); - - MALI_DEBUG_PRINT(5, ("Mali PP: Frameregs: 0x%x 0x%x 0x%x Writeback[1] 0x%x, Pri:%d; Watchd:%d\n", - job200->user_input.frame_registers[0], job200->user_input.frame_registers[1], job200->user_input.frame_registers[2], - job200->user_input.wb0_registers[1], job200->user_input.priority, - job200->user_input.watchdog_msecs)); - - if ( job200->user_input.perf_counter_flag) - { -#if defined(USING_MALI400_L2_CACHE) - MALI_DEBUG_PRINT(5, ("Mali PP: Performance counters: flag:0x%x src0:0x%x src1:0x%x l2_src0:0x%x l2_src1:0x%x\n", - job200->user_input.perf_counter_flag, - job200->user_input.perf_counter_src0, - job200->user_input.perf_counter_src1, - job200->user_input.perf_counter_l2_src0, - job200->user_input.perf_counter_l2_src1)); -#else - MALI_DEBUG_PRINT(5, ("Mali PP: Performance counters: flag:0x%x src0:0x%x src1:0x%x\n", - job200->user_input.perf_counter_flag, - job200->user_input.perf_counter_src0, - job200->user_input.perf_counter_src1)); -#endif - } - - job = GET_JOB_EMBEDDED_PTR(job200); - - job->session = session; - job->flags = user_ptr_job_input->flags; - job_priority_set(job, job200->user_input.priority); - job_watchdog_set(job, job200->user_input.watchdog_msecs ); - -#if MALI_TIMELINE_PROFILING_ENABLED - job200->pid = _mali_osk_get_pid(); - job200->tid = _mali_osk_get_tid(); -#endif - - job->abort_id = job200->user_input.abort_id; - if (mali_job_queue_full(session)) - { - user_ptr_job_input->status = _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE; - goto function_exit; - } - - /* We now know that we has a job, and a empty session slot to put it in */ - - job200->active_mask = MALI200_REG_VAL_IRQ_MASK_USED; - - /* Allocating User Return Data */ - job200->notification_obj = _mali_osk_notification_create( - _MALI_NOTIFICATION_PP_FINISHED, - sizeof(_mali_uk_pp_job_finished_s) ); - - if ( NULL == job200->notification_obj ) - { - MALI_PRINT_ERROR( ("Mali PP: Could not get notification_obj.\n")) ; - err = _MALI_OSK_ERR_NOMEM; - goto function_exit; - } - - _MALI_OSK_INIT_LIST_HEAD( &(job->list) ) ; - - MALI_DEBUG_PRINT(4, ("Mali PP: Job: 0x%08x INPUT from user.\n", (u32)job200->user_input.user_job_ptr)) ; - - /* This should not happen since we have the checking of priority above */ - if ( _MALI_OSK_ERR_OK != mali_core_session_add_job(session, job, &previous_replaced_job)) - { - MALI_PRINT_ERROR( ("Mali PP: Internal error\n")) ; - user_ptr_job_input->status = _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE; - _mali_osk_notification_delete( job200->notification_obj ); - goto function_exit; - } - - /* If MALI_TRUE: This session had a job with lower priority which were removed. - This replaced job is given back to userspace. */ - if ( NULL != previous_replaced_job ) - { - mali200_job *previous_replaced_job200; - - previous_replaced_job200 = GET_JOB200_PTR(previous_replaced_job); - - MALI_DEBUG_PRINT(4, ("Mali PP: Replacing job: 0x%08x\n", (u32)previous_replaced_job200->user_input.user_job_ptr)) ; - - /* Copy to the input data (which also is output data) the - pointer to the job that were replaced, so that the userspace - driver can put this job in the front of its job-queue */ - - user_ptr_job_input->returned_user_job_ptr = previous_replaced_job200->user_input.user_job_ptr; - - /** @note failure to 'copy to user' at this point must not free job200, - * and so no transaction rollback required in the U/K interface */ - - /* This does not cause job200 to free: */ - user_ptr_job_input->status = _MALI_UK_START_JOB_STARTED_LOW_PRI_JOB_RETURNED; - MALI_DEBUG_PRINT(5, ("subsystem_mali200_get_new_job_from_user: Job added, prev returned\n")) ; - } - else - { - /* This does not cause job200 to free: */ - user_ptr_job_input->status = _MALI_UK_START_JOB_STARTED; - MALI_DEBUG_PRINT(5, ("subsystem_mali200_get_new_job_from_user: Job added\n")) ; - } - -function_exit: - if (_MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE == user_ptr_job_input->status - || _MALI_OSK_ERR_OK != err ) - { - _mali_osk_free(job200); - } -#if MALI_STATE_TRACKING - if (_MALI_UK_START_JOB_STARTED==user_ptr_job_input->status) - { - if(job) - { - job->job_nr=_mali_osk_atomic_inc_return(&session->jobs_received); - } - } -#endif - - MALI_ERROR(err); -} - -/* This function is called from the ioctl function and should write the necessary data -to userspace telling which job was finished and the status and debuginfo for this job. -The function must also free and cleanup the input job object. */ -static void subsystem_mali200_return_job_to_user( mali_core_job * job, mali_subsystem_job_end_code end_status) -{ - mali200_job *job200; - _mali_uk_pp_job_finished_s * job_out; - _mali_uk_pp_start_job_s * job_input; - mali_core_session *session; - - if (NULL == job) - { - MALI_DEBUG_PRINT(1, ("subsystem_mali200_return_job_to_user received a NULL ptr\n")); - return; - } - - job200 = _MALI_OSK_CONTAINER_OF(job, mali200_job, embedded_core_job); - - if (NULL == job200->notification_obj) - { - MALI_DEBUG_PRINT(1, ("Found job200 with NULL notification object, abandoning userspace sending\n")); - return; - } - - job_out = job200->notification_obj->result_buffer; - job_input= &(job200->user_input); - session = job->session; - - MALI_DEBUG_PRINT(4, ("Mali PP: Job: 0x%08x OUTPUT to user. Runtime: %dus\n", - (u32)job200->user_input.user_job_ptr, - job->render_time_usecs)) ; - - _mali_osk_memset(job_out, 0 , sizeof(_mali_uk_pp_job_finished_s)); - - job_out->user_job_ptr = job_input->user_job_ptr; - - switch( end_status ) - { - case JOB_STATUS_CONTINUE_RUN: - case JOB_STATUS_END_SUCCESS: - case JOB_STATUS_END_OOM: - case JOB_STATUS_END_ABORT: - case JOB_STATUS_END_TIMEOUT_SW: - case JOB_STATUS_END_HANG: - case JOB_STATUS_END_SEG_FAULT: - case JOB_STATUS_END_ILLEGAL_JOB: - case JOB_STATUS_END_UNKNOWN_ERR: - case JOB_STATUS_END_SHUTDOWN: - case JOB_STATUS_END_SYSTEM_UNUSABLE: - job_out->status = (mali_subsystem_job_end_code) end_status; - break; - - default: - job_out->status = JOB_STATUS_END_UNKNOWN_ERR ; - } - job_out->irq_status = job200->irq_status; - job_out->perf_counter0 = job200->perf_counter0; - job_out->perf_counter1 = job200->perf_counter1; - job_out->render_time = job->render_time_usecs; - -#if defined(USING_MALI400_L2_CACHE) - job_out->perf_counter_l2_src0 = job200->perf_counter_l2_src0; - job_out->perf_counter_l2_src1 = job200->perf_counter_l2_src1; - job_out->perf_counter_l2_val0 = job200->perf_counter_l2_val0; - job_out->perf_counter_l2_val1 = job200->perf_counter_l2_val1; - job_out->perf_counter_l2_val0_raw = job200->perf_counter_l2_val0_raw; - job_out->perf_counter_l2_val1_raw = job200->perf_counter_l2_val1_raw; -#endif - -#if MALI_STATE_TRACKING - _mali_osk_atomic_inc(&session->jobs_returned); -#endif - _mali_osk_notification_queue_send( session->notification_queue, job200->notification_obj); - job200->notification_obj = NULL; - - _mali_osk_free(job200); -} - -static void subsystem_mali200_renderunit_delete(mali_core_renderunit * core) -{ - MALI_DEBUG_PRINT(5, ("Mali PP: mali200_renderunit_delete\n")); - _mali_osk_free(core); -} - -static void mali200_reset_hard(struct mali_core_renderunit * core) -{ - const int reset_finished_loop_count = 15; - const u32 reset_wait_target_register = MALI200_REG_ADDR_MGMT_WRITE_BOUNDARY_LOW; - const u32 reset_invalid_value = 0xC0FFE000; - const u32 reset_check_value = 0xC01A0000; - const u32 reset_default_value = 0; - int i; - - MALI_DEBUG_PRINT(5, ("subsystem_mali200_renderunit_reset_core_hard called for core %s\n", core->description)); - - mali_core_renderunit_register_write(core, reset_wait_target_register, reset_invalid_value); - - mali_core_renderunit_register_write( - core, - MALI200_REG_ADDR_MGMT_CTRL_MGMT, - MALI200_REG_VAL_CTRL_MGMT_FORCE_RESET); - - for (i = 0; i < reset_finished_loop_count; i++) - { - mali_core_renderunit_register_write(core, reset_wait_target_register, reset_check_value); - if (reset_check_value == mali_core_renderunit_register_read(core, reset_wait_target_register)) - { - MALI_DEBUG_PRINT(5, ("Reset loop exiting after %d iterations\n", i)); - break; - } - _mali_osk_time_ubusydelay(10); - } - - if (i == reset_finished_loop_count) - { - MALI_DEBUG_PRINT(1, ("The reset loop didn't work\n")); - } - - mali_core_renderunit_register_write(core, reset_wait_target_register, reset_default_value); /* set it back to the default */ - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI200_REG_VAL_IRQ_MASK_ALL); -} - -static void subsystem_mali200_renderunit_reset_core(struct mali_core_renderunit * core, mali_core_reset_style style) -{ - MALI_DEBUG_PRINT(5, ("Mali PP: renderunit_reset_core\n")); - - switch (style) - { - case MALI_CORE_RESET_STYLE_RUNABLE: - mali200_reset(core); - break; - case MALI_CORE_RESET_STYLE_DISABLE: - mali200_raw_reset(core); /* do the raw reset */ - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, 0); /* then disable the IRQs */ - break; - case MALI_CORE_RESET_STYLE_HARD: - mali200_reset_hard(core); - break; - default: - MALI_DEBUG_PRINT(1, ("Unknown reset type %d\n", style)); - } -} - -static void subsystem_mali200_renderunit_probe_core_irq_trigger(struct mali_core_renderunit* core) -{ - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_USED); - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT, MALI200_REG_VAL_IRQ_FORCE_HANG); - _mali_osk_mem_barrier(); -} - -static _mali_osk_errcode_t subsystem_mali200_renderunit_probe_core_irq_finished(struct mali_core_renderunit* core) -{ - u32 irq_readout; - - irq_readout = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_INT_STATUS); - - if ( MALI200_REG_VAL_IRQ_FORCE_HANG & irq_readout ) - { - mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI200_REG_VAL_IRQ_FORCE_HANG); - _mali_osk_mem_barrier(); - MALI_SUCCESS; - } - - MALI_ERROR(_MALI_OSK_ERR_FAULT); -} - -_mali_osk_errcode_t _mali_ukk_pp_start_job( _mali_uk_pp_start_job_s *args ) -{ - mali_core_session * session; - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - session = (mali_core_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_mali200_id); - MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_FAULT); - return mali_core_subsystem_ioctl_start_job(session, args); -} - -_mali_osk_errcode_t _mali_ukk_get_pp_number_of_cores( _mali_uk_get_pp_number_of_cores_s *args ) -{ - mali_core_session * session; - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - session = (mali_core_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_mali200_id); - MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_FAULT); - return mali_core_subsystem_ioctl_number_of_cores_get(session, &args->number_of_cores); -} - -_mali_osk_errcode_t _mali_ukk_get_pp_core_version( _mali_uk_get_pp_core_version_s *args ) -{ - mali_core_session * session; - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - session = (mali_core_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_mali200_id); - MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_FAULT); - return mali_core_subsystem_ioctl_core_version_get(session, &args->version); -} - -void _mali_ukk_pp_abort_job( _mali_uk_pp_abort_job_s * args) -{ - mali_core_session * session; - MALI_DEBUG_ASSERT_POINTER(args); - if (NULL == args->ctx) return; - session = (mali_core_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_mali200_id); - if (NULL == session) return; - mali_core_subsystem_ioctl_abort_job(session, args->abort_id); - -} - -#if USING_MALI_PMM - -_mali_osk_errcode_t malipp_signal_power_up( u32 core_num, mali_bool queue_only ) -{ - MALI_DEBUG_PRINT(4, ("Mali PP: signal power up core: %d - queue_only: %d\n", core_num, queue_only )); - - return( mali_core_subsystem_signal_power_up( &subsystem_mali200, core_num, queue_only ) ); -} - -_mali_osk_errcode_t malipp_signal_power_down( u32 core_num, mali_bool immediate_only ) -{ - MALI_DEBUG_PRINT(4, ("Mali PP: signal power down core: %d - immediate_only: %d\n", core_num, immediate_only )); - - return( mali_core_subsystem_signal_power_down( &subsystem_mali200, core_num, immediate_only ) ); -} - -#endif - -#if MALI_STATE_TRACKING -u32 mali200_subsystem_dump_state(char *buf, u32 size) -{ - return mali_core_renderunit_dump_state(&subsystem_mali200, buf, size); -} -#endif diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_common.h b/drivers/media/video/samsung/mali/common/mali_kernel_common.h index ab6f143..b354f92 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_common.h +++ b/drivers/media/video/samsung/mali/common/mali_kernel_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010, 2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -28,7 +28,6 @@ #define MALI_PANIC(fmt, args...) #endif - /* The file include several useful macros for error checking, debugging and printing. * - MALI_PRINTF(...) Do not use this function: Will be included in Release builds. * - MALI_DEBUG_PRINT(nr, (X) ) Prints the second argument if nr<=MALI_DEBUG_LEVEL. @@ -129,7 +128,9 @@ } while (0) #ifdef DEBUG +#ifndef mali_debug_level extern int mali_debug_level; +#endif #define MALI_DEBUG_CODE(code) code #define MALI_DEBUG_PRINT(level, args) do { \ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_core.c b/drivers/media/video/samsung/mali/common/mali_kernel_core.c index be1889d..0155dfc 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_core.c +++ b/drivers/media/video/samsung/mali/common/mali_kernel_core.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -8,344 +8,805 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "mali_kernel_subsystem.h" -#include "mali_kernel_mem.h" -#include "mali_kernel_session_manager.h" -#include "mali_kernel_pp.h" -#include "mali_kernel_gp.h" +#include "mali_kernel_common.h" +#include "mali_session.h" #include "mali_osk.h" #include "mali_osk_mali.h" #include "mali_ukk.h" #include "mali_kernel_core.h" -#include "mali_kernel_rendercore.h" -#if defined USING_MALI400_L2_CACHE -#include "mali_kernel_l2_cache.h" +#include "mali_memory.h" +#include "mali_mem_validation.h" +#include "mali_mmu.h" +#include "mali_mmu_page_directory.h" +#include "mali_dlbu.h" +#include "mali_gp.h" +#include "mali_pp.h" +#include "mali_gp_scheduler.h" +#include "mali_pp_scheduler.h" +#include "mali_cluster.h" +#include "mali_group.h" +#include "mali_pm.h" +#include "mali_pmu.h" +#include "mali_scheduler.h" +#ifdef CONFIG_MALI400_GPU_UTILIZATION +#include "mali_kernel_utilization.h" +#endif +#include "mali_l2_cache.h" +#if MALI_TIMELINE_PROFILING_ENABLED +#include "mali_osk_profiling.h" #endif -#if USING_MALI_PMM -#include "mali_pmm.h" -#endif /* USING_MALI_PMM */ - -/* platform specific set up */ -#include "mali_platform.h" - -/* Initialized when this subsystem is initialized. This is determined by the - * position in subsystems[], and so the value used to initialize this is - * determined at compile time */ -static mali_kernel_subsystem_identifier mali_subsystem_core_id = -1; /** Pointer to table of resource definitions available to the Mali driver. * _mali_osk_resources_init() sets up the pointer to this table. */ static _mali_osk_resource_t *arch_configuration = NULL; +/** Start profiling from module load? */ +int mali_boot_profiling = 0; + /** Number of resources initialized by _mali_osk_resources_init() */ static u32 num_resources; -static _mali_osk_errcode_t register_resources( _mali_osk_resource_t **arch_configuration, u32 num_resources ); - -static _mali_osk_errcode_t initialize_subsystems(void); -static void terminate_subsystems(void); - -static _mali_osk_errcode_t mali_kernel_subsystem_core_setup(mali_kernel_subsystem_identifier id); -static void mali_kernel_subsystem_core_cleanup(mali_kernel_subsystem_identifier id); -static _mali_osk_errcode_t mali_kernel_subsystem_core_system_info_fill(_mali_system_info* info); -static _mali_osk_errcode_t mali_kernel_subsystem_core_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue); +static _mali_product_id_t global_product_id = _MALI_PRODUCT_ID_UNKNOWN; +static u32 global_gpu_base_address = 0; +static u32 global_gpu_major_version = 0; +static u32 global_gpu_minor_version = 0; static _mali_osk_errcode_t build_system_info(void); static void cleanup_system_info(_mali_system_info *cleanup); -/** - * @brief handler for MEM_VALIDATION resources - * - * This resource handler is common to all memory systems. It provides a default - * means for validating requests to map in external memory via - * _mali_ukk_map_external_mem. In addition, if _mali_ukk_va_to_pa is - * implemented, then _mali_ukk_va_to_pa can make use of this MEM_VALIDATION - * resource. - * - * MEM_VALIDATION also provide a CPU physical to Mali physical address - * translation, for use by _mali_ukk_map_external_mem. - * - * @note MEM_VALIDATION resources are only to handle simple cases where a - * certain physical address range is allowed to be mapped in by any process, - * e.g. a framebuffer at a fixed location. If the implementor has more complex - * mapping requirements, then they must either: - * - implement their own memory validation function - * - or, integrate with UMP. - * - * @param resource The resource to handle (type MEM_VALIDATION) - * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. - */ -static _mali_osk_errcode_t mali_kernel_core_resource_mem_validation(_mali_osk_resource_t * resource); - -/* MEM_VALIDATION handler state */ -typedef struct -{ - u32 phys_base; /**< Mali physical base of the memory, page aligned */ - u32 size; /**< size in bytes of the memory, multiple of page size */ - s32 cpu_usage_adjust; /**< Offset to add to Mali Physical address to obtain CPU physical address */ -} _mali_mem_validation_t; +/* system info variables */ +static _mali_osk_lock_t *system_info_lock = NULL; +static _mali_system_info *system_info = NULL; +static u32 system_info_size = 0; +static u32 first_pp_offset = 0; -#define INVALID_MEM 0xffffffff +#define HANG_CHECK_MSECS_DEFAULT 500 /* 500 ms */ +#define WATCHDOG_MSECS_DEFAULT 4000 /* 4 s */ -static _mali_mem_validation_t mem_validator = { INVALID_MEM, INVALID_MEM, -1 }; +/* timer related */ +int mali_max_job_runtime = WATCHDOG_MSECS_DEFAULT; +int mali_hang_check_interval = HANG_CHECK_MSECS_DEFAULT; -static struct mali_kernel_subsystem mali_subsystem_core = +static _mali_osk_resource_t *mali_find_resource(_mali_osk_resource_type_t type, u32 offset) { - mali_kernel_subsystem_core_setup, /* startup */ - mali_kernel_subsystem_core_cleanup, /* shutdown */ - NULL, /* load_complete */ - mali_kernel_subsystem_core_system_info_fill, /* system_info_fill */ - mali_kernel_subsystem_core_session_begin, /* session_begin */ - NULL, /* session_end */ - NULL, /* broadcast_notification */ -#if MALI_STATE_TRACKING - NULL, /* dump_state */ -#endif -}; + int i; + u32 addr = global_gpu_base_address + offset; -static struct mali_kernel_subsystem * subsystems[] = -{ + for (i = 0; i < num_resources; i++) + { + if (type == arch_configuration[i].type && arch_configuration[i].base == addr) + { + return &(arch_configuration[i]); + } + } -#if USING_MALI_PMM - /* The PMM must be initialized before any cores - including L2 cache */ - &mali_subsystem_pmm, -#endif + return NULL; +} - /* always included */ - &mali_subsystem_memory, +static u32 mali_count_resources(_mali_osk_resource_type_t type) +{ + int i; + u32 retval = 0; - /* The rendercore subsystem must be initialized before any subsystem based on the - * rendercores is started e.g. mali_subsystem_mali200 and mali_subsystem_gp2 */ - &mali_subsystem_rendercore, + for (i = 0; i < num_resources; i++) + { + if (type == arch_configuration[i].type) + { + retval++; + } + } - /* add reference to the subsystem */ - &mali_subsystem_mali200, + return retval; +} - /* add reference to the subsystem */ - &mali_subsystem_gp2, -#if defined USING_MALI400_L2_CACHE - &mali_subsystem_l2_cache, -#endif +static _mali_osk_errcode_t mali_parse_gpu_base_and_first_pp_offset_address(void) +{ + int i; + _mali_osk_resource_t *first_gp_resource = NULL; + _mali_osk_resource_t *first_pp_resource = NULL; + + for (i = 0; i < num_resources; i++) + { + if (MALI_GP == arch_configuration[i].type) + { + if (NULL == first_gp_resource || first_gp_resource->base > arch_configuration[i].base) + { + first_gp_resource = &(arch_configuration[i]); + } + } + if (MALI_PP == arch_configuration[i].type) + { + if (NULL == first_pp_resource || first_pp_resource->base > arch_configuration[i].base) + { + first_pp_resource = &(arch_configuration[i]); + } + } + } - /* always included */ - /* NOTE Keep the core entry at the tail of the list */ - &mali_subsystem_core -}; + if (NULL == first_gp_resource || NULL == first_pp_resource) + { + MALI_PRINT_ERROR(("No GP+PP core specified in config file\n")); + return _MALI_OSK_ERR_FAULT; + } -#define SUBSYSTEMS_COUNT ( sizeof(subsystems) / sizeof(subsystems[0]) ) + if (first_gp_resource->base < first_pp_resource->base) + { + /* GP is first, so we are dealing with Mali-300, Mali-400 or Mali-450 */ + global_gpu_base_address = first_gp_resource->base; + first_pp_offset = 0x8000; + } + else + { + /* PP is first, so we are dealing with Mali-200 */ + global_gpu_base_address = first_pp_resource->base; + first_pp_offset = 0x0; + } + MALI_SUCCESS; +} -/* Pointers to this type available as incomplete struct in mali_kernel_session_manager.h */ -struct mali_session_data +static _mali_osk_errcode_t mali_parse_product_info(void) { - void * subsystem_data[SUBSYSTEMS_COUNT]; - _mali_osk_notification_queue_t * ioctl_queue; -}; + _mali_osk_resource_t *first_pp_resource = NULL; -static mali_kernel_resource_registrator resource_handler[RESOURCE_TYPE_COUNT] = { NULL, }; + /* Find the first PP core */ + first_pp_resource = mali_find_resource(MALI_PP, first_pp_offset); + if (NULL != first_pp_resource) + { + /* Create a dummy PP object for this core so that we can read the version register */ + struct mali_group *group = mali_group_create(NULL, NULL); + if (NULL != group) + { + /*struct mali_pp_core *pp_core = mali_pp_create(first_pp_resource, group, 0);*/ + struct mali_pp_core *pp_core = mali_pp_create(first_pp_resource, group); + if (NULL != pp_core) + { + u32 pp_version = mali_pp_core_get_version(pp_core); + mali_pp_delete(pp_core); + mali_group_delete(group); + + global_gpu_major_version = (pp_version >> 8) & 0xFF; + global_gpu_minor_version = pp_version & 0xFF; + + switch (pp_version >> 16) + { + case MALI200_PP_PRODUCT_ID: + global_product_id = _MALI_PRODUCT_ID_MALI200; + MALI_DEBUG_PRINT(2, ("Found Mali GPU Mali-200 r%up%u\n", global_gpu_major_version, global_gpu_minor_version)); + break; + case MALI300_PP_PRODUCT_ID: + global_product_id = _MALI_PRODUCT_ID_MALI300; + MALI_DEBUG_PRINT(2, ("Found Mali GPU Mali-300 r%up%u\n", global_gpu_major_version, global_gpu_minor_version)); + break; + case MALI400_PP_PRODUCT_ID: + global_product_id = _MALI_PRODUCT_ID_MALI400; + MALI_DEBUG_PRINT(2, ("Found Mali GPU Mali-400 MP r%up%u\n", global_gpu_major_version, global_gpu_minor_version)); + break; + case MALI450_PP_PRODUCT_ID: + global_product_id = _MALI_PRODUCT_ID_MALI450; + MALI_DEBUG_PRINT(2, ("Found Mali GPU Mali-450 MP r%up%u\n", global_gpu_major_version, global_gpu_minor_version)); + break; + default: + MALI_DEBUG_PRINT(2, ("Found unknown Mali GPU GPU (r%up%u)\n", global_gpu_major_version, global_gpu_minor_version)); + return _MALI_OSK_ERR_FAULT; + } + + return _MALI_OSK_ERR_OK; + } + else + { + MALI_PRINT_ERROR(("Failed to create initial PP object\n")); + } + } + else + { + MALI_PRINT_ERROR(("Failed to create initial group object\n")); + } + } + else + { + MALI_PRINT_ERROR(("First PP core not specified in config file\n")); + } -/* system info variables */ -static _mali_osk_lock_t *system_info_lock = NULL; -static _mali_system_info * system_info = NULL; -static u32 system_info_size = 0; + return _MALI_OSK_ERR_FAULT; +} -/* is called from OS specific driver entry point */ -_mali_osk_errcode_t mali_kernel_constructor( void ) +static void mali_delete_clusters(void) { - _mali_osk_errcode_t err; - - err = mali_platform_init(); - if (_MALI_OSK_ERR_OK != err) goto error1; + u32 i; + u32 number_of_clusters = mali_cluster_get_glob_num_clusters(); - err = _mali_osk_init(); - if (_MALI_OSK_ERR_OK != err) goto error2; + for (i = 0; i < number_of_clusters; i++) + { + mali_cluster_delete(mali_cluster_get_global_cluster(i)); + } +} - MALI_DEBUG_PRINT(2, ("\n")); - MALI_DEBUG_PRINT(2, ("Inserting Mali v%d device driver. \n",_MALI_API_VERSION)); - MALI_DEBUG_PRINT(2, ("Compiled: %s, time: %s.\n", __DATE__, __TIME__)); - MALI_DEBUG_PRINT(2, ("Svn revision: %s\n", SVN_REV_STRING)); +static _mali_osk_errcode_t mali_create_cluster(_mali_osk_resource_t *resource) +{ + if (NULL != resource) + { + struct mali_l2_cache_core *l2_cache; - err = initialize_subsystems(); - if (_MALI_OSK_ERR_OK != err) goto error3; + if (mali_l2_cache_core_get_glob_num_l2_cores() >= mali_l2_cache_core_get_max_num_l2_cores()) + { + MALI_PRINT_ERROR(("Found too many L2 cache core objects, max %u is supported\n", mali_l2_cache_core_get_max_num_l2_cores())); + return _MALI_OSK_ERR_FAULT; + } - MALI_PRINT(("Mali device driver %s loaded\n", SVN_REV_STRING)); + MALI_DEBUG_PRINT(3, ("Found L2 cache %s, starting new cluster\n", resource->description)); - MALI_SUCCESS; + /*l2_cache = mali_l2_cache_create(resource, global_num_l2_cache_cores);*/ + l2_cache = mali_l2_cache_create(resource); + if (NULL == l2_cache) + { + MALI_PRINT_ERROR(("Failed to create L2 cache object\n")); + return _MALI_OSK_ERR_FAULT; + } -error3: - MALI_PRINT(("Mali subsystems failed\n")); - _mali_osk_term(); -error2: - MALI_PRINT(("Mali device driver init failed\n")); - if (_MALI_OSK_ERR_OK != mali_platform_deinit()) + if (NULL == mali_cluster_create(l2_cache)) + { + MALI_PRINT_ERROR(("Failed to create cluster object\n")); + mali_l2_cache_delete(l2_cache); + return _MALI_OSK_ERR_FAULT; + } + } + else { - MALI_PRINT(("Failed to deinit platform\n")); + mali_cluster_create(NULL); + if (NULL == mali_cluster_get_global_cluster(0)) + { + MALI_PRINT_ERROR(("Failed to create cluster object\n")); + return _MALI_OSK_ERR_FAULT; + } } -error1: - MALI_PRINT(("Failed to init platform\n")); - MALI_ERROR(err); + + MALI_DEBUG_PRINT(3, ("Created cluster object\n")); + return _MALI_OSK_ERR_OK; } -/* is called from OS specific driver exit point */ -void mali_kernel_destructor( void ) +static _mali_osk_errcode_t mali_parse_config_cluster(void) { - MALI_DEBUG_PRINT(2, ("\n")); - MALI_DEBUG_PRINT(2, ("Unloading Mali v%d device driver.\n",_MALI_API_VERSION)); -#if USING_MALI_PMM - malipmm_force_powerup(); -#endif - terminate_subsystems(); /* subsystems are responsible for their registered resources */ - _mali_osk_term(); - - if (_MALI_OSK_ERR_OK != mali_platform_deinit()) + if (_MALI_PRODUCT_ID_MALI200 == global_product_id) { - MALI_PRINT(("Failed to deinit platform\n")); + /* Create dummy cluster without L2 cache */ + return mali_create_cluster(NULL); } - MALI_DEBUG_PRINT(2, ("Module unloaded.\n")); -} + else if (_MALI_PRODUCT_ID_MALI300 == global_product_id || _MALI_PRODUCT_ID_MALI400 == global_product_id) + { + _mali_osk_resource_t *l2_resource = mali_find_resource(MALI_L2, 0x1000); + if (NULL == l2_resource) + { + MALI_DEBUG_PRINT(3, ("Did not find required Mali L2 cache in config file\n")); + return _MALI_OSK_ERR_FAULT; + } -_mali_osk_errcode_t register_resources( _mali_osk_resource_t **arch_configuration, u32 num_resources ) -{ - _mali_osk_resource_t *arch_resource = *arch_configuration; - u32 i; -#if USING_MALI_PMM - u32 is_pmu_first_resource = 1; -#endif /* USING_MALI_PMM */ - - /* loop over arch configuration */ - for (i = 0; i < num_resources; ++i, arch_resource++) - { - if ( (arch_resource->type >= RESOURCE_TYPE_FIRST) && - (arch_resource->type < RESOURCE_TYPE_COUNT) && - (NULL != resource_handler[arch_resource->type]) - ) - { -#if USING_MALI_PMM - if((arch_resource->type != PMU) && (is_pmu_first_resource == 1)) + return mali_create_cluster(l2_resource); + } + else if (_MALI_PRODUCT_ID_MALI450 == global_product_id) + { + /* + * L2 for GP at 0x10000 + * L2 for PP0-3 at 0x01000 + * L2 for PP4-7 at 0x11000 (optional) + */ + + _mali_osk_resource_t *l2_gp_resource; + _mali_osk_resource_t *l2_pp_grp0_resource; + _mali_osk_resource_t *l2_pp_grp1_resource; + + /* Make cluster for GP's L2 */ + l2_gp_resource = mali_find_resource(MALI_L2, 0x10000); + if (NULL != l2_gp_resource) + { + _mali_osk_errcode_t ret; + MALI_DEBUG_PRINT(3, ("Creating Mali-450 cluster for GP\n")); + ret = mali_create_cluster(l2_gp_resource); + if (_MALI_OSK_ERR_OK != ret) { - _mali_osk_resource_t mali_pmu_virtual_resource; - mali_pmu_virtual_resource.type = PMU; - mali_pmu_virtual_resource.description = "Virtual PMU"; - mali_pmu_virtual_resource.base = 0x00000000; - mali_pmu_virtual_resource.cpu_usage_adjust = 0; - mali_pmu_virtual_resource.size = 0; - mali_pmu_virtual_resource.irq = 0; - mali_pmu_virtual_resource.flags = 0; - mali_pmu_virtual_resource.mmu_id = 0; - mali_pmu_virtual_resource.alloc_order = 0; - MALI_CHECK_NO_ERROR(resource_handler[mali_pmu_virtual_resource.type](&mali_pmu_virtual_resource)); + return ret; } - is_pmu_first_resource = 0; -#endif /* USING_MALI_PMM */ + } + else + { + MALI_DEBUG_PRINT(3, ("Did not find required Mali L2 cache for GP in config file\n")); + return _MALI_OSK_ERR_FAULT; + } - MALI_CHECK_NO_ERROR(resource_handler[arch_resource->type](arch_resource)); - /* the subsystem shutdown process will release all the resources already registered */ + /* Make cluster for first PP core group */ + l2_pp_grp0_resource = mali_find_resource(MALI_L2, 0x1000); + if (NULL != l2_pp_grp0_resource) + { + _mali_osk_errcode_t ret; + MALI_DEBUG_PRINT(3, ("Creating Mali-450 cluster for PP group 0\n")); + ret = mali_create_cluster(l2_pp_grp0_resource); + if (_MALI_OSK_ERR_OK != ret) + { + return ret; + } } else { - MALI_DEBUG_PRINT(1, ("No handler installed for resource %s, type %d\n", arch_resource->description, arch_resource->type)); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); + MALI_DEBUG_PRINT(3, ("Did not find required Mali L2 cache for PP group 0 in config file\n")); + return _MALI_OSK_ERR_FAULT; + } + + /* Second PP core group is optional, don't fail if we don't find it */ + l2_pp_grp1_resource = mali_find_resource(MALI_L2, 0x11000); + if (NULL != l2_pp_grp1_resource) + { + _mali_osk_errcode_t ret; + MALI_DEBUG_PRINT(3, ("Creating Mali-450 cluster for PP group 0\n")); + ret = mali_create_cluster(l2_pp_grp1_resource); + if (_MALI_OSK_ERR_OK != ret) + { + return ret; + } } } - MALI_SUCCESS; + return _MALI_OSK_ERR_OK; } -static _mali_osk_errcode_t initialize_subsystems(void) +static _mali_osk_errcode_t mali_create_group(struct mali_cluster *cluster, + _mali_osk_resource_t *resource_mmu, + _mali_osk_resource_t *resource_gp, + _mali_osk_resource_t *resource_pp) { - int i, j; - _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; /* default error code */ + struct mali_mmu_core *mmu; + struct mali_group *group; + struct mali_pp_core *pp; - MALI_CHECK_NON_NULL(system_info_lock = _mali_osk_lock_init( (_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_SPINLOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE), 0, 0 ), _MALI_OSK_ERR_FAULT); + MALI_DEBUG_PRINT(3, ("Starting new group for MMU %s\n", resource_mmu->description)); - for (i = 0; i < (int)SUBSYSTEMS_COUNT; ++i) + /* Create the MMU object */ + mmu = mali_mmu_create(resource_mmu); + if (NULL == mmu) { - if (NULL != subsystems[i]->startup) + MALI_PRINT_ERROR(("Failed to create MMU object\n")); + return _MALI_OSK_ERR_FAULT; + } + + /* Create the group object */ + group = mali_group_create(cluster, mmu); + if (NULL == group) + { + MALI_PRINT_ERROR(("Failed to create group object for MMU %s\n", resource_mmu->description)); + mali_mmu_delete(mmu); + return _MALI_OSK_ERR_FAULT; + } + + /* Set pointer back to group in mmu.*/ + mali_mmu_set_group(mmu, group); + + /* Add this group to current cluster */ + mali_cluster_add_group(cluster, group); + + if (NULL != resource_gp) + { + /* Create the GP core object inside this group */ + /* global_gp_core = mali_gp_create(resource_gp, group); */ + if (NULL == mali_gp_create(resource_gp, group)) { - /* the subsystem has a startup function defined */ - err = subsystems[i]->startup(i); /* the subsystem identifier is the offset in our subsystems array */ - if (_MALI_OSK_ERR_OK != err) goto cleanup; + /* No need to clean up now, as we will clean up everything linked in from the cluster when we fail this function */ + MALI_PRINT_ERROR(("Failed to create GP object\n")); + return _MALI_OSK_ERR_FAULT; } + + /* Add GP object to this group */ + MALI_DEBUG_PRINT(3, ("Adding GP %s to group\n", resource_gp->description)); + mali_group_add_gp_core(group, mali_gp_get_global_gp_core()); } - for (j = 0; j < (int)SUBSYSTEMS_COUNT; ++j) + if (NULL != resource_pp) { - if (NULL != subsystems[j]->load_complete) + /* Create the PP core object inside this group */ + pp = mali_pp_create(resource_pp, group); + + if (NULL == pp) { - /* the subsystem has a load_complete function defined */ - err = subsystems[j]->load_complete(j); - if (_MALI_OSK_ERR_OK != err) goto cleanup; + /* No need to clean up now, as we will clean up everything linked in from the cluster when we fail this function */ + MALI_PRINT_ERROR(("Failed to create PP object\n")); + return _MALI_OSK_ERR_FAULT; } + + /* Add PP object to this group */ + MALI_DEBUG_PRINT(3, ("Adding PP %s to group\n", resource_pp->description)); + mali_group_add_pp_core(group, pp); } - /* All systems loaded and resources registered */ - /* Build system info */ - if (_MALI_OSK_ERR_OK != build_system_info()) goto cleanup; + return _MALI_OSK_ERR_OK; +} + +static _mali_osk_errcode_t mali_parse_config_groups(void) +{ + if (_MALI_PRODUCT_ID_MALI200 == global_product_id) + { + _mali_osk_resource_t *resource_gp; + _mali_osk_resource_t *resource_pp; + _mali_osk_resource_t *resource_mmu; + + MALI_DEBUG_ASSERT(1 == mali_cluster_get_glob_num_clusters()); - MALI_SUCCESS; /* all ok */ + resource_gp = mali_find_resource(MALI_GP, 0x02000); + resource_pp = mali_find_resource(MALI_PP, 0x00000); + resource_mmu = mali_find_resource(MMU, 0x03000); -cleanup: - /* i is index of subsystem which failed to start, all indices before that has to be shut down */ - for (i = i - 1; i >= 0; --i) + if (NULL == resource_mmu || NULL == resource_gp || NULL == resource_pp) + { + /* Missing mandatory core(s) */ + return _MALI_OSK_ERR_FAULT; + } + + /*return mali_create_group(global_clusters[0], resource_mmu, resource_gp, resource_pp);*/ + return mali_create_group(mali_cluster_get_global_cluster(0), resource_mmu, resource_gp, resource_pp); + } + else if (_MALI_PRODUCT_ID_MALI300 == global_product_id || + _MALI_PRODUCT_ID_MALI400 == global_product_id || + _MALI_PRODUCT_ID_MALI450 == global_product_id) { - /* the subsystem identifier is the offset in our subsystems array */ - /* Call possible shutdown notficiation functions */ - if (NULL != subsystems[i]->shutdown) subsystems[i]->shutdown(i); + _mali_osk_errcode_t err; + int cluster_id_gp = 0; + int cluster_id_pp_grp0 = 0; + int cluster_id_pp_grp1 = 0; + int i; + _mali_osk_resource_t *resource_gp; + _mali_osk_resource_t *resource_gp_mmu; + _mali_osk_resource_t *resource_pp[mali_pp_get_max_num_pp_cores()]; + _mali_osk_resource_t *resource_pp_mmu[mali_pp_get_max_num_pp_cores()]; + u32 max_num_pp_cores = mali_pp_get_max_num_pp_cores(); + + if (_MALI_PRODUCT_ID_MALI450 == global_product_id) + { + /* Mali-450 has separate L2s for GP, and PP core group(s) */ + cluster_id_pp_grp0 = 1; + cluster_id_pp_grp1 = 2; + } + + resource_gp = mali_find_resource(MALI_GP, 0x00000); + resource_gp_mmu = mali_find_resource(MMU, 0x03000); + resource_pp[0] = mali_find_resource(MALI_PP, 0x08000); + resource_pp[1] = mali_find_resource(MALI_PP, 0x0A000); + resource_pp[2] = mali_find_resource(MALI_PP, 0x0C000); + resource_pp[3] = mali_find_resource(MALI_PP, 0x0E000); + resource_pp[4] = mali_find_resource(MALI_PP, 0x28000); + resource_pp[5] = mali_find_resource(MALI_PP, 0x2A000); + resource_pp[6] = mali_find_resource(MALI_PP, 0x2C000); + resource_pp[7] = mali_find_resource(MALI_PP, 0x2E000); + resource_pp_mmu[0] = mali_find_resource(MMU, 0x04000); + resource_pp_mmu[1] = mali_find_resource(MMU, 0x05000); + resource_pp_mmu[2] = mali_find_resource(MMU, 0x06000); + resource_pp_mmu[3] = mali_find_resource(MMU, 0x07000); + resource_pp_mmu[4] = mali_find_resource(MMU, 0x1C000); + resource_pp_mmu[5] = mali_find_resource(MMU, 0x1D000); + resource_pp_mmu[6] = mali_find_resource(MMU, 0x1E000); + resource_pp_mmu[7] = mali_find_resource(MMU, 0x1F000); + + if (NULL == resource_gp || NULL == resource_gp_mmu || NULL == resource_pp[0] || NULL == resource_pp_mmu[0]) + { + /* Missing mandatory core(s) */ + MALI_DEBUG_PRINT(2, ("Missing mandatory resource, need at least one GP and one PP, both with a separate MMU (0x%08X, 0x%08X, 0x%08X, 0x%08X)\n", + resource_gp, resource_gp_mmu, resource_pp[0], resource_pp_mmu[0])); + return _MALI_OSK_ERR_FAULT; + } + + MALI_DEBUG_ASSERT(1 <= mali_cluster_get_glob_num_clusters()); + err = mali_create_group(mali_cluster_get_global_cluster(cluster_id_gp), resource_gp_mmu, resource_gp, NULL); + if (err != _MALI_OSK_ERR_OK) + { + return err; + } + + /* Create group for first (and mandatory) PP core */ + MALI_DEBUG_ASSERT(mali_cluster_get_glob_num_clusters() >= (cluster_id_pp_grp0 + 1)); /* >= 1 on Mali-300 and Mali-400, >= 2 on Mali-450 */ + err = mali_create_group(mali_cluster_get_global_cluster(cluster_id_pp_grp0), resource_pp_mmu[0], NULL, resource_pp[0]); + if (err != _MALI_OSK_ERR_OK) + { + return err; + } + + /* Create groups for rest of the cores in the first PP core group */ + for (i = 1; i < 4; i++) /* First half of the PP cores belong to first core group */ + { + if (NULL != resource_pp[i]) + { + err = mali_create_group(mali_cluster_get_global_cluster(cluster_id_pp_grp0), resource_pp_mmu[i], NULL, resource_pp[i]); + if (err != _MALI_OSK_ERR_OK) + { + return err; + } + } + } + + /* Create groups for cores in the second PP core group */ + for (i = 4; i < max_num_pp_cores; i++) /* Second half of the PP cores belong to second core group */ + { + if (NULL != resource_pp[i]) + { + MALI_DEBUG_ASSERT(mali_cluster_get_glob_num_clusters() >= 2); /* Only Mali-450 have more than 4 PPs, and these cores belong to second core group */ + err = mali_create_group(mali_cluster_get_global_cluster(cluster_id_pp_grp1), resource_pp_mmu[i], NULL, resource_pp[i]); + if (err != _MALI_OSK_ERR_OK) + { + return err; + } + } + } } - _mali_osk_lock_term( system_info_lock ); - MALI_ERROR(err); /* err is what the module which failed its startup returned, or the default */ + return _MALI_OSK_ERR_OK; } -static void terminate_subsystems(void) +static _mali_osk_errcode_t mali_parse_config_pmu(void) { - int i; - /* shut down subsystems in reverse order from startup */ - for (i = SUBSYSTEMS_COUNT - 1; i >= 0; --i) + _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; + _mali_osk_resource_t *resource_pmu; + u32 number_of_pp_cores; + u32 number_of_l2_caches; + + resource_pmu = mali_find_resource(PMU, 0x02000); + number_of_pp_cores = mali_count_resources(MALI_PP); + number_of_l2_caches = mali_count_resources(MALI_L2); + + if (NULL != resource_pmu) { - /* the subsystem identifier is the offset in our subsystems array */ - if (NULL != subsystems[i]->shutdown) subsystems[i]->shutdown(i); + if (NULL == mali_pmu_create(resource_pmu, number_of_pp_cores, number_of_l2_caches)) + { + err = _MALI_OSK_ERR_FAULT; + } } - if (system_info_lock) _mali_osk_lock_term( system_info_lock ); - - /* Free _mali_system_info struct */ - cleanup_system_info(system_info); + return err; } -void _mali_kernel_core_broadcast_subsystem_message(mali_core_notification_message message, u32 data) +static _mali_osk_errcode_t mali_parse_config_memory(void) { int i; + _mali_osk_errcode_t ret; - for (i = 0; i < (int)SUBSYSTEMS_COUNT; ++i) + for(i = 0; i < num_resources; i++) { - if (NULL != subsystems[i]->broadcast_notification) + switch(arch_configuration[i].type) { - subsystems[i]->broadcast_notification(message, data); + case OS_MEMORY: + ret = mali_memory_core_resource_os_memory(&arch_configuration[i]); + if (_MALI_OSK_ERR_OK != ret) + { + MALI_PRINT_ERROR(("Failed to register OS_MEMORY\n")); + mali_memory_terminate(); + return ret; + } + break; + case MEMORY: + ret = mali_memory_core_resource_dedicated_memory(&arch_configuration[i]); + if (_MALI_OSK_ERR_OK != ret) + { + MALI_PRINT_ERROR(("Failed to register MEMORY\n")); + mali_memory_terminate(); + return ret; + } + break; + case MEM_VALIDATION: + ret = mali_mem_validation_add_range(&arch_configuration[i]); + if (_MALI_OSK_ERR_OK != ret) + { + MALI_PRINT_ERROR(("Failed to register MEM_VALIDATION\n")); + mali_memory_terminate(); + return ret; + } + break; + default: + break; } } + return _MALI_OSK_ERR_OK; } -static _mali_osk_errcode_t mali_kernel_subsystem_core_setup(mali_kernel_subsystem_identifier id) +_mali_osk_errcode_t mali_initialize_subsystems(void) { - mali_subsystem_core_id = id; + _mali_osk_errcode_t err; + mali_bool is_pmu_enabled; - /* Register our own resources */ - MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(MEM_VALIDATION, mali_kernel_core_resource_mem_validation)); + MALI_CHECK_NON_NULL(system_info_lock = _mali_osk_lock_init( (_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_SPINLOCK + | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE), 0, 0 ), _MALI_OSK_ERR_FAULT); - /* parse the arch resource definition and tell all the subsystems */ - /* this is why the core subsystem has to be specified last in the subsystem array */ - MALI_CHECK_NO_ERROR(_mali_osk_resources_init(&arch_configuration, &num_resources)); + err = mali_session_initialize(); + if (_MALI_OSK_ERR_OK != err) goto session_init_failed; - MALI_CHECK_NO_ERROR(register_resources(&arch_configuration, num_resources)); +#if MALI_TIMELINE_PROFILING_ENABLED + err = _mali_osk_profiling_init(mali_boot_profiling ? MALI_TRUE : MALI_FALSE); + if (_MALI_OSK_ERR_OK != err) + { + /* No biggie if we wheren't able to initialize the profiling */ + MALI_PRINT_ERROR(("Failed to initialize profiling, feature will be unavailable\n")); + } +#endif - /* resource parsing succeeded and the subsystem have corretly accepted their resources */ - MALI_SUCCESS; + /* Build dummy system info. Will be removed in the future. */ + err = build_system_info(); + if (_MALI_OSK_ERR_OK != err) goto build_system_info_failed; + + /* Get data from config.h */ + err = _mali_osk_resources_init(&arch_configuration, &num_resources); + if (_MALI_OSK_ERR_OK != err) goto osk_resources_init_failed; + + /* Initialize driver subsystems */ + err = mali_memory_initialize(); + if (_MALI_OSK_ERR_OK != err) goto memory_init_failed; + + /* Configure memory early. Memory allocation needed for mali_mmu_initialize. */ + err = mali_parse_config_memory(); + if (_MALI_OSK_ERR_OK != err) goto parse_memory_config_failed; + + /* Parsing the GPU base address and first pp offset */ + err = mali_parse_gpu_base_and_first_pp_offset_address(); + if (_MALI_OSK_ERR_OK != err) goto parse_gpu_base_address_failed; + + /* Initialize the MALI PMU */ + err = mali_parse_config_pmu(); + if (_MALI_OSK_ERR_OK != err) goto parse_pmu_config_failed; + + is_pmu_enabled = mali_pmu_get_global_pmu_core() != NULL ? MALI_TRUE : MALI_FALSE; + + /* Initialize the power management module */ + err = mali_pm_initialize(); + if (_MALI_OSK_ERR_OK != err) goto pm_init_failed; + + /* Make sure the power stays on for the rest of this function */ + mali_pm_always_on(MALI_TRUE); + + /* Detect which Mali GPU we are dealing with */ + err = mali_parse_product_info(); + if (_MALI_OSK_ERR_OK != err) goto product_info_parsing_failed; + + /* The global_product_id is now populated with the correct Mali GPU */ + + /* Initialize MMU module */ + err = mali_mmu_initialize(); + if (_MALI_OSK_ERR_OK != err) goto mmu_init_failed; + + /* Initialize the DLBU module for Mali-450 */ + if (_MALI_PRODUCT_ID_MALI450 == global_product_id) + { + err = mali_dlbu_initialize(); + if (_MALI_OSK_ERR_OK != err) goto dlbu_init_failed; + } + + /* Start configuring the actual Mali hardware. */ + err = mali_parse_config_cluster(); + if (_MALI_OSK_ERR_OK != err) goto config_parsing_failed; + err = mali_parse_config_groups(); + if (_MALI_OSK_ERR_OK != err) goto config_parsing_failed; + + /* Initialize the schedulers */ + err = mali_scheduler_initialize(); + if (_MALI_OSK_ERR_OK != err) goto scheduler_init_failed; + err = mali_gp_scheduler_initialize(); + if (_MALI_OSK_ERR_OK != err) goto gp_scheduler_init_failed; + err = mali_pp_scheduler_initialize(); + if (_MALI_OSK_ERR_OK != err) goto pp_scheduler_init_failed; + +#ifdef CONFIG_MALI400_GPU_UTILIZATION + /* Initialize the GPU utilization tracking */ + err = mali_utilization_init(); + if (_MALI_OSK_ERR_OK != err) goto utilization_init_failed; +#endif + + /* We no longer need to stay */ + mali_pm_always_on(MALI_FALSE); + MALI_SUCCESS; /* all ok */ + + /* Error handling */ +#ifdef CONFIG_MALI400_GPU_UTILIZATION +utilization_init_failed: + mali_pp_scheduler_terminate(); +#endif +pp_scheduler_init_failed: + mali_gp_scheduler_terminate(); +gp_scheduler_init_failed: + mali_scheduler_terminate(); +scheduler_init_failed: +config_parsing_failed: + mali_delete_clusters(); /* Delete clusters even if config parsing failed. */ + if (_MALI_PRODUCT_ID_MALI450 == global_product_id) + { + mali_dlbu_terminate(); + } +dlbu_init_failed: + mali_mmu_terminate(); +mmu_init_failed: + /* Nothing to roll back */ +product_info_parsing_failed: + mali_pm_terminate(); +pm_init_failed: + if (is_pmu_enabled) + { + mali_pmu_delete(mali_pmu_get_global_pmu_core()); + } +parse_pmu_config_failed: +parse_gpu_base_address_failed: +parse_memory_config_failed: + mali_memory_terminate(); +memory_init_failed: + _mali_osk_resources_term(&arch_configuration, num_resources); +osk_resources_init_failed: + cleanup_system_info(system_info); +build_system_info_failed: +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_term(); +#endif + mali_session_terminate(); +session_init_failed: + return err; +} + +void mali_terminate_subsystems(void) +{ + struct mali_pmu_core *pmu; + MALI_DEBUG_PRINT(2, ("terminate_subsystems() called\n")); + + /* shut down subsystems in reverse order from startup */ + + mali_pm_always_on(MALI_TRUE); /* Mali will be powered off once PM subsystem terminates */ + +#ifdef CONFIG_MALI400_GPU_UTILIZATION + mali_utilization_term(); +#endif + + mali_pp_scheduler_terminate(); + mali_gp_scheduler_terminate(); + mali_scheduler_terminate(); + + mali_delete_clusters(); /* Delete clusters even if config parsing failed. */ + + if (_MALI_PRODUCT_ID_MALI450 == global_product_id) + { + mali_dlbu_terminate(); + } + + mali_mmu_terminate(); + + pmu = mali_pmu_get_global_pmu_core(); + if (NULL != pmu) + { + mali_pmu_delete(pmu); + } + + mali_pm_terminate(); + + mali_memory_terminate(); + + _mali_osk_resources_term(&arch_configuration, num_resources); + + cleanup_system_info(system_info); + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_term(); +#endif + + mali_session_terminate(); + + if (NULL != system_info_lock) + { + _mali_osk_lock_term( system_info_lock ); + } +} + +_mali_product_id_t mali_kernel_core_get_product_id(void) +{ + return global_product_id; } -static void mali_kernel_subsystem_core_cleanup(mali_kernel_subsystem_identifier id) +void mali_kernel_core_wakeup(void) { - _mali_osk_resources_term(&arch_configuration, num_resources); + u32 i; + u32 glob_num_clusters = mali_cluster_get_glob_num_clusters(); + struct mali_cluster *cluster; + + for (i = 0; i < glob_num_clusters; i++) + { + cluster = mali_cluster_get_global_cluster(i); + mali_cluster_reset(cluster); + } } static void cleanup_system_info(_mali_system_info *cleanup) @@ -373,11 +834,10 @@ static void cleanup_system_info(_mali_system_info *cleanup) _mali_osk_free(cleanup); } +/* Build a dummy system info struct. User space still need this. */ static _mali_osk_errcode_t build_system_info(void) { - unsigned int i; - int err = _MALI_OSK_ERR_FAULT; - _mali_system_info * new_info, * cleanup; + _mali_system_info * new_info; _mali_core_info * current_core; _mali_mem_info * current_mem; u32 new_size = 0; @@ -387,19 +847,25 @@ static _mali_osk_errcode_t build_system_info(void) _mali_osk_memset(new_info, 0, sizeof(_mali_system_info)); - /* if an error happens during any of the system_info_fill calls cleanup the new info structs */ - cleanup = new_info; + /* fill in the info */ + new_info->has_mmu = 1; + new_info->drivermode = _MALI_DRIVER_MODE_NORMAL; - /* ask each subsystems to fill in their info */ - for (i = 0; i < SUBSYSTEMS_COUNT; ++i) + new_info->core_info = NULL; /* Not used by user space */ + + new_info->mem_info = _mali_osk_calloc(1, sizeof(_mali_mem_info)); + if(NULL == new_info->mem_info) { - if (NULL != subsystems[i]->system_info_fill) - { - err = subsystems[i]->system_info_fill(new_info); - if (_MALI_OSK_ERR_OK != err) goto error_exit; - } + _mali_osk_free(new_info); + return _MALI_OSK_ERR_NOMEM; } + new_info->mem_info->size = 1024 * 1024 * 1024; /* 1GiB */ + new_info->mem_info->flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE | _MALI_MMU_READABLE | _MALI_MMU_WRITEABLE; + new_info->mem_info->maximum_order_supported = 30; + new_info->mem_info->identifier = 0; + new_info->mem_info->next = NULL; + /* building succeeded, calculate the size */ /* size needed of the system info struct itself */ @@ -420,8 +886,6 @@ static _mali_osk_errcode_t build_system_info(void) /* lock system info access so a user wont't get a corrupted version */ _mali_osk_lock_wait( system_info_lock, _MALI_OSK_LOCKMODE_RW ); - /* cleanup the old one */ - cleanup = system_info; /* set new info */ system_info = new_info; system_info_size = new_size; @@ -430,25 +894,15 @@ static _mali_osk_errcode_t build_system_info(void) _mali_osk_lock_signal( system_info_lock, _MALI_OSK_LOCKMODE_RW ); /* ok result */ - err = _MALI_OSK_ERR_OK; - - /* we share the cleanup routine with the error case */ -error_exit: - if (NULL == cleanup) MALI_ERROR((_mali_osk_errcode_t)err); /* no cleanup needed, return what err contains */ - - /* cleanup */ - cleanup_system_info(cleanup); - - /* return whatever err is, we could end up here in both the error and success cases */ - MALI_ERROR((_mali_osk_errcode_t)err); + return _MALI_OSK_ERR_OK; } _mali_osk_errcode_t _mali_ukk_get_api_version( _mali_uk_get_api_version_s *args ) { - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - /* check compatability */ + /* check compatability */ if ( args->version == _MALI_UK_API_VERSION ) { args->compatible = 1; @@ -461,14 +915,14 @@ _mali_osk_errcode_t _mali_ukk_get_api_version( _mali_uk_get_api_version_s *args args->version = _MALI_UK_API_VERSION; /* report our version */ /* success regardless of being compatible or not */ - MALI_SUCCESS; + MALI_SUCCESS; } _mali_osk_errcode_t _mali_ukk_get_system_info_size(_mali_uk_get_system_info_size_s *args) { - MALI_DEBUG_ASSERT_POINTER(args); - args->size = system_info_size; - MALI_SUCCESS; + MALI_DEBUG_ASSERT_POINTER(args); + args->size = system_info_size; + MALI_SUCCESS; } _mali_osk_errcode_t _mali_ukk_get_system_info( _mali_uk_get_system_info_s *args ) @@ -477,12 +931,12 @@ _mali_osk_errcode_t _mali_ukk_get_system_info( _mali_uk_get_system_info_s *args _mali_mem_info * current_mem; _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; void * current_write_pos, ** current_patch_pos; - u32 adjust_ptr_base; + u32 adjust_ptr_base; /* check input */ MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - MALI_CHECK_NON_NULL(args->system_info, _MALI_OSK_ERR_INVALID_ARGS); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + MALI_CHECK_NON_NULL(args->system_info, _MALI_OSK_ERR_INVALID_ARGS); /* lock the system info */ _mali_osk_lock_wait( system_info_lock, _MALI_OSK_LOCKMODE_RW ); @@ -491,20 +945,20 @@ _mali_osk_errcode_t _mali_ukk_get_system_info( _mali_uk_get_system_info_s *args if (args->size < system_info_size) goto exit_when_locked; /* we build a copy of system_info in the user space buffer specified by the user and - * patch up the pointers. The ukk_private members of _mali_uk_get_system_info_s may - * indicate a different base address for patching the pointers (normally the - * address of the provided system_info buffer would be used). This is helpful when - * the system_info buffer needs to get copied to user space and the pointers need - * to be in user space. - */ - if (0 == args->ukk_private) - { - adjust_ptr_base = (u32)args->system_info; - } - else - { - adjust_ptr_base = args->ukk_private; - } + * patch up the pointers. The ukk_private members of _mali_uk_get_system_info_s may + * indicate a different base address for patching the pointers (normally the + * address of the provided system_info buffer would be used). This is helpful when + * the system_info buffer needs to get copied to user space and the pointers need + * to be in user space. + */ + if (0 == args->ukk_private) + { + adjust_ptr_base = (u32)args->system_info; + } + else + { + adjust_ptr_base = args->ukk_private; + } /* copy each struct into the buffer, and update its pointers */ current_write_pos = (void *)args->system_info; @@ -557,56 +1011,56 @@ _mali_osk_errcode_t _mali_ukk_get_system_info( _mali_uk_get_system_info_s *args err = _MALI_OSK_ERR_OK; exit_when_locked: _mali_osk_lock_signal( system_info_lock, _MALI_OSK_LOCKMODE_RW ); - MALI_ERROR(err); + MALI_ERROR(err); } _mali_osk_errcode_t _mali_ukk_wait_for_notification( _mali_uk_wait_for_notification_s *args ) { _mali_osk_errcode_t err; - _mali_osk_notification_t * notification; - _mali_osk_notification_queue_t *queue; + _mali_osk_notification_t *notification; + _mali_osk_notification_queue_t *queue; - /* check input */ + /* check input */ MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - queue = (_mali_osk_notification_queue_t *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_core_id); + queue = ((struct mali_session_data *)args->ctx)->ioctl_queue; /* if the queue does not exist we're currently shutting down */ if (NULL == queue) { MALI_DEBUG_PRINT(1, ("No notification queue registered with the session. Asking userspace to stop querying\n")); - args->type = _MALI_NOTIFICATION_CORE_SHUTDOWN_IN_PROGRESS; + args->type = _MALI_NOTIFICATION_CORE_SHUTDOWN_IN_PROGRESS; MALI_SUCCESS; } - /* receive a notification, might sleep */ + /* receive a notification, might sleep */ err = _mali_osk_notification_queue_receive(queue, ¬ification); if (_MALI_OSK_ERR_OK != err) { - MALI_ERROR(err); /* errcode returned, pass on to caller */ - } + MALI_ERROR(err); /* errcode returned, pass on to caller */ + } /* copy the buffer to the user */ - args->type = (_mali_uk_notification_type)notification->notification_type; - _mali_osk_memcpy(&args->data, notification->result_buffer, notification->result_buffer_size); + args->type = (_mali_uk_notification_type)notification->notification_type; + _mali_osk_memcpy(&args->data, notification->result_buffer, notification->result_buffer_size); /* finished with the notification */ _mali_osk_notification_delete( notification ); - MALI_SUCCESS; /* all ok */ + MALI_SUCCESS; /* all ok */ } _mali_osk_errcode_t _mali_ukk_post_notification( _mali_uk_post_notification_s *args ) { _mali_osk_notification_t * notification; - _mali_osk_notification_queue_t *queue; + _mali_osk_notification_queue_t *queue; - /* check input */ + /* check input */ MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - queue = (_mali_osk_notification_queue_t *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_core_id); + queue = ((struct mali_session_data *)args->ctx)->ioctl_queue; /* if the queue does not exist we're currently shutting down */ if (NULL == queue) @@ -618,294 +1072,115 @@ _mali_osk_errcode_t _mali_ukk_post_notification( _mali_uk_post_notification_s *a notification = _mali_osk_notification_create(args->type, 0); if ( NULL == notification) { - MALI_PRINT_ERROR( ("Failed to create notification object\n")) ; + MALI_PRINT_ERROR( ("Failed to create notification object\n")); return _MALI_OSK_ERR_NOMEM; } _mali_osk_notification_queue_send(queue, notification); - MALI_SUCCESS; /* all ok */ -} - -static _mali_osk_errcode_t mali_kernel_subsystem_core_system_info_fill(_mali_system_info* info) -{ - MALI_CHECK_NON_NULL(info, _MALI_OSK_ERR_INVALID_ARGS); - - info->drivermode = _MALI_DRIVER_MODE_NORMAL; - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_kernel_subsystem_core_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue) -{ - MALI_CHECK_NON_NULL(slot, _MALI_OSK_ERR_INVALID_ARGS); - *slot = queue; - MALI_SUCCESS; -} - -/* MEM_VALIDATION resource handler */ -static _mali_osk_errcode_t mali_kernel_core_resource_mem_validation(_mali_osk_resource_t * resource) -{ - /* Check that no other MEM_VALIDATION resources exist */ - MALI_CHECK( ((u32)-1) == mem_validator.phys_base, _MALI_OSK_ERR_FAULT ); - - /* Check restrictions on page alignment */ - MALI_CHECK( 0 == (resource->base & (~_MALI_OSK_CPU_PAGE_MASK)), _MALI_OSK_ERR_FAULT ); - MALI_CHECK( 0 == (resource->size & (~_MALI_OSK_CPU_PAGE_MASK)), _MALI_OSK_ERR_FAULT ); - MALI_CHECK( 0 == (resource->cpu_usage_adjust & (~_MALI_OSK_CPU_PAGE_MASK)), _MALI_OSK_ERR_FAULT ); - - mem_validator.phys_base = resource->base; - mem_validator.size = resource->size; - mem_validator.cpu_usage_adjust = resource->cpu_usage_adjust; - MALI_DEBUG_PRINT( 2, ("Memory Validator '%s' installed for Mali physical address base==0x%08X, size==0x%08X, cpu_adjust==0x%08X\n", - resource->description, mem_validator.phys_base, mem_validator.size, mem_validator.cpu_usage_adjust )); - MALI_SUCCESS; -} - -_mali_osk_errcode_t mali_kernel_core_translate_cpu_to_mali_phys_range( u32 *phys_base, u32 size ) -{ - u32 mali_phys_base; - - mali_phys_base = *phys_base - mem_validator.cpu_usage_adjust; - - MALI_CHECK( 0 == ( mali_phys_base & (~_MALI_OSK_CPU_PAGE_MASK)), _MALI_OSK_ERR_FAULT ); - MALI_CHECK( 0 == ( size & (~_MALI_OSK_CPU_PAGE_MASK)), _MALI_OSK_ERR_FAULT ); - - MALI_CHECK_NO_ERROR( mali_kernel_core_validate_mali_phys_range( mali_phys_base, size ) ); - - *phys_base = mali_phys_base; - MALI_SUCCESS; -} - -_mali_osk_errcode_t mali_kernel_core_validate_mali_phys_range( u32 phys_base, u32 size ) -{ - MALI_CHECK_GOTO( 0 == ( phys_base & (~_MALI_OSK_CPU_PAGE_MASK)), failure ); - MALI_CHECK_GOTO( 0 == ( size & (~_MALI_OSK_CPU_PAGE_MASK)), failure ); - - if ( phys_base >= mem_validator.phys_base - && (phys_base + size) >= mem_validator.phys_base - && phys_base <= (mem_validator.phys_base + mem_validator.size) - && (phys_base + size) <= (mem_validator.phys_base + mem_validator.size) ) - { - MALI_SUCCESS; - } - - failure: - MALI_PRINTF( ("*******************************************************************************\n") ); - MALI_PRINTF( ("MALI PHYSICAL RANGE VALIDATION ERROR!\n") ); - MALI_PRINTF( ("\n") ); - MALI_PRINTF( ("We failed to validate a Mali-Physical range that the user-side wished to map in\n") ); - MALI_PRINTF( ("\n") ); - MALI_PRINTF( ("It is likely that the user-side wished to do Direct Rendering, but a suitable\n") ); - MALI_PRINTF( ("address range validation mechanism has not been correctly setup\n") ); - MALI_PRINTF( ("\n") ); - MALI_PRINTF( ("The range supplied was: phys_base=0x%08X, size=0x%08X\n", phys_base, size) ); - MALI_PRINTF( ("\n") ); - MALI_PRINTF( ("Please refer to the ARM Mali Software Integration Guide for more information.\n") ); - MALI_PRINTF( ("\n") ); - MALI_PRINTF( ("*******************************************************************************\n") ); - - MALI_ERROR( _MALI_OSK_ERR_FAULT ); -} - - -_mali_osk_errcode_t _mali_kernel_core_register_resource_handler(_mali_osk_resource_type_t type, mali_kernel_resource_registrator handler) -{ - MALI_CHECK(type < RESOURCE_TYPE_COUNT, _MALI_OSK_ERR_INVALID_ARGS); - MALI_DEBUG_ASSERT(NULL == resource_handler[type]); /* A handler for resource already exists */ - resource_handler[type] = handler; - MALI_SUCCESS; -} - -void * mali_kernel_session_manager_slot_get(struct mali_session_data * session_data, int id) -{ - MALI_DEBUG_ASSERT_POINTER(session_data); - if(id >= SUBSYSTEMS_COUNT) { MALI_DEBUG_PRINT(3, ("mali_kernel_session_manager_slot_get: id %d out of range\n", id)); return NULL; } - - if (NULL == session_data) { MALI_DEBUG_PRINT(3, ("mali_kernel_session_manager_slot_get: got NULL session data\n")); return NULL; } - return session_data->subsystem_data[id]; + MALI_SUCCESS; /* all ok */ } _mali_osk_errcode_t _mali_ukk_open(void **context) { - int i; - _mali_osk_errcode_t err; - struct mali_session_data * session_data; + struct mali_session_data *session_data; /* allocated struct to track this session */ - session_data = (struct mali_session_data *)_mali_osk_malloc(sizeof(struct mali_session_data)); - MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_NOMEM); + session_data = (struct mali_session_data *)_mali_osk_calloc(1, sizeof(struct mali_session_data)); + MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_NOMEM); - _mali_osk_memset(session_data->subsystem_data, 0, sizeof(session_data->subsystem_data)); + MALI_DEBUG_PRINT(2, ("Session starting\n")); /* create a response queue for this session */ session_data->ioctl_queue = _mali_osk_notification_queue_init(); if (NULL == session_data->ioctl_queue) { _mali_osk_free(session_data); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); + MALI_ERROR(_MALI_OSK_ERR_NOMEM); } - MALI_DEBUG_PRINT(3, ("Session starting\n")); - - /* call session_begin on all subsystems */ - for (i = 0; i < (int)SUBSYSTEMS_COUNT; ++i) + session_data->page_directory = mali_mmu_pagedir_alloc(); + if (NULL == session_data->page_directory) { - if (NULL != subsystems[i]->session_begin) - { - /* subsystem has a session_begin */ - err = subsystems[i]->session_begin(session_data, &session_data->subsystem_data[i], session_data->ioctl_queue); - MALI_CHECK_GOTO(err == _MALI_OSK_ERR_OK, cleanup); - } + _mali_osk_notification_queue_term(session_data->ioctl_queue); + _mali_osk_free(session_data); + MALI_ERROR(_MALI_OSK_ERR_NOMEM); } - *context = (void*)session_data; + if (_MALI_OSK_ERR_OK != mali_mmu_pagedir_map(session_data->page_directory, MALI_DLB_VIRT_ADDR, _MALI_OSK_MALI_PAGE_SIZE)) + { + MALI_PRINT_ERROR(("Failed to map DLB page into session\n")); + _mali_osk_notification_queue_term(session_data->ioctl_queue); + _mali_osk_free(session_data); + MALI_ERROR(_MALI_OSK_ERR_NOMEM); + } - MALI_DEBUG_PRINT(3, ("Session started\n")); - MALI_SUCCESS; + if (0 != mali_dlbu_phys_addr) + { + mali_mmu_pagedir_update(session_data->page_directory, MALI_DLB_VIRT_ADDR, mali_dlbu_phys_addr, _MALI_OSK_MALI_PAGE_SIZE); + } -cleanup: - MALI_DEBUG_PRINT(2, ("Session startup failed\n")); - /* i is index of subsystem which failed session begin, all indices before that has to be ended */ - /* end subsystem sessions in the reverse order they where started in */ - for (i = i - 1; i >= 0; --i) + if (_MALI_OSK_ERR_OK != mali_memory_session_begin(session_data)) { - if (NULL != subsystems[i]->session_end) subsystems[i]->session_end(session_data, &session_data->subsystem_data[i]); + mali_mmu_pagedir_free(session_data->page_directory); + _mali_osk_notification_queue_term(session_data->ioctl_queue); + _mali_osk_free(session_data); + MALI_ERROR(_MALI_OSK_ERR_NOMEM); } - _mali_osk_notification_queue_term(session_data->ioctl_queue); - _mali_osk_free(session_data); + *context = (void*)session_data; - /* return what the subsystem which failed session start returned */ - MALI_ERROR(err); + /* Add session to the list of all sessions. */ + mali_session_add(session_data); + + MALI_DEBUG_PRINT(3, ("Session started\n")); + MALI_SUCCESS; } _mali_osk_errcode_t _mali_ukk_close(void **context) { - int i; - struct mali_session_data * session_data; + struct mali_session_data *session; + MALI_CHECK_NON_NULL(context, _MALI_OSK_ERR_INVALID_ARGS); + session = (struct mali_session_data *)*context; - MALI_CHECK_NON_NULL(context, _MALI_OSK_ERR_INVALID_ARGS); + MALI_DEBUG_PRINT(3, ("Session ending\n")); - session_data = (struct mali_session_data *)*context; + /* Remove session from list of all sessions. */ + mali_session_remove(session); - MALI_DEBUG_PRINT(2, ("Session ending\n")); + /* Abort queued and running jobs */ + mali_gp_scheduler_abort_session(session); + mali_pp_scheduler_abort_session(session); - /* end subsystem sessions in the reverse order they where started in */ - for (i = SUBSYSTEMS_COUNT - 1; i >= 0; --i) - { - if (NULL != subsystems[i]->session_end) subsystems[i]->session_end(session_data, &session_data->subsystem_data[i]); - } + /* Flush pending work. + * Needed to make sure all bottom half processing related to this + * session has been completed, before we free internal data structures. + */ + _mali_osk_flush_workqueue(NULL); - _mali_osk_notification_queue_term(session_data->ioctl_queue); - _mali_osk_free(session_data); + /* Free remaining memory allocated to this session */ + mali_memory_session_end(session); - *context = NULL; + /* Free session data structures */ + mali_mmu_pagedir_free(session->page_directory); + _mali_osk_notification_queue_term(session->ioctl_queue); + _mali_osk_free(session); - MALI_DEBUG_PRINT(2, ("Session has ended\n")); - - MALI_SUCCESS; -} + *context = NULL; -#if USING_MALI_PMM - -_mali_osk_errcode_t mali_core_signal_power_up( mali_pmm_core_id core, mali_bool queue_only ) -{ - switch( core ) - { - case MALI_PMM_CORE_GP: - MALI_CHECK_NO_ERROR(maligp_signal_power_up(queue_only)); - break; -#if defined USING_MALI400_L2_CACHE - case MALI_PMM_CORE_L2: - if( !queue_only ) - { - /* Enable L2 cache due to power up */ - mali_kernel_l2_cache_do_enable(); + MALI_DEBUG_PRINT(2, ("Session has ended\n")); - /* Invalidate the cache on power up */ - MALI_DEBUG_PRINT(5, ("L2 Cache: Invalidate all\n")); - MALI_CHECK_NO_ERROR(mali_kernel_l2_cache_invalidate_all()); - } - break; -#endif - case MALI_PMM_CORE_PP0: - MALI_CHECK_NO_ERROR(malipp_signal_power_up(0, queue_only)); - break; - case MALI_PMM_CORE_PP1: - MALI_CHECK_NO_ERROR(malipp_signal_power_up(1, queue_only)); - break; - case MALI_PMM_CORE_PP2: - MALI_CHECK_NO_ERROR(malipp_signal_power_up(2, queue_only)); - break; - case MALI_PMM_CORE_PP3: - MALI_CHECK_NO_ERROR(malipp_signal_power_up(3, queue_only)); - break; - default: - /* Unknown core */ - MALI_DEBUG_PRINT_ERROR( ("Unknown core signalled with power up: %d\n", core) ); - MALI_ERROR( _MALI_OSK_ERR_INVALID_ARGS ); - } - - MALI_SUCCESS; -} - -_mali_osk_errcode_t mali_core_signal_power_down( mali_pmm_core_id core, mali_bool immediate_only ) -{ - switch( core ) - { - case MALI_PMM_CORE_GP: - MALI_CHECK_NO_ERROR(maligp_signal_power_down(immediate_only)); - break; -#if defined USING_MALI400_L2_CACHE - case MALI_PMM_CORE_L2: - /* Nothing to do */ - break; -#endif - case MALI_PMM_CORE_PP0: - MALI_CHECK_NO_ERROR(malipp_signal_power_down(0, immediate_only)); - break; - case MALI_PMM_CORE_PP1: - MALI_CHECK_NO_ERROR(malipp_signal_power_down(1, immediate_only)); - break; - case MALI_PMM_CORE_PP2: - MALI_CHECK_NO_ERROR(malipp_signal_power_down(2, immediate_only)); - break; - case MALI_PMM_CORE_PP3: - MALI_CHECK_NO_ERROR(malipp_signal_power_down(3, immediate_only)); - break; - default: - /* Unknown core */ - MALI_DEBUG_PRINT_ERROR( ("Unknown core signalled with power down: %d\n", core) ); - MALI_ERROR( _MALI_OSK_ERR_INVALID_ARGS ); - } - MALI_SUCCESS; } -#endif - - #if MALI_STATE_TRACKING u32 _mali_kernel_core_dump_state(char* buf, u32 size) { - int i, n; - char *original_buf = buf; - for (i = 0; i < SUBSYSTEMS_COUNT; ++i) - { - if (NULL != subsystems[i]->dump_state) - { - n = subsystems[i]->dump_state(buf, size); - size -= n; - buf += n; - } - } -#if USING_MALI_PMM - n = mali_pmm_dump_os_thread_state(buf, size); - size -= n; - buf += n; -#endif - /* Return number of bytes written to buf */ - return (u32)(buf - original_buf); + int n = 0; /* Number of bytes written to buf */ + + n += mali_gp_scheduler_dump_state(buf + n, size - n); + n += mali_pp_scheduler_dump_state(buf + n, size - n); + + return n; } #endif diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_core.h b/drivers/media/video/samsung/mali/common/mali_kernel_core.h index 715c1cd..d424c48 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_core.h +++ b/drivers/media/video/samsung/mali/common/mali_kernel_core.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -13,122 +13,27 @@ #include "mali_osk.h" -#if USING_MALI_PMM -#include "mali_ukk.h" -#include "mali_pmm.h" -#include "mali_pmm_system.h" -#endif +extern int mali_hang_check_interval; +extern int mali_max_job_runtime; -_mali_osk_errcode_t mali_kernel_constructor( void ); -void mali_kernel_destructor( void ); +typedef enum +{ + _MALI_PRODUCT_ID_UNKNOWN, + _MALI_PRODUCT_ID_MALI200, + _MALI_PRODUCT_ID_MALI300, + _MALI_PRODUCT_ID_MALI400, + _MALI_PRODUCT_ID_MALI450, +} _mali_product_id_t; -/** - * @brief Tranlate CPU physical to Mali physical addresses. - * - * This function is used to convert CPU physical addresses to Mali Physical - * addresses, such that _mali_ukk_map_external_mem may be used to map them - * into Mali. This will be used by _mali_ukk_va_to_mali_pa. - * - * This function only supports physically contiguous regions. - * - * A default implementation is provided, which uses a registered MEM_VALIDATION - * resource to do a static translation. Only an address range which will lie - * in the range specified by MEM_VALIDATION will be successfully translated. - * - * If a more complex, or non-static translation is required, then the - * implementor has the following options: - * - Rewrite this function to provide such a translation - * - Integrate the provider of the memory with UMP. - * - * @param[in,out] phys_base pointer to the page-aligned base address of the - * physical range to be translated - * - * @param[in] size size of the address range to be translated, which must be a - * multiple of the physical page size. - * - * @return on success, _MALI_OSK_ERR_OK and *phys_base is translated. If the - * cpu physical address range is not in the valid range, then a suitable - * _mali_osk_errcode_t error. - * - */ -_mali_osk_errcode_t mali_kernel_core_translate_cpu_to_mali_phys_range( u32 *phys_base, u32 size ); - - -/** - * @brief Validate a Mali physical address range. - * - * This function is used to ensure that an address range passed to - * _mali_ukk_map_external_mem is allowed to be mapped into Mali. - * - * This function only supports physically contiguous regions. - * - * A default implementation is provided, which uses a registered MEM_VALIDATION - * resource to do a static translation. Only an address range which will lie - * in the range specified by MEM_VALIDATION will be successfully validated. - * - * If a more complex, or non-static validation is required, then the - * implementor has the following options: - * - Rewrite this function to provide such a validation - * - Integrate the provider of the memory with UMP. - * - * @param phys_base page-aligned base address of the Mali physical range to be - * validated. - * - * @param size size of the address range to be validated, which must be a - * multiple of the physical page size. - * - * @return _MALI_OSK_ERR_OK if the Mali physical range is valid. Otherwise, a - * suitable _mali_osk_errcode_t error. - * - */ -_mali_osk_errcode_t mali_kernel_core_validate_mali_phys_range( u32 phys_base, u32 size ); +_mali_osk_errcode_t mali_initialize_subsystems(void); -#if USING_MALI_PMM -/** - * @brief Signal a power up on a Mali core. - * - * This function flags a core as powered up. - * For PP and GP cores it calls functions that move the core from a power off - * queue into the idle queue ready to run jobs. It also tries to schedule any - * pending jobs to run on it. - * - * This function will fail if the core is not powered off - either running or - * already idle. - * - * @param core The PMM core id to power up. - * @param queue_only When MALI_TRUE only re-queue the core - do not reset. - * - * @return _MALI_OSK_ERR_OK if the core has been powered up. Otherwise a - * suitable _mali_osk_errcode_t error. - */ -_mali_osk_errcode_t mali_core_signal_power_up( mali_pmm_core_id core, mali_bool queue_only ); - -/** - * @brief Signal a power down on a Mali core. - * - * This function flags a core as powered down. - * For PP and GP cores it calls functions that move the core from an idle - * queue into the power off queue. - * - * This function will fail if the core is not idle - either running or - * already powered down. - * - * @param core The PMM core id to power up. - * @param immediate_only Do not set the core to pending power down if it can't - * power down immediately - * - * @return _MALI_OSK_ERR_OK if the core has been powered up. Otherwise a - * suitable _mali_osk_errcode_t error. - */ -_mali_osk_errcode_t mali_core_signal_power_down( mali_pmm_core_id core, mali_bool immediate_only ); +void mali_terminate_subsystems(void); -#endif +void mali_kernel_core_wakeup(void); -/** - * Flag to indicate whether or not mali_benchmark is turned on. - */ -extern int mali_benchmark; +_mali_product_id_t mali_kernel_core_get_product_id(void); +u32 _mali_kernel_core_dump_state(char* buf, u32 size); #endif /* __MALI_KERNEL_CORE_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_descriptor_mapping.c b/drivers/media/video/samsung/mali/common/mali_kernel_descriptor_mapping.c index 8b2a97d..b9f05ca 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_descriptor_mapping.c +++ b/drivers/media/video/samsung/mali/common/mali_kernel_descriptor_mapping.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010, 2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -40,11 +40,7 @@ mali_descriptor_mapping * mali_descriptor_mapping_create(int init_entries, int m map->table = descriptor_table_alloc(init_entries); if (NULL != map->table) { -#if !USING_MMU - map->lock = _mali_osk_lock_init( (_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_READERWRITER | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE), 0, 20); -#else - map->lock = _mali_osk_lock_init( (_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_READERWRITER | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE), 0, 116); -#endif + map->lock = _mali_osk_lock_init( (_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_READERWRITER | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE), 0, _MALI_OSK_LOCK_ORDER_DESCRIPTOR_MAP); if (NULL != map->lock) { _mali_osk_set_nonatomic_bit(0, map->table->usage); /* reserve bit 0 to prevent NULL/zero logic to kick in */ @@ -151,15 +147,20 @@ _mali_osk_errcode_t mali_descriptor_mapping_set(mali_descriptor_mapping * map, i MALI_ERROR(result); } -void mali_descriptor_mapping_free(mali_descriptor_mapping * map, int descriptor) +void *mali_descriptor_mapping_free(mali_descriptor_mapping * map, int descriptor) { + void *old_value = NULL; + _mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RW); if ( (descriptor >= 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage) ) { + old_value = map->table->mappings[descriptor]; map->table->mappings[descriptor] = NULL; _mali_osk_clear_nonatomic_bit(descriptor, map->table->usage); } _mali_osk_lock_signal(map->lock, _MALI_OSK_LOCKMODE_RW); + + return old_value; } static mali_descriptor_table * descriptor_table_alloc(int count) diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_descriptor_mapping.h b/drivers/media/video/samsung/mali/common/mali_kernel_descriptor_mapping.h index 745be92..82ed94d 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_descriptor_mapping.h +++ b/drivers/media/video/samsung/mali/common/mali_kernel_descriptor_mapping.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010, 2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -93,7 +93,9 @@ void mali_descriptor_mapping_call_for_each(mali_descriptor_mapping * map, void ( * For the descriptor to be reused it has to be freed * @param map The map to free the descriptor from * @param descriptor The descriptor ID to free + * + * @return old value of descriptor mapping */ -void mali_descriptor_mapping_free(mali_descriptor_mapping * map, int descriptor); +void *mali_descriptor_mapping_free(mali_descriptor_mapping * map, int descriptor); #endif /* __MALI_KERNEL_DESCRIPTOR_MAPPING_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_l2_cache.c b/drivers/media/video/samsung/mali/common/mali_kernel_l2_cache.c deleted file mode 100644 index e4d4ab1..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_l2_cache.c +++ /dev/null @@ -1,517 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "mali_kernel_common.h" -#include "mali_osk.h" -#include "mali_osk_list.h" - -#include "mali_kernel_core.h" -#include "mali_kernel_pp.h" -#include "mali_kernel_subsystem.h" -#include "regs/mali_200_regs.h" -#include "mali_kernel_rendercore.h" -#include "mali_kernel_l2_cache.h" - -/** - * Size of the Mali L2 cache registers in bytes - */ -#define MALI400_L2_CACHE_REGISTERS_SIZE 0x30 - -/** - * Mali L2 cache register numbers - * Used in the register read/write routines. - * See the hardware documentation for more information about each register - */ -typedef enum mali_l2_cache_register { - MALI400_L2_CACHE_REGISTER_STATUS = 0x0002, - /*unused = 0x0003 */ - MALI400_L2_CACHE_REGISTER_COMMAND = 0x0004, /**< Misc cache commands, e.g. clear */ - MALI400_L2_CACHE_REGISTER_CLEAR_PAGE = 0x0005, - MALI400_L2_CACHE_REGISTER_MAX_READS = 0x0006, /**< Limit of outstanding read requests */ - MALI400_L2_CACHE_REGISTER_ENABLE = 0x0007, /**< Enable misc cache features */ - MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0 = 0x0008, - MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0 = 0x0009, - MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1 = 0x000A, - MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1 = 0x000B, -} mali_l2_cache_register; - - -/** - * Mali L2 cache commands - * These are the commands that can be sent to the Mali L2 cache unit - */ -typedef enum mali_l2_cache_command -{ - MALI400_L2_CACHE_COMMAND_CLEAR_ALL = 0x01, /**< Clear the entire cache */ - /* Read HW TRM carefully before adding/using other commands than the clear above */ -} mali_l2_cache_command; - -/** - * Mali L2 cache commands - * These are the commands that can be sent to the Mali L2 cache unit - */ -typedef enum mali_l2_cache_enable -{ - MALI400_L2_CACHE_ENABLE_DEFAULT = 0x0, /**< Default state of enable register */ - MALI400_L2_CACHE_ENABLE_ACCESS = 0x01, /**< Permit cacheable accesses */ - MALI400_L2_CACHE_ENABLE_READ_ALLOCATE = 0x02, /**< Permit cache read allocate */ -} mali_l2_cache_enable; - -/** - * Mali L2 cache status bits - */ -typedef enum mali_l2_cache_status -{ - MALI400_L2_CACHE_STATUS_COMMAND_BUSY = 0x01, /**< Command handler of L2 cache is busy */ - MALI400_L2_CACHE_STATUS_DATA_BUSY = 0x02, /**< L2 cache is busy handling data requests */ -} mali_l2_cache_status; - - -/** - * Definition of the L2 cache core struct - * Used to track a L2 cache unit in the system. - * Contains information about the mapping of the registers - */ -typedef struct mali_kernel_l2_cache_core -{ - unsigned long base; /**< Physical address of the registers */ - mali_io_address mapped_registers; /**< Virtual mapping of the registers */ - u32 mapping_size; /**< Size of registers in bytes */ - _mali_osk_list_t list; /**< Used to link multiple cache cores into a list */ - _mali_osk_lock_t *lock; /**< Serialize all L2 cache commands */ -} mali_kernel_l2_cache_core; - - -#define MALI400_L2_MAX_READS_DEFAULT 0x1C - -int mali_l2_max_reads = MALI400_L2_MAX_READS_DEFAULT; - - -/** - * Mali L2 cache subsystem startup function - * Called by the driver core when the driver is loaded. - * - * @param id Identifier assigned by the core to the L2 cache subsystem - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_l2_cache_initialize(mali_kernel_subsystem_identifier id); - -/** - * Mali L2 cache subsystem shutdown function - * Called by the driver core when the driver is unloaded. - * Cleans up - * @param id Identifier assigned by the core to the L2 cache subsystem - */ -static void mali_l2_cache_terminate(mali_kernel_subsystem_identifier id); - -/** - * L2 cache subsystem complete notification function. - * Called by the driver core when all drivers have loaded and all resources has been registered - * @param id Identifier assigned by the core to the L2 cache subsystem - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_l2_cache_load_complete(mali_kernel_subsystem_identifier id); - -/** - * Mali L2 cache subsystem's notification handler for a Mali L2 cache resource instances. - * Registered with the core during startup. - * Called by the core for each Mali L2 cache described in the active architecture's config.h file. - * @param resource The resource to handle (type MALI400L2) - * @return 0 if the Mali L2 cache was found and initialized, negative on error - */ -static _mali_osk_errcode_t mali_l2_cache_core_create(_mali_osk_resource_t * resource); - -/** - * Write to a L2 cache register - * Writes the given value to the specified register - * @param unit The L2 cache to write to - * @param reg The register to write to - * @param val The value to write to the register - */ -static void mali_l2_cache_register_write(mali_kernel_l2_cache_core * unit, mali_l2_cache_register reg, u32 val); - - - -/** - * Invalidate specified L2 cache - * @param cache The L2 cache to invalidate - * @return 0 if Mali L2 cache was successfully invalidated, otherwise error - */ -static _mali_osk_errcode_t mali_kernel_l2_cache_invalidate_all_cache(mali_kernel_l2_cache_core *cache); - - -/* - The fixed Mali L2 cache system's mali subsystem interface implementation. - We currently handle module and session life-time management. -*/ -struct mali_kernel_subsystem mali_subsystem_l2_cache = -{ - mali_l2_cache_initialize, /**< startup */ - NULL, /*mali_l2_cache_terminate,*/ /**< shutdown */ - mali_l2_cache_load_complete, /**< load_complete */ - NULL, /**< system_info_fill */ - NULL, /**< session_begin */ - NULL, /**< session_end */ - NULL, /**< broadcast_notification */ -#if MALI_STATE_TRACKING - NULL, /**< dump_state */ -#endif -}; - - - -static _MALI_OSK_LIST_HEAD(caches_head); - - - - -/* called during module init */ -static _mali_osk_errcode_t mali_l2_cache_initialize(mali_kernel_subsystem_identifier id) -{ - _mali_osk_errcode_t err; - - MALI_IGNORE( id ); - - MALI_DEBUG_PRINT(2, ( "Mali L2 cache system initializing\n")); - - _MALI_OSK_INIT_LIST_HEAD(&caches_head); - - /* This will register the function for adding Mali L2 cache cores to the subsystem */ - err = _mali_kernel_core_register_resource_handler(MALI400L2, mali_l2_cache_core_create); - - MALI_ERROR(err); -} - - - -/* called if/when our module is unloaded */ -static void mali_l2_cache_terminate(mali_kernel_subsystem_identifier id) -{ - mali_kernel_l2_cache_core * cache, *temp_cache; - - MALI_DEBUG_PRINT(2, ( "Mali L2 cache system terminating\n")); - - /* loop over all L2 cache units and shut them down */ - _MALI_OSK_LIST_FOREACHENTRY( cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list ) - { - /* reset to defaults */ - mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_MAX_READS, (u32)MALI400_L2_MAX_READS_DEFAULT); - mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_ENABLE, (u32)MALI400_L2_CACHE_ENABLE_DEFAULT); - - /* remove from the list of cacges on the system */ - _mali_osk_list_del( &cache->list ); - - /* release resources */ - _mali_osk_mem_unmapioregion( cache->base, cache->mapping_size, cache->mapped_registers ); - _mali_osk_mem_unreqregion( cache->base, cache->mapping_size ); - _mali_osk_lock_term( cache->lock ); - _mali_osk_free( cache ); - - #if USING_MALI_PMM - /* Unregister the L2 cache with the PMM */ - malipmm_core_unregister( MALI_PMM_CORE_L2 ); - #endif - } -} - -static _mali_osk_errcode_t mali_l2_cache_core_create(_mali_osk_resource_t * resource) -{ - _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT ; - mali_kernel_l2_cache_core * cache = NULL; - - MALI_DEBUG_PRINT(2, ( "Creating Mali L2 cache: %s\n", resource->description)); - -#if USING_MALI_PMM - /* Register the L2 cache with the PMM */ - err = malipmm_core_register( MALI_PMM_CORE_L2 ); - if( _MALI_OSK_ERR_OK != err ) - { - MALI_DEBUG_PRINT(1, ( "Failed to register L2 cache unit with PMM")); - return err; - } -#endif - - err = _mali_osk_mem_reqregion( resource->base, MALI400_L2_CACHE_REGISTERS_SIZE, resource->description); - - MALI_CHECK_GOTO( _MALI_OSK_ERR_OK == err, err_cleanup_requestmem_failed); - - /* Reset error that might be passed out */ - err = _MALI_OSK_ERR_FAULT; - - cache = _mali_osk_malloc(sizeof(mali_kernel_l2_cache_core)); - - MALI_CHECK_GOTO( NULL != cache, err_cleanup); - - cache->lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_SPINLOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, 104 ); - - MALI_CHECK_GOTO( NULL != cache->lock, err_cleanup); - - /* basic setup */ - _MALI_OSK_INIT_LIST_HEAD(&cache->list); - - cache->base = resource->base; - cache->mapping_size = MALI400_L2_CACHE_REGISTERS_SIZE; - - /* map the registers */ - cache->mapped_registers = _mali_osk_mem_mapioregion( cache->base, cache->mapping_size, resource->description ); - - MALI_CHECK_GOTO( NULL != cache->mapped_registers, err_cleanup); - - /* Invalidate cache (just to keep it in a known state at startup) */ - err = mali_kernel_l2_cache_invalidate_all_cache(cache); - - MALI_CHECK_GOTO( _MALI_OSK_ERR_OK == err, err_cleanup); - - /* add to our list of L2 caches */ - _mali_osk_list_add( &cache->list, &caches_head ); - - MALI_SUCCESS; - -err_cleanup: - /* This cleanup used when resources have been requested successfully */ - - if ( NULL != cache ) - { - if (NULL != cache->mapped_registers) - { - _mali_osk_mem_unmapioregion( cache->base, cache->mapping_size, cache->mapped_registers); - } - else - { - MALI_DEBUG_PRINT(1, ( "Failed to map Mali L2 cache registers at 0x%08lX\n", cache->base)); - } - - if( NULL != cache->lock ) - { - _mali_osk_lock_term( cache->lock ); - } - else - { - MALI_DEBUG_PRINT(1, ( "Failed to allocate a lock for handling a L2 cache unit")); - } - - _mali_osk_free( cache ); - } - else - { - MALI_DEBUG_PRINT(1, ( "Failed to allocate memory for handling a L2 cache unit")); - } - - /* A call is to request region, so this must always be reversed */ - _mali_osk_mem_unreqregion( resource->base, MALI400_L2_CACHE_REGISTERS_SIZE); -#if USING_MALI_PMM - malipmm_core_unregister( MALI_PMM_CORE_L2 ); -#endif - return err; - -err_cleanup_requestmem_failed: - MALI_DEBUG_PRINT(1, ("Failed to request Mali L2 cache '%s' register address space at (0x%08X - 0x%08X)\n", - resource->description, resource->base, resource->base + MALI400_L2_CACHE_REGISTERS_SIZE - 1) ); -#if USING_MALI_PMM - malipmm_core_unregister( MALI_PMM_CORE_L2 ); -#endif - return err; - -} - - -static void mali_l2_cache_register_write(mali_kernel_l2_cache_core * unit, mali_l2_cache_register reg, u32 val) -{ - _mali_osk_mem_iowrite32(unit->mapped_registers, (u32)reg * sizeof(u32), val); -} - - -static u32 mali_l2_cache_register_read(mali_kernel_l2_cache_core * unit, mali_l2_cache_register reg) -{ - return _mali_osk_mem_ioread32(unit->mapped_registers, (u32)reg * sizeof(u32)); -} - -void mali_kernel_l2_cache_do_enable(void) -{ - mali_kernel_l2_cache_core * cache, *temp_cache; - - /* loop over all L2 cache units and enable them*/ - _MALI_OSK_LIST_FOREACHENTRY( cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list) - { - mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_ENABLE, (u32)MALI400_L2_CACHE_ENABLE_ACCESS | (u32)MALI400_L2_CACHE_ENABLE_READ_ALLOCATE); - mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_MAX_READS, (u32)mali_l2_max_reads); - } -} - - -static _mali_osk_errcode_t mali_l2_cache_load_complete(mali_kernel_subsystem_identifier id) -{ - mali_kernel_l2_cache_do_enable(); - MALI_DEBUG_PRINT(2, ( "Mali L2 cache system load complete\n")); - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_kernel_l2_cache_send_command(mali_kernel_l2_cache_core *cache, u32 reg, u32 val) -{ - int i = 0; - const int loop_count = 100000; - - /* - * Grab lock in order to send commands to the L2 cache in a serialized fashion. - * The L2 cache will ignore commands if it is busy. - */ - _mali_osk_lock_wait(cache->lock, _MALI_OSK_LOCKMODE_RW); - - /* First, wait for L2 cache command handler to go idle */ - - for (i = 0; i < loop_count; i++) - { - if (!(_mali_osk_mem_ioread32(cache->mapped_registers , (u32)MALI400_L2_CACHE_REGISTER_STATUS * sizeof(u32)) & (u32)MALI400_L2_CACHE_STATUS_COMMAND_BUSY)) - { - break; - } - } - - if (i == loop_count) - { - _mali_osk_lock_signal(cache->lock, _MALI_OSK_LOCKMODE_RW); - MALI_DEBUG_PRINT(1, ( "Mali L2 cache: aborting wait for command interface to go idle\n")); - MALI_ERROR( _MALI_OSK_ERR_FAULT ); - } - - /* then issue the command */ - mali_l2_cache_register_write(cache, reg, val); - - _mali_osk_lock_signal(cache->lock, _MALI_OSK_LOCKMODE_RW); - MALI_SUCCESS; -} - - -static _mali_osk_errcode_t mali_kernel_l2_cache_invalidate_all_cache(mali_kernel_l2_cache_core *cache) -{ - return mali_kernel_l2_cache_send_command(cache, MALI400_L2_CACHE_REGISTER_COMMAND, MALI400_L2_CACHE_COMMAND_CLEAR_ALL); -} - -_mali_osk_errcode_t mali_kernel_l2_cache_invalidate_all(void) -{ - mali_kernel_l2_cache_core * cache, *temp_cache; - - /* loop over all L2 cache units and invalidate them */ - - _MALI_OSK_LIST_FOREACHENTRY( cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list) - { - MALI_CHECK_NO_ERROR( mali_kernel_l2_cache_invalidate_all_cache(cache) ); - } - - MALI_SUCCESS; -} - - -static _mali_osk_errcode_t mali_kernel_l2_cache_invalidate_page_cache(mali_kernel_l2_cache_core *cache, u32 page) -{ - return mali_kernel_l2_cache_send_command(cache, MALI400_L2_CACHE_REGISTER_CLEAR_PAGE, page); -} - -_mali_osk_errcode_t mali_kernel_l2_cache_invalidate_page(u32 page) -{ - mali_kernel_l2_cache_core * cache, *temp_cache; - - /* loop over all L2 cache units and invalidate them */ - - _MALI_OSK_LIST_FOREACHENTRY( cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list) - { - MALI_CHECK_NO_ERROR( mali_kernel_l2_cache_invalidate_page_cache(cache, page) ); - } - - MALI_SUCCESS; -} - - -void mali_kernel_l2_cache_set_perf_counters(u32 src0, u32 src1, int force_reset) -{ - mali_kernel_l2_cache_core * cache, *temp_cache; - int reset0 = force_reset; - int reset1 = force_reset; - MALI_DEBUG_CODE( - int changed0 = 0; - int changed1 = 0; - ) - - /* loop over all L2 cache units and activate the counters on them */ - _MALI_OSK_LIST_FOREACHENTRY(cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list) - { - u32 cur_src0 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0); - u32 cur_src1 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1); - - if (src0 != cur_src0) - { - mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0, src0); - MALI_DEBUG_CODE(changed0 = 1;) - reset0 = 1; - } - - if (src1 != cur_src1) - { - mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1, src1); - MALI_DEBUG_CODE(changed1 = 1;) - reset1 = 1; - } - - if (reset0) - { - mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0, 0); - } - - if (reset1) - { - mali_l2_cache_register_write(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1, 0); - } - - MALI_DEBUG_PRINT(5, ("L2 cache counters set: SRC0=%u, CHANGED0=%d, RESET0=%d, SRC1=%u, CHANGED1=%d, RESET1=%d\n", - src0, changed0, reset0, - src1, changed1, reset1)); - } -} - - -void mali_kernel_l2_cache_get_perf_counters(u32 *src0, u32 *val0, u32 *src1, u32 *val1) -{ - mali_kernel_l2_cache_core * cache, *temp_cache; - int first_time = 1; - *src0 = 0; - *src1 = 0; - *val0 = 0; - *val1 = 0; - - /* loop over all L2 cache units and read the counters */ - _MALI_OSK_LIST_FOREACHENTRY(cache, temp_cache, &caches_head, mali_kernel_l2_cache_core, list) - { - u32 cur_src0 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0); - u32 cur_src1 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1); - u32 cur_val0 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0); - u32 cur_val1 = mali_l2_cache_register_read(cache, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1); - - MALI_DEBUG_PRINT(5, ("L2 cache counters get: SRC0=%u, VAL0=%u, SRC1=%u, VAL1=%u\n", cur_src0, cur_val0, cur_src1, cur_val1)); - - /* Only update the counter source once, with the value from the first L2 cache unit. */ - if (first_time) - { - *src0 = cur_src0; - *src1 = cur_src1; - first_time = 0; - } - - /* Bail out if the L2 cache units have different counters set. */ - if (*src0 == cur_src0 && *src1 == cur_src1) - { - *val0 += cur_val0; - *val1 += cur_val1; - } - else - { - MALI_DEBUG_PRINT(1, ("Warning: Mali L2 caches has different performance counters set, not retrieving data\n")); - } - } -} diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_l2_cache.h b/drivers/media/video/samsung/mali/common/mali_kernel_l2_cache.h deleted file mode 100644 index 8c12b50..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_l2_cache.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __MALI_KERNEL_L2_CACHE_H__ -#define __MALI_KERNEL_L2_CACHE_H__ - -#include "mali_osk.h" -#include "mali_kernel_subsystem.h" -extern struct mali_kernel_subsystem mali_subsystem_l2_cache; - -_mali_osk_errcode_t mali_kernel_l2_cache_invalidate_all(void); -_mali_osk_errcode_t mali_kernel_l2_cache_invalidate_page(u32 page); - -void mali_kernel_l2_cache_do_enable(void); -void mali_kernel_l2_cache_set_perf_counters(u32 src0, u32 src1, int force_reset); -void mali_kernel_l2_cache_get_perf_counters(u32 *src0, u32 *val0, u32 *src1, u32 *val1); - -#endif /* __MALI_KERNEL_L2_CACHE_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_mem_buddy.c b/drivers/media/video/samsung/mali/common/mali_kernel_mem_buddy.c deleted file mode 100644 index e378f03..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_mem_buddy.c +++ /dev/null @@ -1,1427 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "mali_kernel_core.h" -#include "mali_kernel_subsystem.h" -#include "mali_kernel_mem.h" -#include "mali_kernel_descriptor_mapping.h" -#include "mali_kernel_session_manager.h" - -/* kernel side OS functions and user-kernel interface */ -#include "mali_osk.h" -#include "mali_osk_mali.h" -#include "mali_osk_list.h" -#include "mali_ukk.h" - -#ifdef _MALI_OSK_SPECIFIC_INDIRECT_MMAP -#include "mali_osk_indir_mmap.h" -#endif - -#error Support for non-MMU builds is no longer supported and is planned for removal. - -/** - * Minimum memory allocation size - */ -#define MIN_BLOCK_SIZE (1024*1024UL) - -/** - * Per-session memory descriptor mapping table sizes - */ -#define MALI_MEM_DESCRIPTORS_INIT 64 -#define MALI_MEM_DESCRIPTORS_MAX 4096 - -/** - * Enum uses to store multiple fields in one u32 to keep the memory block struct small - */ -enum MISC_SHIFT { MISC_SHIFT_FREE = 0, MISC_SHIFT_ORDER = 1, MISC_SHIFT_TOPLEVEL = 6 }; -enum MISC_MASK { MISC_MASK_FREE = 0x01, MISC_MASK_ORDER = 0x1F, MISC_MASK_TOPLEVEL = 0x1F }; - -/* forward declaration of the block struct */ -struct mali_memory_block; - -/** - * Definition of memory bank type. - * Represents a memory bank (separate address space) - * Each bank keeps track of its block usage. - * A buddy system used to track the usage -*/ -typedef struct mali_memory_bank -{ - _mali_osk_list_t list; /* links multiple banks together */ - _mali_osk_lock_t *lock; - u32 base_addr; /* Mali seen address of bank */ - u32 cpu_usage_adjust; /* Adjustment factor for what the CPU sees */ - u32 size; /* the effective size */ - u32 real_size; /* the real size of the bank, as given by to the subsystem */ - int min_order; - int max_order; - struct mali_memory_block * blocklist; - _mali_osk_list_t *freelist; - _mali_osk_atomic_t num_active_allocations; - u32 used_for_flags; - u32 alloc_order; /**< Order in which the bank will be used for allocations */ - const char *name; /**< Descriptive name of the bank */ -} mali_memory_bank; - -/** - * Definition of the memory block type - * Represents a memory block, which is the smallest memory unit operated on. - * A block keeps info about its mapping, if in use by a user process - */ -typedef struct mali_memory_block -{ - _mali_osk_list_t link; /* used for freelist and process usage list*/ - mali_memory_bank * bank; /* the bank it belongs to */ - void __user * mapping; /* possible user space mapping of this block */ - u32 misc; /* used while a block is free to track the number blocks it represents */ - int descriptor; - u32 mmap_cookie; /**< necessary for interaction with _mali_ukk_mem_mmap/munmap */ -} mali_memory_block; - -/** - * Defintion of the type used to represent memory used by a session. - * Containts the head of the list of memory currently in use by a session. - */ -typedef struct memory_session -{ - _mali_osk_lock_t *lock; - _mali_osk_list_t memory_head; /* List of the memory blocks used by this session. */ - mali_descriptor_mapping * descriptor_mapping; /**< Mapping between userspace descriptors and our pointers */ -} memory_session; - -/* - Subsystem interface implementation -*/ -/** - * Buddy block memory subsystem startup function - * Called by the driver core when the driver is loaded. - * Registers the memory systems ioctl handler, resource handlers and memory map function with the core. - * - * @param id Identifier assigned by the core to the memory subsystem - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_initialize(mali_kernel_subsystem_identifier id); - -/** - * Buddy block memory subsystem shutdown function - * Called by the driver core when the driver is unloaded. - * Cleans up - * @param id Identifier assigned by the core to the memory subsystem - */ -static void mali_memory_core_terminate(mali_kernel_subsystem_identifier id); - -/** - * Buddy block memory load complete notification function. - * Called by the driver core when all drivers have loaded and all resources has been registered - * Reports on the memory resources registered - * @param id Identifier assigned by the core to the memory subsystem - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_load_complete(mali_kernel_subsystem_identifier id); - - -/** - * Buddy block memory subsystem session begin notification - * Called by the core when a new session to the driver is started. - * Creates a memory session object and sets it as the subsystem slot data for this session - * @param slot Pointer to the slot to use for storing per-session data - * @param queue The user space event sink - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue); - -/** - * Buddy block memory subsystem session end notification - * Called by the core when a session to the driver has ended. - * Cleans up per session data, which includes checking and fixing memory leaks - * - * @param slot Pointer to the slot to use for storing per-session data - */ -static void mali_memory_core_session_end(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot); - -/** - * Buddy block memory subsystem system info filler - * Called by the core when a system info update is needed - * We fill in info about all the memory types we have - * @param info Pointer to system info struct to update - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_system_info_fill(_mali_system_info* info); - -/* our registered resource handlers */ -/** - * Buddy block memory subsystem's notification handler for MEMORY resource instances. - * Registered with the core during startup. - * Called by the core for each memory bank described in the active architecture's config.h file. - * Requests memory region ownership and calls backend. - * @param resource The resource to handle (type MEMORY) - * @return 0 if the memory was claimed and accepted, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_resource_memory(_mali_osk_resource_t * resource); - -/** - * Buddy block memory subsystem's notification handler for MMU resource instances. - * Registered with the core during startup. - * Called by the core for each mmu described in the active architecture's config.h file. - * @param resource The resource to handle (type MMU) - * @return 0 if the MMU was found and initialized, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_resource_mmu(_mali_osk_resource_t * resource); - -/** - * Buddy block memory subsystem's notification handler for FPGA_FRAMEWORK resource instances. - * Registered with the core during startup. - * Called by the core for each fpga framework described in the active architecture's config.h file. - * @param resource The resource to handle (type FPGA_FRAMEWORK) - * @return 0 if the FPGA framework was found and initialized, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_resource_fpga(_mali_osk_resource_t * resource); - -/* ioctl command implementations */ -/** - * Buddy block memory subsystem's handler for MALI_IOC_MEM_GET_BIG_BLOCK ioctl - * Called by the generic ioctl handler when the MALI_IOC_MEM_GET_BIG_BLOCK command is received. - * Finds an available memory block and maps into the current process' address space. - * @param ukk_private private word for use by the User/Kernel interface - * @param session_data Pointer to the per-session object which will track the memory usage - * @param argument The argument from the user. A pointer to an struct mali_dd_get_big_block in user space - * @return Zero if successful, a standard Linux error value value on error (a negative value) - */ -_mali_osk_errcode_t _mali_ukk_get_big_block( _mali_uk_get_big_block_s *args ); - -/** - * Buddy block memory subsystem's handler for MALI_IOC_MEM_FREE_BIG_BLOCK ioctl - * Called by the generic ioctl handler when the MALI_IOC_MEM_FREE_BIG_BLOCK command is received. - * Unmaps the memory from the process' address space and marks the block as free. - * @param session_data Pointer to the per-session object which tracks the memory usage - * @param argument The argument from the user. A pointer to an struct mali_dd_get_big_block in user space - * @return Zero if successful, a standard Linux error value value on error (a negative value) - */ - -/* this static version allows us to make use of it while holding the memory_session lock. - * This is required for the session_end code */ -static _mali_osk_errcode_t _mali_ukk_free_big_block_internal( struct mali_session_data * mali_session_data, memory_session * session_data, _mali_uk_free_big_block_s *args); - -_mali_osk_errcode_t _mali_ukk_free_big_block( _mali_uk_free_big_block_s *args ); - -/** - * Buddy block memory subsystem's memory bank registration routine - * Called when a MEMORY resource has been found. - * The memory region has already been reserved for use by this driver. - * Create a bank object to represent this region and initialize its slots. - * @note Can only be called in an module atomic scope, i.e. during module init since no locking is performed - * @param phys_base Physical base address of this bank - * @param cpu_usage_adjust Adjustment factor for CPU seen address - * @param size Size of the bank in bytes - * @param flags Memory type bits - * @param alloc_order Order in which the bank will be used for allocations - * @param name descriptive name of the bank - * @return Zero on success, negative on error - */ -static int mali_memory_bank_register(u32 phys_base, u32 cpu_usage_adjust, u32 size, u32 flags, u32 alloc_order, const char *name); - -/** - * Get a block of mali memory of at least the given size and of the given type - * This is the backend for get_big_block. - * @param type_id The type id of memory requested. - * @param minimum_size The size requested - * @return Pointer to a block on success, NULL on failure - */ -static mali_memory_block * mali_memory_block_get(u32 type_id, u32 minimum_size); - -/** - * Get the mali seen address of the memory described by the block - * @param block The memory block to return the address of - * @return The mali seen address of the memory block - */ -MALI_STATIC_INLINE u32 block_mali_addr_get(mali_memory_block * block); - -/** - * Get the cpu seen address of the memory described by the block - * The cpu_usage_adjust will be used to change the mali seen phys address - * @param block The memory block to return the address of - * @return The mali seen address of the memory block - */ -MALI_STATIC_INLINE u32 block_cpu_addr_get(mali_memory_block * block); - -/** - * Get the size of the memory described by the given block - * @param block The memory block to return the size of - * @return The size of the memory block described by the object - */ -MALI_STATIC_INLINE u32 block_size_get(mali_memory_block * block); - -/** - * Get the user space accessible mapping the memory described by the given memory block - * Returns a pointer in user space to the memory, if one has been created. - * @param block The memory block to return the mapping of - * @return User space pointer to cpu accessible memory or NULL if not mapped - */ -MALI_STATIC_INLINE void __user * block_mapping_get(mali_memory_block * block); - -/** - * Set the user space accessible mapping the memory described by the given memory block. - * Sets the stored pointer to user space for the memory described by this block. - * @param block The memory block to set mapping info for - * @param ptr User space pointer to cpu accessible memory or NULL if not mapped - */ -MALI_STATIC_INLINE void block_mapping_set(mali_memory_block * block, void __user * ptr); - -/** - * Get the cookie for use with _mali_ukk_mem_munmap(). - * @param block The memory block to get the cookie from - * @return the cookie. A return of 0 is still a valid cookie. - */ -MALI_STATIC_INLINE u32 block_mmap_cookie_get(mali_memory_block * block); - -/** - * Set the cookie returned via _mali_ukk_mem_mmap(). - * @param block The memory block to set the cookie for - * @param cookie the cookie - */ -MALI_STATIC_INLINE void block_mmap_cookie_set(mali_memory_block * block, u32 cookie); - - -/** - * Get a memory block's free status - * @param block The block to get the state of - */ -MALI_STATIC_INLINE u32 get_block_free(mali_memory_block * block); - -/** - * Set a memory block's free status - * @param block The block to set the state for - * @param state The state to set - */ -MALI_STATIC_INLINE void set_block_free(mali_memory_block * block, int state); - -/** - * Set a memory block's order - * @param block The block to set the order for - * @param order The order to set - */ -MALI_STATIC_INLINE void set_block_order(mali_memory_block * block, u32 order); - -/** - * Get a memory block's order - * @param block The block to get the order for - * @return The order this block exists on - */ -MALI_STATIC_INLINE u32 get_block_order(mali_memory_block * block); - -/** - * Tag a block as being a toplevel block. - * A toplevel block has no buddy and no parent - * @param block The block to tag as being toplevel - */ -MALI_STATIC_INLINE void set_block_toplevel(mali_memory_block * block, u32 level); - -/** - * Check if a block is a toplevel block - * @param block The block to check - * @return 1 if toplevel, 0 else - */ -MALI_STATIC_INLINE u32 get_block_toplevel(mali_memory_block * block); - -/** - * Checks if the given block is a buddy at the given order and that it's free - * @param block The block to check - * @param order The order to check against - * @return 0 if not valid, else 1 - */ -MALI_STATIC_INLINE int block_is_valid_buddy(mali_memory_block * block, int order); - -/* - The buddy system uses the following rules to quickly find a blocks buddy - and parent (block representing this block at a higher order level): - - Given a block with index i the blocks buddy is at index i ^ ( 1 << order) - - Given a block with index i the blocks parent is at i & ~(1 << order) -*/ - -/** - * Get a blocks buddy - * @param block The block to find the buddy for - * @param order The order to operate on - * @return Pointer to the buddy block - */ -MALI_STATIC_INLINE mali_memory_block * block_get_buddy(mali_memory_block * block, u32 order); - -/** - * Get a blocks parent - * @param block The block to find the parent for - * @param order The order to operate on - * @return Pointer to the parent block - */ -MALI_STATIC_INLINE mali_memory_block * block_get_parent(mali_memory_block * block, u32 order); - -/** - * Release mali memory - * Backend for free_big_block. - * Will release the mali memory described by the given block struct. - * @param block Memory block to free - */ -static void block_release(mali_memory_block * block); - -/* end interface implementation */ - -/** - * List of all the memory banks registerd with the subsystem. - * Access to this list is NOT synchronized since it's only - * written to during module init and termination. - */ -static _MALI_OSK_LIST_HEAD(memory_banks_list); - -/* - The buddy memory system's mali subsystem interface implementation. - We currently handle module and session life-time management. -*/ -struct mali_kernel_subsystem mali_subsystem_memory = -{ - mali_memory_core_initialize, /* startup */ - NULL, /*mali_memory_core_terminate,*/ /* shutdown */ - mali_memory_core_load_complete, /* load_complete */ - mali_memory_core_system_info_fill, /* system_info_fill */ - mali_memory_core_session_begin, /* session_begin */ - mali_memory_core_session_end, /* session_end */ - NULL, /* broadcast_notification */ -#if MALI_STATE_TRACKING - NULL, /* dump_state */ -#endif -}; - -/* Initialized when this subsystem is initialized. This is determined by the - * position in subsystems[], and so the value used to initialize this is - * determined at compile time */ -static mali_kernel_subsystem_identifier mali_subsystem_memory_id = -1; - -/* called during module init */ -static _mali_osk_errcode_t mali_memory_core_initialize(mali_kernel_subsystem_identifier id) -{ - _MALI_OSK_INIT_LIST_HEAD(&memory_banks_list); - - mali_subsystem_memory_id = id; - - /* register our handlers */ - MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(MEMORY, mali_memory_core_resource_memory)); - - MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(MMU, mali_memory_core_resource_mmu)); - - MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(FPGA_FRAMEWORK, mali_memory_core_resource_fpga)); - - MALI_SUCCESS; -} - -/* called if/when our module is unloaded */ -static void mali_memory_core_terminate(mali_kernel_subsystem_identifier id) -{ - mali_memory_bank * bank, *temp; - - /* loop over all memory banks to free them */ - /* we use the safe version since we delete the current bank in the body */ - _MALI_OSK_LIST_FOREACHENTRY(bank, temp, &memory_banks_list, mali_memory_bank, list) - { - MALI_DEBUG_CODE(int usage_count = _mali_osk_atomic_read(&bank->num_active_allocations)); - /* - Report leaked memory - If this happens we have a bug in our session cleanup code. - */ - MALI_DEBUG_PRINT_IF(1, 0 != usage_count, ("%d allocation(s) from memory bank at 0x%X still in use\n", usage_count, bank->base_addr)); - - _mali_osk_atomic_term(&bank->num_active_allocations); - - _mali_osk_lock_term(bank->lock); - - /* unlink from bank list */ - _mali_osk_list_del(&bank->list); - - /* release kernel resources used by the bank */ - _mali_osk_mem_unreqregion(bank->base_addr, bank->real_size); - - /* remove all resources used to represent this bank*/ - _mali_osk_free(bank->freelist); - _mali_osk_free(bank->blocklist); - - /* destroy the bank object itself */ - _mali_osk_free(bank); - } - - /* No need to de-initialize mali_subsystem_memory_id - it could only be - * re-initialized to the same value */ -} - -/* load_complete handler */ -static _mali_osk_errcode_t mali_memory_core_load_complete(mali_kernel_subsystem_identifier id) -{ - mali_memory_bank * bank, *temp; - - MALI_DEBUG_PRINT( 1, ("Mali memory allocators will be used in this order of preference (lowest number first) :\n")); - - _MALI_OSK_LIST_FOREACHENTRY(bank, temp, &memory_banks_list, mali_memory_bank, list) - { - if ( NULL != bank->name ) - { - MALI_DEBUG_PRINT( 1, ("\t%d: %s\n", bank->alloc_order, bank->name) ); - } - else - { - MALI_DEBUG_PRINT( 1, ("\t%d: (UNNAMED ALLOCATOR)\n", bank->alloc_order ) ); - } - } - MALI_SUCCESS; -} - -MALI_STATIC_INLINE u32 order_needed_for_size(u32 size, struct mali_memory_bank * bank) -{ - u32 order = 0; - - if (0 < size) - { - for ( order = sizeof(u32)*8 - 1; ((1UL<<order) & size) == 0; --order) - /* nothing */; - - /* check if size is pow2, if not we need increment order by one */ - if (0 != (size & ((1UL<<order)-1))) ++order; - } - - if ((NULL != bank) && (order < bank->min_order)) order = bank->min_order; - /* Not capped to max order, that doesn't make sense */ - - return order; -} - -MALI_STATIC_INLINE u32 maximum_order_which_fits(u32 size) -{ - u32 order = 0; - u32 powsize = 1; - while (powsize < size) - { - powsize <<= 1; - if (powsize > size) break; - order++; - } - - return order; -} - -/* called for new MEMORY resources */ -static _mali_osk_errcode_t mali_memory_bank_register(u32 phys_base, u32 cpu_usage_adjust, u32 size, u32 flags, u32 alloc_order, const char *name) -{ - /* no locking performed due to function contract */ - int i; - u32 left, offset; - mali_memory_bank * bank; - mali_memory_bank * bank_enum, *temp; - - _mali_osk_errcode_t err; - - /* Only a multiple of MIN_BLOCK_SIZE is usable */ - u32 usable_size = size & ~(MIN_BLOCK_SIZE - 1); - - /* handle zero sized banks and bank smaller than the fixed block size */ - if (0 == usable_size) - { - MALI_PRINT(("Usable size == 0\n")); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - - /* warn for banks not a muliple of the block size */ - MALI_DEBUG_PRINT_IF(1, usable_size != size, ("Memory bank @ 0x%X not a multiple of minimum block size. %d bytes wasted\n", phys_base, size - usable_size)); - - /* check against previous registrations */ - MALI_DEBUG_CODE( - { - _MALI_OSK_LIST_FOREACHENTRY(bank, temp, &memory_banks_list, mali_memory_bank, list) - { - /* duplicate ? */ - if (bank->base_addr == phys_base) - { - MALI_PRINT(("Duplicate registration of a memory bank at 0x%X detected\n", phys_base)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - /* overlapping ? */ - else if ( - ( (phys_base > bank->base_addr) && (phys_base < (bank->base_addr + bank->real_size)) ) || - ( (phys_base + size) > bank->base_addr && ((phys_base + size) < (bank->base_addr + bank->real_size)) ) - ) - { - MALI_PRINT(("Overlapping memory blocks found. Memory at 0x%X overlaps with memory at 0x%X size 0x%X\n", bank->base_addr, phys_base, size)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - } - } - ); - - /* create an object to represent this memory bank */ - MALI_CHECK_NON_NULL(bank = (mali_memory_bank*)_mali_osk_malloc(sizeof(mali_memory_bank)), _MALI_OSK_ERR_NOMEM); - - /* init the fields */ - _MALI_OSK_INIT_LIST_HEAD(&bank->list); - bank->base_addr = phys_base; - bank->cpu_usage_adjust = cpu_usage_adjust; - bank->size = usable_size; - bank->real_size = size; - bank->alloc_order = alloc_order; - bank->name = name; - - err = _mali_osk_atomic_init(&bank->num_active_allocations, 0); - if (err != _MALI_OSK_ERR_OK) - { - _mali_osk_free(bank); - MALI_ERROR(err); - } - - bank->used_for_flags = flags; - bank->min_order = order_needed_for_size(MIN_BLOCK_SIZE, NULL); - bank->max_order = maximum_order_which_fits(usable_size); - bank->lock = _mali_osk_lock_init((_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_SPINLOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE), 0, 0); - if (NULL == bank->lock) - { - _mali_osk_atomic_term(&bank->num_active_allocations); - _mali_osk_free(bank); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - bank->blocklist = _mali_osk_calloc(1, sizeof(struct mali_memory_block) * (usable_size / MIN_BLOCK_SIZE)); - if (NULL == bank->blocklist) - { - _mali_osk_lock_term(bank->lock); - _mali_osk_atomic_term(&bank->num_active_allocations); - _mali_osk_free(bank); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - for (i = 0; i < (usable_size / MIN_BLOCK_SIZE); i++) - { - bank->blocklist[i].bank = bank; - } - - bank->freelist = _mali_osk_calloc(1, sizeof(_mali_osk_list_t) * (bank->max_order - bank->min_order + 1)); - if (NULL == bank->freelist) - { - _mali_osk_lock_term(bank->lock); - _mali_osk_free(bank->blocklist); - _mali_osk_atomic_term(&bank->num_active_allocations); - _mali_osk_free(bank); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - for (i = 0; i < (bank->max_order - bank->min_order + 1); i++) _MALI_OSK_INIT_LIST_HEAD(&bank->freelist[i]); - - /* init slot info */ - for (offset = 0, left = usable_size; offset < (usable_size / MIN_BLOCK_SIZE); /* updated inside the body */) - { - u32 block_order; - mali_memory_block * block; - - /* the maximum order which fits in the remaining area */ - block_order = maximum_order_which_fits(left); - - /* find the block pointer */ - block = &bank->blocklist[offset]; - - /* tag the block as being toplevel */ - set_block_toplevel(block, block_order); - - /* tag it as being free */ - set_block_free(block, 1); - - /* set the order */ - set_block_order(block, block_order); - - _mali_osk_list_addtail(&block->link, bank->freelist + (block_order - bank->min_order)); - - left -= (1 << block_order); - offset += ((1 << block_order) / MIN_BLOCK_SIZE); - } - - /* add bank to list of banks on the system */ - _MALI_OSK_LIST_FOREACHENTRY( bank_enum, temp, &memory_banks_list, mali_memory_bank, list ) - { - if ( bank_enum->alloc_order >= alloc_order ) - { - /* Found insertion point - our item must go before this one */ - break; - } - } - _mali_osk_list_addtail(&bank->list, &bank_enum->list); - - MALI_SUCCESS; -} - -_mali_osk_errcode_t mali_memory_mmu_register(u32 type, u32 phys_base) -{ - /* not supported */ - return _MALI_OSK_ERR_INVALID_FUNC; -} - -void mali_memory_mmu_unregister(u32 phys_base) -{ - /* not supported */ - return; -} - -static mali_memory_block * mali_memory_block_get(u32 type_id, u32 minimum_size) -{ - mali_memory_bank * bank; - mali_memory_block * block = NULL; - u32 requested_order, current_order; - - /* input validation */ - if (0 == minimum_size) - { - /* bad size */ - MALI_DEBUG_PRINT(2, ("Zero size block requested by mali_memory_block_get\n")); - return NULL; - } - - bank = (mali_memory_bank*)type_id; - - requested_order = order_needed_for_size(minimum_size, bank); - - MALI_DEBUG_PRINT(4, ("For size %d we need order %d (%d)\n", minimum_size, requested_order, 1 << requested_order)); - - _mali_osk_lock_wait(bank->lock, _MALI_OSK_LOCKMODE_RW); - /* ! critical section begin */ - - MALI_DEBUG_PRINT(7, ("Bank 0x%x locked\n", bank)); - - for (current_order = requested_order; current_order <= bank->max_order; ++current_order) - { - _mali_osk_list_t * list = bank->freelist + (current_order - bank->min_order); - MALI_DEBUG_PRINT(7, ("Checking freelist 0x%x for order %d\n", list, current_order)); - if (0 != _mali_osk_list_empty(list)) continue; /* empty list */ - - MALI_DEBUG_PRINT(7, ("Found an entry on the freelist for order %d\n", current_order)); - - - block = _MALI_OSK_LIST_ENTRY(list->next, mali_memory_block, link); - _mali_osk_list_delinit(&block->link); - - while (current_order > requested_order) - { - mali_memory_block * buddy_block; - MALI_DEBUG_PRINT(7, ("Splitting block 0x%x\n", block)); - current_order--; - list--; - buddy_block = block_get_buddy(block, current_order - bank->min_order); - set_block_order(buddy_block, current_order); - set_block_free(buddy_block, 1); - _mali_osk_list_add(&buddy_block->link, list); - } - - set_block_order(block, current_order); - set_block_free(block, 0); - - /* update usage count */ - _mali_osk_atomic_inc(&bank->num_active_allocations); - - break; - } - - /* ! critical section end */ - _mali_osk_lock_signal(bank->lock, _MALI_OSK_LOCKMODE_RW); - - MALI_DEBUG_PRINT(7, ("Lock released for bank 0x%x\n", bank)); - - MALI_DEBUG_PRINT_IF(7, NULL != block, ("Block 0x%x allocated\n", block)); - - return block; -} - - -static void block_release(mali_memory_block * block) -{ - mali_memory_bank * bank; - u32 current_order; - - if (NULL == block) return; - - bank = block->bank; - - /* we're manipulating the free list, so we need to lock it */ - _mali_osk_lock_wait(bank->lock, _MALI_OSK_LOCKMODE_RW); - /* ! critical section begin */ - - set_block_free(block, 1); - current_order = get_block_order(block); - - while (current_order <= bank->max_order) - { - mali_memory_block * buddy_block; - buddy_block = block_get_buddy(block, current_order - bank->min_order); - if (!block_is_valid_buddy(buddy_block, current_order)) break; - _mali_osk_list_delinit(&buddy_block->link); /* remove from free list */ - /* clear tracked data in both blocks */ - set_block_order(block, 0); - set_block_free(block, 0); - set_block_order(buddy_block, 0); - set_block_free(buddy_block, 0); - /* make the parent control the new state */ - block = block_get_parent(block, current_order - bank->min_order); - set_block_order(block, current_order + 1); /* merged has a higher order */ - set_block_free(block, 1); /* mark it as free */ - current_order++; - if (get_block_toplevel(block) == current_order) break; /* stop the merge if we've arrived at a toplevel block */ - } - - _mali_osk_list_add(&block->link, &bank->freelist[current_order - bank->min_order]); - - /* update bank usage statistics */ - _mali_osk_atomic_dec(&block->bank->num_active_allocations); - - /* !critical section end */ - _mali_osk_lock_signal(bank->lock, _MALI_OSK_LOCKMODE_RW); - - return; -} - -MALI_STATIC_INLINE u32 block_get_offset(mali_memory_block * block) -{ - return block - block->bank->blocklist; -} - -MALI_STATIC_INLINE u32 block_mali_addr_get(mali_memory_block * block) -{ - if (NULL != block) return block->bank->base_addr + MIN_BLOCK_SIZE * block_get_offset(block); - else return 0; -} - -MALI_STATIC_INLINE u32 block_cpu_addr_get(mali_memory_block * block) -{ - if (NULL != block) return (block->bank->base_addr + MIN_BLOCK_SIZE * block_get_offset(block)) + block->bank->cpu_usage_adjust; - else return 0; -} - -MALI_STATIC_INLINE u32 block_size_get(mali_memory_block * block) -{ - if (NULL != block) return 1 << get_block_order(block); - else return 0; -} - -MALI_STATIC_INLINE void __user * block_mapping_get(mali_memory_block * block) -{ - if (NULL != block) return block->mapping; - else return NULL; -} - -MALI_STATIC_INLINE void block_mapping_set(mali_memory_block * block, void __user * ptr) -{ - if (NULL != block) block->mapping = ptr; -} - -MALI_STATIC_INLINE u32 block_mmap_cookie_get(mali_memory_block * block) -{ - if (NULL != block) return block->mmap_cookie; - else return 0; -} - -/** - * Set the cookie returned via _mali_ukk_mem_mmap(). - * @param block The memory block to set the cookie for - * @param cookie the cookie - */ -MALI_STATIC_INLINE void block_mmap_cookie_set(mali_memory_block * block, u32 cookie) -{ - if (NULL != block) block->mmap_cookie = cookie; -} - - -static _mali_osk_errcode_t mali_memory_core_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue) -{ - memory_session * session_data; - - /* validate input */ - if (NULL == slot) - { - MALI_DEBUG_PRINT(1, ("NULL slot given to memory session begin\n")); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - - if (NULL != *slot) - { - MALI_DEBUG_PRINT(1, ("The slot given to memory session begin already contains data")); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - - /* create the session data object */ - MALI_CHECK_NON_NULL(session_data = _mali_osk_malloc(sizeof(memory_session)), _MALI_OSK_ERR_NOMEM); - - /* create descriptor mapping table */ - session_data->descriptor_mapping = mali_descriptor_mapping_create(MALI_MEM_DESCRIPTORS_INIT, MALI_MEM_DESCRIPTORS_MAX); - - if (NULL == session_data->descriptor_mapping) - { - _mali_osk_free(session_data); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - _MALI_OSK_INIT_LIST_HEAD(&session_data->memory_head); /* no memory in use */ - session_data->lock = _mali_osk_lock_init((_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_ONELOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE), 0, 0); - if (NULL == session_data->lock) - { - _mali_osk_free(session_data); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - *slot = session_data; /* slot will point to our data object */ - - MALI_SUCCESS; -} - -static void mali_memory_core_session_end(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot) -{ - memory_session * session_data; - - /* validate input */ - if (NULL == slot) - { - MALI_DEBUG_PRINT(1, ("NULL slot given to memory session begin\n")); - return; - } - - if (NULL == *slot) - { - MALI_DEBUG_PRINT(1, ("NULL memory_session found in current session object")); - return; - } - - _mali_osk_lock_wait(((memory_session*)*slot)->lock, _MALI_OSK_LOCKMODE_RW); - session_data = (memory_session *)*slot; - /* clear our slot */ - *slot = NULL; - - /* - First free all memory still being used. - This can happen if the caller has leaked memory or - the application has crashed forcing an auto-session end. - */ - if (0 == _mali_osk_list_empty(&session_data->memory_head)) - { - mali_memory_block * block, * temp; - MALI_DEBUG_PRINT(1, ("Memory found on session usage list during session termination\n")); - - /* use the _safe version since fre_big_block removes the active block from the list we're iterating */ - _MALI_OSK_LIST_FOREACHENTRY(block, temp, &session_data->memory_head, mali_memory_block, link) - { - _mali_osk_errcode_t err; - _mali_uk_free_big_block_s uk_args; - - MALI_DEBUG_PRINT(4, ("Freeing block 0x%x with mali address 0x%x size %d mapped in user space at 0x%x\n", - block, - (void*)block_mali_addr_get(block), - block_size_get(block), - block_mapping_get(block)) - ); - - /* free the block */ - /** @note manual type safety check-point */ - uk_args.ctx = mali_session_data; - uk_args.cookie = (u32)block->descriptor; - err = _mali_ukk_free_big_block_internal( mali_session_data, session_data, &uk_args ); - - if ( _MALI_OSK_ERR_OK != err ) - { - MALI_DEBUG_PRINT_ERROR(("_mali_ukk_free_big_block_internal() failed during session termination on block with cookie==0x%X\n", - uk_args.cookie) - ); - } - } - } - - if (NULL != session_data->descriptor_mapping) - { - mali_descriptor_mapping_destroy(session_data->descriptor_mapping); - session_data->descriptor_mapping = NULL; - } - - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - _mali_osk_lock_term(session_data->lock); - - /* free the session data object */ - _mali_osk_free(session_data); - - return; -} - -static _mali_osk_errcode_t mali_memory_core_system_info_fill(_mali_system_info* info) -{ - mali_memory_bank * bank, *temp; - _mali_mem_info **mem_info_tail; - - /* check input */ - MALI_CHECK_NON_NULL(info, _MALI_OSK_ERR_INVALID_ARGS); - - /* make sure we won't leak any memory. It could also be that it's an uninitialized variable, but that would be a bug in the caller */ - MALI_DEBUG_ASSERT(NULL == info->mem_info); - - mem_info_tail = &info->mem_info; - - _MALI_OSK_LIST_FOREACHENTRY(bank, temp, &memory_banks_list, mali_memory_bank, list) - { - _mali_mem_info * mem_info; - - mem_info = (_mali_mem_info *)_mali_osk_calloc(1, sizeof(_mali_mem_info)); - if (NULL == mem_info) return _MALI_OSK_ERR_NOMEM; /* memory already allocated will be freed by the caller */ - - /* set info */ - mem_info->size = bank->size; - mem_info->flags = (_mali_bus_usage)bank->used_for_flags; - mem_info->maximum_order_supported = bank->max_order; - mem_info->identifier = (u32)bank; - - /* add to system info linked list */ - (*mem_info_tail) = mem_info; - mem_info_tail = &mem_info->next; - } - - /* all OK */ - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_memory_core_resource_memory(_mali_osk_resource_t * resource) -{ - _mali_osk_errcode_t err; - - /* Request ownership of the memory */ - if (_MALI_OSK_ERR_OK != _mali_osk_mem_reqregion(resource->base, resource->size, resource->description)) - { - MALI_DEBUG_PRINT(1, ("Failed to request memory region %s (0x%08X - 0x%08X)\n", resource->description, resource->base, resource->base + resource->size - 1)); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - /* call backend */ - err = mali_memory_bank_register(resource->base, resource->cpu_usage_adjust, resource->size, resource->flags, resource->alloc_order, resource->description); - if (_MALI_OSK_ERR_OK != err) - { - /* if backend refused the memory we have to release the region again */ - MALI_DEBUG_PRINT(1, ("Memory bank registration failed\n")); - _mali_osk_mem_unreqregion(resource->base, resource->size); - MALI_ERROR(err); - } - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_memory_core_resource_mmu(_mali_osk_resource_t * resource) -{ - /* Not supported by the fixed block memory system */ - MALI_DEBUG_PRINT(1, ("MMU resource not supported by non-MMU driver!\n")); - MALI_ERROR(_MALI_OSK_ERR_INVALID_FUNC); -} - -static _mali_osk_errcode_t mali_memory_core_resource_fpga(_mali_osk_resource_t * resource) -{ - mali_io_address mapping; - - MALI_DEBUG_PRINT(5, ("FPGA framework '%s' @ (0x%08X - 0x%08X)\n", - resource->description, resource->base, resource->base + sizeof(u32) * 2 - 1 - )); - - mapping = _mali_osk_mem_mapioregion(resource->base + 0x1000, sizeof(u32) * 2, "fpga framework"); - if (mapping) - { - u32 data; - data = _mali_osk_mem_ioread32(mapping, 0); - MALI_DEBUG_PRINT(2, ("FPGA framwork '%s' @ 0x%08X:\n", resource->description, resource->base)); - MALI_DEBUG_PRINT(2, ("\tBitfile date: %d%02d%02d_%02d%02d\n", - (data >> 20), - (data >> 16) & 0xF, - (data >> 11) & 0x1F, - (data >> 6) & 0x1F, - (data >> 0) & 0x3F)); - data = _mali_osk_mem_ioread32(mapping, sizeof(u32)); - MALI_DEBUG_PRINT(2, ("\tBitfile SCCS rev: %d\n", data)); - - _mali_osk_mem_unmapioregion(resource->base + 0x1000, sizeof(u32) *2, mapping); - } - else MALI_DEBUG_PRINT(1, ("Failed to access FPGA framwork '%s' @ 0x%08X\n", resource->description, resource->base)); - - MALI_SUCCESS; -} - -/* static _mali_osk_errcode_t get_big_block(void * ukk_private, struct mali_session_data * mali_session_data, void __user * argument) */ -_mali_osk_errcode_t _mali_ukk_get_big_block( _mali_uk_get_big_block_s *args ) -{ - _mali_uk_mem_mmap_s args_mmap = {0, }; - int md; - mali_memory_block * block; - _mali_osk_errcode_t err; - memory_session * session_data; - - MALI_DEBUG_ASSERT_POINTER( args ); - - MALI_DEBUG_ASSERT_POINTER( args->ctx ); - - /** @note manual type safety check-point */ - session_data = (memory_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_memory_id); - - MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); - - _mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - if (!args->type_id) - { - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* at least min block size */ - if (MIN_BLOCK_SIZE > args->minimum_size_requested) args->minimum_size_requested = MIN_BLOCK_SIZE; - - /* perform the actual allocation */ - block = mali_memory_block_get(args->type_id, args->minimum_size_requested); - if ( NULL == block ) - { - /* no memory available with requested type_id */ - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session_data->descriptor_mapping, block, &md)) - { - block_release(block); - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - block->descriptor = md; - - - /* fill in response */ - args->mali_address = block_mali_addr_get(block); - args->block_size = block_size_get(block); - args->cookie = (u32)md; - args->flags = block->bank->used_for_flags; - - /* map the block into the process' address space */ - - /** @note manual type safety check-point */ - args_mmap.ukk_private = (void *)args->ukk_private; - args_mmap.ctx = args->ctx; - args_mmap.size = args->block_size; - args_mmap.phys_addr = block_cpu_addr_get(block); - -#ifndef _MALI_OSK_SPECIFIC_INDIRECT_MMAP - err = _mali_ukk_mem_mmap( &args_mmap ); -#else - err = _mali_osk_specific_indirect_mmap( &args_mmap ); -#endif - - /* check if the mapping failed */ - if ( _MALI_OSK_ERR_OK != err ) - { - MALI_DEBUG_PRINT(1, ("Memory mapping failed 0x%x\n", args->cpuptr)); - /* mapping failed */ - - /* remove descriptor entry */ - mali_descriptor_mapping_free(session_data->descriptor_mapping, md); - - /* free the mali memory */ - block_release(block); - - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - return err; - } - - args->cpuptr = args_mmap.mapping; - block_mmap_cookie_set(block, args_mmap.cookie); - block_mapping_set(block, args->cpuptr); - - MALI_DEBUG_PRINT(2, ("Mali memory 0x%x (size %d) mapped in process memory space at 0x%x\n", (void*)args->mali_address, args->block_size, args->cpuptr)); - - /* track memory in use for the session */ - _mali_osk_list_addtail(&block->link, &session_data->memory_head); - - /* memory assigned to the session, memory mapped into the process' view */ - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - MALI_SUCCESS; -} - -/* Internal code that assumes the memory session lock is held */ -static _mali_osk_errcode_t _mali_ukk_free_big_block_internal( struct mali_session_data * mali_session_data, memory_session * session_data, _mali_uk_free_big_block_s *args) -{ - mali_memory_block * block = NULL; - _mali_osk_errcode_t err; - _mali_uk_mem_munmap_s args_munmap = {0,}; - - MALI_DEBUG_ASSERT_POINTER( mali_session_data ); - MALI_DEBUG_ASSERT_POINTER( session_data ); - MALI_DEBUG_ASSERT_POINTER( args ); - - err = mali_descriptor_mapping_get(session_data->descriptor_mapping, (int)args->cookie, (void**)&block); - if (_MALI_OSK_ERR_OK != err) - { - MALI_DEBUG_PRINT(1, ("Invalid memory descriptor %d used to release memory pages\n", (int)args->cookie)); - MALI_ERROR(err); - } - - MALI_DEBUG_ASSERT_POINTER(block); - - MALI_DEBUG_PRINT(4, ("Asked to free block 0x%x with mali address 0x%x size %d mapped in user space at 0x%x\n", - block, - (void*)block_mali_addr_get(block), - block_size_get(block), - block_mapping_get(block)) - ); - - /** @note manual type safety check-point */ - args_munmap.ctx = (void*)mali_session_data; - args_munmap.mapping = block_mapping_get( block ); - args_munmap.size = block_size_get( block ); - args_munmap.cookie = block_mmap_cookie_get( block ); - -#ifndef _MALI_OSK_SPECIFIC_INDIRECT_MMAP - _mali_ukk_mem_munmap( &args_munmap ); -#else - _mali_osk_specific_indirect_munmap( &args_munmap ); -#endif - - MALI_DEBUG_PRINT(6, ("Session data 0x%x, lock 0x%x\n", session_data, &session_data->lock)); - - /* unlink from session usage list */ - MALI_DEBUG_PRINT(5, ("unlink from session usage list\n")); - _mali_osk_list_delinit(&block->link); - - /* remove descriptor entry */ - mali_descriptor_mapping_free(session_data->descriptor_mapping, (int)args->cookie); - - /* free the mali memory */ - block_release(block); - MALI_DEBUG_PRINT(5, ("Block freed\n")); - - MALI_SUCCESS; -} - -/* static _mali_osk_errcode_t free_big_block( struct mali_session_data * mali_session_data, void __user * argument) */ -_mali_osk_errcode_t _mali_ukk_free_big_block( _mali_uk_free_big_block_s *args ) -{ - _mali_osk_errcode_t err; - struct mali_session_data * mali_session_data; - memory_session * session_data; - - MALI_DEBUG_ASSERT_POINTER( args ); - - MALI_DEBUG_ASSERT_POINTER( args->ctx ); - - /** @note manual type safety check-point */ - mali_session_data = (struct mali_session_data *)args->ctx; - - /* Must always verify this, since these are provided by the user */ - MALI_CHECK_NON_NULL(mali_session_data, _MALI_OSK_ERR_INVALID_ARGS); - - session_data = mali_kernel_session_manager_slot_get(mali_session_data, mali_subsystem_memory_id); - - MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); - - _mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - /** @note this has been separated out so that the session_end handler can call this while it has the memory_session lock held */ - err = _mali_ukk_free_big_block_internal( mali_session_data, session_data, args ); - - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - return err; -} - -MALI_STATIC_INLINE u32 get_block_free(mali_memory_block * block) -{ - return (block->misc >> MISC_SHIFT_FREE) & MISC_MASK_FREE; -} - -MALI_STATIC_INLINE void set_block_free(mali_memory_block * block, int state) -{ - if (state) block->misc |= (MISC_MASK_FREE << MISC_SHIFT_FREE); - else block->misc &= ~(MISC_MASK_FREE << MISC_SHIFT_FREE); -} - -MALI_STATIC_INLINE void set_block_order(mali_memory_block * block, u32 order) -{ - block->misc &= ~(MISC_MASK_ORDER << MISC_SHIFT_ORDER); - block->misc |= ((order & MISC_MASK_ORDER) << MISC_SHIFT_ORDER); -} - -MALI_STATIC_INLINE u32 get_block_order(mali_memory_block * block) -{ - return (block->misc >> MISC_SHIFT_ORDER) & MISC_MASK_ORDER; -} - -MALI_STATIC_INLINE void set_block_toplevel(mali_memory_block * block, u32 level) -{ - block->misc |= ((level & MISC_MASK_TOPLEVEL) << MISC_SHIFT_TOPLEVEL); -} - -MALI_STATIC_INLINE u32 get_block_toplevel(mali_memory_block * block) -{ - return (block->misc >> MISC_SHIFT_TOPLEVEL) & MISC_MASK_TOPLEVEL; -} - -MALI_STATIC_INLINE int block_is_valid_buddy(mali_memory_block * block, int order) -{ - if (get_block_free(block) && (get_block_order(block) == order)) return 1; - else return 0; -} - -MALI_STATIC_INLINE mali_memory_block * block_get_buddy(mali_memory_block * block, u32 order) -{ - return block + ( (block_get_offset(block) ^ (1 << order)) - block_get_offset(block)); -} - -MALI_STATIC_INLINE mali_memory_block * block_get_parent(mali_memory_block * block, u32 order) -{ - return block + ((block_get_offset(block) & ~(1 << order)) - block_get_offset(block)); -} - -/* This handler registered to mali_mmap for non-MMU builds */ -_mali_osk_errcode_t _mali_ukk_mem_mmap( _mali_uk_mem_mmap_s *args ) -{ - _mali_osk_errcode_t ret; - struct mali_session_data * mali_session_data; - mali_memory_allocation * descriptor; - memory_session * session_data; - - /* validate input */ - if (NULL == args) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: args was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); } - - /* Unpack arguments */ - mali_session_data = (struct mali_session_data *)args->ctx; - - if (NULL == mali_session_data) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: mali_session data was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); } - - MALI_DEBUG_ASSERT( mali_subsystem_memory_id >= 0 ); - - session_data = mali_kernel_session_manager_slot_get(mali_session_data, mali_subsystem_memory_id); - /* validate input */ - if (NULL == session_data) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: session data was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_FAULT); } - - descriptor = (mali_memory_allocation*) _mali_osk_calloc( 1, sizeof(mali_memory_allocation) ); - if (NULL == descriptor) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: descriptor was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_NOMEM); } - - descriptor->size = args->size; - descriptor->mali_address = args->phys_addr; - descriptor->mali_addr_mapping_info = (void*)session_data; - descriptor->process_addr_mapping_info = args->ukk_private; /* save to be used during physical manager callback */ - descriptor->flags = MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE; - - ret = _mali_osk_mem_mapregion_init( descriptor ); - if ( _MALI_OSK_ERR_OK != ret ) - { - MALI_DEBUG_PRINT(3, ("_mali_osk_mem_mapregion_init() failed\n")); - _mali_osk_free(descriptor); - MALI_ERROR(ret); - } - - ret = _mali_osk_mem_mapregion_map( descriptor, 0, &descriptor->mali_address, descriptor->size ); - if ( _MALI_OSK_ERR_OK != ret ) - { - MALI_DEBUG_PRINT(3, ("_mali_osk_mem_mapregion_map() failed\n")); - _mali_osk_mem_mapregion_term( descriptor ); - _mali_osk_free(descriptor); - MALI_ERROR(ret); - } - - args->mapping = descriptor->mapping; - - /** - * @note we do not require use of mali_descriptor_mapping here: - * the cookie gets stored in the mali_memory_block struct, which itself is - * protected by mali_descriptor_mapping, and so this cookie never leaves - * kernel space (on any OS). - * - * In the MMU case, we must use a mali_descriptor_mapping, since on _some_ - * OSs, the cookie leaves kernel space. - */ - args->cookie = (u32)descriptor; - MALI_SUCCESS; -} - -/* This handler registered to mali_munmap for non-MMU builds */ -_mali_osk_errcode_t _mali_ukk_mem_munmap( _mali_uk_mem_munmap_s *args ) -{ - mali_memory_allocation * descriptor; - - /** see note in _mali_ukk_mem_mmap() - no need to use descriptor mapping */ - descriptor = (mali_memory_allocation *)args->cookie; - MALI_DEBUG_ASSERT_POINTER(descriptor); - - /* args->mapping and args->size are also discarded. They are only necessary for certain do_munmap implementations. However, they could be used to check the descriptor at this point. */ - _mali_osk_mem_mapregion_unmap( descriptor, 0, descriptor->size, (_mali_osk_mem_mapregion_flags_t)0 ); - - _mali_osk_mem_mapregion_term( descriptor ); - - _mali_osk_free(descriptor); - - return _MALI_OSK_ERR_OK; -} - -/** - * Stub function to satisfy UDD interface exclusion requirement. - * This is because the Base code compiles in \b both MMU and non-MMU calls, - * so both sets must be declared (but the 'unused' set may be stub) - */ -_mali_osk_errcode_t _mali_ukk_init_mem( _mali_uk_init_mem_s *args ) -{ - MALI_IGNORE( args ); - return _MALI_OSK_ERR_FAULT; -} - -/** - * Stub function to satisfy UDD interface exclusion requirement. - * This is because the Base code compiles in \b both MMU and non-MMU calls, - * so both sets must be declared (but the 'unused' set may be stub) - */ -_mali_osk_errcode_t _mali_ukk_term_mem( _mali_uk_term_mem_s *args ) -{ - MALI_IGNORE( args ); - return _MALI_OSK_ERR_FAULT; -} - -/** - * Stub function to satisfy UDD interface exclusion requirement. - * This is because the Base code compiles in \b both MMU and non-MMU calls, - * so both sets must be declared (but the 'unused' set may be stub) - */ -_mali_osk_errcode_t _mali_ukk_map_external_mem( _mali_uk_map_external_mem_s *args ) -{ - MALI_IGNORE( args ); - return _MALI_OSK_ERR_FAULT; -} - -/** - * Stub function to satisfy UDD interface exclusion requirement. - * This is because the Base code compiles in \b both MMU and non-MMU calls, - * so both sets must be declared (but the 'unused' set may be stub) - */ -_mali_osk_errcode_t _mali_ukk_unmap_external_mem( _mali_uk_unmap_external_mem_s *args ) -{ - MALI_IGNORE( args ); - return _MALI_OSK_ERR_FAULT; -} - -/** - * Stub function to satisfy UDD interface exclusion requirement. - * This is because the Base code compiles in \b both MMU and non-MMU calls, - * so both sets must be declared (but the 'unused' set may be stub) - */ -_mali_osk_errcode_t _mali_ukk_query_mmu_page_table_dump_size( _mali_uk_query_mmu_page_table_dump_size_s *args ) -{ - MALI_IGNORE( args ); - return _MALI_OSK_ERR_FAULT; -} - -/** - * Stub function to satisfy UDD interface exclusion requirement. - * This is because the Base code compiles in \b both MMU and non-MMU calls, - * so both sets must be declared (but the 'unused' set may be stub) - */ -_mali_osk_errcode_t _mali_ukk_dump_mmu_page_table( _mali_uk_dump_mmu_page_table_s * args ) -{ - MALI_IGNORE( args ); - return _MALI_OSK_ERR_FAULT; -} diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_mem_mmu.c b/drivers/media/video/samsung/mali/common/mali_kernel_mem_mmu.c deleted file mode 100644 index c993ad5..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_mem_mmu.c +++ /dev/null @@ -1,3157 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "mali_kernel_subsystem.h" -#include "mali_kernel_mem.h" -#include "mali_kernel_ioctl.h" -#include "mali_kernel_descriptor_mapping.h" -#include "mali_kernel_mem_mmu.h" -#include "mali_kernel_memory_engine.h" -#include "mali_block_allocator.h" -#include "mali_kernel_mem_os.h" -#include "mali_kernel_session_manager.h" -#include "mali_kernel_core.h" -#include "mali_kernel_rendercore.h" - -#if defined USING_MALI400_L2_CACHE -#include "mali_kernel_l2_cache.h" -#endif - -#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 -#include "ump_kernel_interface.h" -#endif - -/* kernel side OS functions and user-kernel interface */ -#include "mali_osk.h" -#include "mali_osk_mali.h" -#include "mali_ukk.h" -#include "mali_osk_bitops.h" -#include "mali_osk_list.h" - -/** - * Size of the MMU registers in bytes - */ -#define MALI_MMU_REGISTERS_SIZE 0x24 - -/** - * Size of an MMU page in bytes - */ -#define MALI_MMU_PAGE_SIZE 0x1000 - -/** - * Page directory index from address - * Calculates the page directory index from the given address - */ -#define MALI_MMU_PDE_ENTRY(address) (((address)>>22) & 0x03FF) - -/** - * Page table index from address - * Calculates the page table index from the given address - */ -#define MALI_MMU_PTE_ENTRY(address) (((address)>>12) & 0x03FF) - -/** - * Extract the memory address from an PDE/PTE entry - */ -#define MALI_MMU_ENTRY_ADDRESS(value) ((value) & 0xFFFFFC00) - -/** - * Calculate memory address from PDE and PTE - */ -#define MALI_MMU_ADDRESS(pde, pte) (((pde)<<22) | ((pte)<<12)) - -/** - * Linux kernel version has marked SA_SHIRQ as deprecated, IRQF_SHARED should be used. - * This is to handle older kernels which haven't done this swap. - */ -#ifndef IRQF_SHARED -#define IRQF_SHARED SA_SHIRQ -#endif /* IRQF_SHARED */ - -/** - * Per-session memory descriptor mapping table sizes - */ -#define MALI_MEM_DESCRIPTORS_INIT 64 -#define MALI_MEM_DESCRIPTORS_MAX 65536 - -/** - * Used to disallow more than one core to run a MMU at the same time - * - * @note This value is hardwired into some systems' configuration files, - * which \em might not be a header file (e.g. some external data configuration - * file). Therefore, if this value is modified, its occurance must be - * \b manually checked for in the entire driver source tree. - */ -#define MALI_MMU_DISALLOW_PARALLELL_WORK_OF_MALI_CORES 1 - -#define MALI_INVALID_PAGE ((u32)(~0)) - -/** - * - */ -typedef enum mali_mmu_entry_flags -{ - MALI_MMU_FLAGS_PRESENT = 0x01, - MALI_MMU_FLAGS_READ_PERMISSION = 0x02, - MALI_MMU_FLAGS_WRITE_PERMISSION = 0x04, - MALI_MMU_FLAGS_MASK = 0x07 -} mali_mmu_entry_flags; - -/** - * MMU register numbers - * Used in the register read/write routines. - * See the hardware documentation for more information about each register - */ -typedef enum mali_mmu_register { - MALI_MMU_REGISTER_DTE_ADDR = 0x0000, /**< Current Page Directory Pointer */ - MALI_MMU_REGISTER_STATUS = 0x0001, /**< Status of the MMU */ - MALI_MMU_REGISTER_COMMAND = 0x0002, /**< Command register, used to control the MMU */ - MALI_MMU_REGISTER_PAGE_FAULT_ADDR = 0x0003, /**< Logical address of the last page fault */ - MALI_MMU_REGISTER_ZAP_ONE_LINE = 0x004, /**< Used to invalidate the mapping of a single page from the MMU */ - MALI_MMU_REGISTER_INT_RAWSTAT = 0x0005, /**< Raw interrupt status, all interrupts visible */ - MALI_MMU_REGISTER_INT_CLEAR = 0x0006, /**< Indicate to the MMU that the interrupt has been received */ - MALI_MMU_REGISTER_INT_MASK = 0x0007, /**< Enable/disable types of interrupts */ - MALI_MMU_REGISTER_INT_STATUS = 0x0008 /**< Interrupt status based on the mask */ -} mali_mmu_register; - -/** - * MMU interrupt register bits - * Each cause of the interrupt is reported - * through the (raw) interrupt status registers. - * Multiple interrupts can be pending, so multiple bits - * can be set at once. - */ -typedef enum mali_mmu_interrupt -{ - MALI_MMU_INTERRUPT_PAGE_FAULT = 0x01, /**< A page fault occured */ - MALI_MMU_INTERRUPT_READ_BUS_ERROR = 0x02 /**< A bus read error occured */ -} mali_mmu_interrupt; - -/** - * MMU commands - * These are the commands that can be sent - * to the MMU unit. - */ -typedef enum mali_mmu_command -{ - MALI_MMU_COMMAND_ENABLE_PAGING = 0x00, /**< Enable paging (memory translation) */ - MALI_MMU_COMMAND_DISABLE_PAGING = 0x01, /**< Disable paging (memory translation) */ - MALI_MMU_COMMAND_ENABLE_STALL = 0x02, /**< Enable stall on page fault */ - MALI_MMU_COMMAND_DISABLE_STALL = 0x03, /**< Disable stall on page fault */ - MALI_MMU_COMMAND_ZAP_CACHE = 0x04, /**< Zap the entire page table cache */ - MALI_MMU_COMMAND_PAGE_FAULT_DONE = 0x05, /**< Page fault processed */ - MALI_MMU_COMMAND_SOFT_RESET = 0x06 /**< Reset the MMU back to power-on settings */ -} mali_mmu_command; - -typedef enum mali_mmu_status_bits -{ - MALI_MMU_STATUS_BIT_PAGING_ENABLED = 1 << 0, - MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE = 1 << 1, - MALI_MMU_STATUS_BIT_STALL_ACTIVE = 1 << 2, - MALI_MMU_STATUS_BIT_IDLE = 1 << 3, - MALI_MMU_STATUS_BIT_REPLAY_BUFFER_EMPTY = 1 << 4, - MALI_MMU_STATUS_BIT_PAGE_FAULT_IS_WRITE = 1 << 5, -} mali_mmu_status_bits; - -/** - * Defintion of the type used to represent memory used by a session. - * Containts the pointer to the huge user space virtual memory area - * used to access the Mali memory. - */ -typedef struct memory_session -{ - _mali_osk_lock_t *lock; /**< Lock protecting the vm manipulation */ - - u32 mali_base_address; /**< Mali virtual memory area used by this session */ - mali_descriptor_mapping * descriptor_mapping; /**< Mapping between userspace descriptors and our pointers */ - - u32 page_directory; /**< Physical address of the memory session's page directory */ - - mali_io_address page_directory_mapped; /**< Pointer to the mapped version of the page directory into the kernel's address space */ - mali_io_address page_entries_mapped[1024]; /**< Pointers to the page tables which exists in the page directory mapped into the kernel's address space */ - u32 page_entries_usage_count[1024]; /**< Tracks usage count of the page table pages, so they can be releases on the last reference */ - - _mali_osk_list_t active_mmus; /**< The MMUs in this session, in increasing order of ID (so we can lock them in the correct order when necessary) */ - _mali_osk_list_t memory_head; /**< Track all the memory allocated in this session, for freeing on abnormal termination */ -} memory_session; - -typedef struct mali_kernel_memory_mmu_idle_callback -{ - _mali_osk_list_t link; - void (*callback)(void*); - void * callback_argument; -} mali_kernel_memory_mmu_idle_callback; - -/** - * Definition of the MMU struct - * Used to track a MMU unit in the system. - * Contains information about the mapping of the registers - */ -typedef struct mali_kernel_memory_mmu -{ - int id; /**< ID of the MMU, no duplicate IDs may exist on the system */ - const char * description; /**< Description text received from the resource manager to help identify the resource for people */ - int irq_nr; /**< IRQ number */ - u32 base; /**< Physical address of the registers */ - mali_io_address mapped_registers; /**< Virtual mapping of the registers */ - u32 mapping_size; /**< Size of registers in bytes */ - _mali_osk_list_t list; /**< Used to link multiple MMU's into a list */ - _mali_osk_irq_t *irq; - u32 flags; /**< Used to store if there is something special with this mmu. */ - - _mali_osk_lock_t *lock; /**< Lock protecting access to the usage fields */ - /* usage fields */ - memory_session * active_session; /**< Active session, NULL if no session is active */ - u32 usage_count; /**< Number of nested activations of the active session */ - _mali_osk_list_t callbacks; /**< Callback registered for MMU idle notification */ - void *core; - - int in_page_fault_handler; - - _mali_osk_list_t session_link; -} mali_kernel_memory_mmu; - -typedef struct dedicated_memory_info -{ - u32 base; - u32 size; - struct dedicated_memory_info * next; -} dedicated_memory_info; - -/* types used for external_memory and ump_memory physical memory allocators, which are using the mali_allocation_engine */ -#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 -typedef struct ump_mem_allocation -{ - mali_allocation_engine * engine; - mali_memory_allocation * descriptor; - u32 initial_offset; - u32 size_allocated; - ump_dd_handle ump_mem; -} ump_mem_allocation ; -#endif - -typedef struct external_mem_allocation -{ - mali_allocation_engine * engine; - mali_memory_allocation * descriptor; - u32 initial_offset; - u32 size; -} external_mem_allocation; - -/* - Subsystem interface implementation -*/ -/** - * Fixed block memory subsystem startup function. - * Called by the driver core when the driver is loaded. - * Registers the memory systems ioctl handler, resource handlers and memory map function with the core. - * - * @param id Identifier assigned by the core to the memory subsystem - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_initialize(mali_kernel_subsystem_identifier id); - -/** - * Fixed block memory subsystem shutdown function. - * Called by the driver core when the driver is unloaded. - * Cleans up - * @param id Identifier assigned by the core to the memory subsystem - */ -static void mali_memory_core_terminate(mali_kernel_subsystem_identifier id); - -/** - * MMU Memory load complete notification function. - * Called by the driver core when all drivers have loaded and all resources has been registered - * Builds the memory overall memory list - * @param id Identifier assigned by the core to the memory subsystem - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_load_complete(mali_kernel_subsystem_identifier id); - -/** - * Fixed block memory subsystem session begin notification - * Called by the core when a new session to the driver is started. - * Creates a memory session object and sets it as the subsystem slot data for this session - * @param slot Pointer to the slot to use for storing per-session data - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue); - -/** - * Fixed block memory subsystem session end notification - * Called by the core when a session to the driver has ended. - * Cleans up per session data, which includes checking and fixing memory leaks - * - * @param slot Pointer to the slot to use for storing per-session data - */ -static void mali_memory_core_session_end(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot); - -/** - * Fixed block memory subsystem system info filler - * Called by the core when a system info update is needed - * We fill in info about all the memory types we have - * @param info Pointer to system info struct to update - * @return 0 on success, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_system_info_fill(_mali_system_info* info); - -/* our registered resource handlers */ - -/** - * Fixed block memory subsystem's notification handler for MMU resource instances. - * Registered with the core during startup. - * Called by the core for each mmu described in the active architecture's config.h file. - * @param resource The resource to handle (type MMU) - * @return 0 if the MMU was found and initialized, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_resource_mmu(_mali_osk_resource_t * resource); - -/** - * Fixed block memory subsystem's notification handler for FPGA_FRAMEWORK resource instances. - * Registered with the core during startup. - * Called by the core for each fpga framework described in the active architecture's config.h file. - * @param resource The resource to handle (type FPGA_FRAMEWORK) - * @return 0 if the FPGA framework was found and initialized, negative on error - */ -static _mali_osk_errcode_t mali_memory_core_resource_fpga(_mali_osk_resource_t * resource); - - -static _mali_osk_errcode_t mali_memory_core_resource_dedicated_memory(_mali_osk_resource_t * resource); -static _mali_osk_errcode_t mali_memory_core_resource_os_memory(_mali_osk_resource_t * resource); - -/** - * @brief Internal function for unmapping memory - * - * Worker function for unmapping memory from a user-process. We assume that the - * session/descriptor's lock was obtained before entry. For example, the - * wrapper _mali_ukk_mem_munmap() will lock the descriptor, then call this - * function to do the actual unmapping. mali_memory_core_session_end() could - * also call this directly (depending on compilation options), having locked - * the descriptor. - * - * This function will fail if it is unable to put the MMU in stall mode (which - * might be the case if a page fault is also being processed). - * - * @param args see _mali_uk_mem_munmap_s in "mali_uk_types.h" - * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. - */ -static _mali_osk_errcode_t _mali_ukk_mem_munmap_internal( _mali_uk_mem_munmap_s *args ); - -/** - * The MMU interrupt handler - * Upper half of the MMU interrupt processing. - * Called by the kernel when the MMU has triggered an interrupt. - * The interrupt function supports IRQ sharing. So it'll probe the MMU in question - * @param irq The irq number (not used) - * @param dev_id Points to the MMU object being handled - * @param regs Registers of interrupted process (not used) - * @return Standard Linux interrupt result. - * Subset used by the driver is IRQ_HANDLED processed - * IRQ_NONE Not processed - */ -static _mali_osk_errcode_t mali_kernel_memory_mmu_interrupt_handler_upper_half(void * data); - -/** - * The MMU reset hander - * Bottom half of the MMU interrupt processing for page faults and bus errors - * @param work The item to operate on, NULL in our case - */ -static void mali_kernel_memory_mmu_interrupt_handler_bottom_half ( void *data ); - -/** - * Read MMU register value - * Reads the contents of the specified register. - * @param unit The MMU to read from - * @param reg The register to read - * @return The contents of the register - */ -static u32 mali_mmu_register_read(mali_kernel_memory_mmu * unit, mali_mmu_register reg); - -/** - * Write to a MMU register - * Writes the given value to the specified register - * @param unit The MMU to write to - * @param reg The register to write to - * @param val The value to write to the register - */ -static void mali_mmu_register_write(mali_kernel_memory_mmu * unit, mali_mmu_register reg, u32 val); - -/** - * Issues the reset command to the MMU and waits for HW to be ready again - * @param mmu The MMU to reset - */ -static void mali_mmu_raw_reset(mali_kernel_memory_mmu * mmu); - -/** - * Issues the enable paging command to the MMU and waits for HW to complete the request - * @param mmu The MMU to enable paging for - */ -static void mali_mmu_enable_paging(mali_kernel_memory_mmu * mmu); - -/** - * Issues the enable stall command to the MMU and waits for HW to complete the request - * @param mmu The MMU to enable paging for - * @return MALI_TRUE if HW stall was successfully engaged, otherwise MALI_FALSE (req timed out) - */ -static mali_bool mali_mmu_enable_stall(mali_kernel_memory_mmu * mmu); - -/** - * Issues the disable stall command to the MMU and waits for HW to complete the request - * @param mmu The MMU to enable paging for - */ -static void mali_mmu_disable_stall(mali_kernel_memory_mmu * mmu); - -#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 -static void ump_memory_release(void * ctx, void * handle); -static mali_physical_memory_allocation_result ump_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info); -#endif /* MALI_USE_UNIFIED_MEMORY_PROVIDER != 0*/ - - -static void external_memory_release(void * ctx, void * handle); -static mali_physical_memory_allocation_result external_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info); - - - - -/* nop functions */ - -/* mali address manager needs to allocate page tables on allocate, write to page table(s) on map, write to page table(s) and release page tables on release */ -static _mali_osk_errcode_t mali_address_manager_allocate(mali_memory_allocation * descriptor); /* validates the range, allocates memory for the page tables if needed */ -static _mali_osk_errcode_t mali_address_manager_map(mali_memory_allocation * descriptor, u32 offset, u32 *phys_addr, u32 size); -static void mali_address_manager_release(mali_memory_allocation * descriptor); - -static void mali_mmu_activate_address_space(mali_kernel_memory_mmu * mmu, u32 page_directory); - -_mali_osk_errcode_t mali_mmu_page_table_cache_create(void); -void mali_mmu_page_table_cache_destroy(void); - -_mali_osk_errcode_t mali_mmu_get_table_page(u32 *table_page, mali_io_address *mapping); -void mali_mmu_release_table_page(u32 pa); - -static _mali_osk_errcode_t mali_allocate_empty_page_directory(void); - -static void mali_free_empty_page_directory(void); - -static _mali_osk_errcode_t fill_page(mali_io_address mapping, u32 data); - -static _mali_osk_errcode_t mali_allocate_fault_flush_pages(void); - -static void mali_free_fault_flush_pages(void); - -static void mali_mmu_probe_irq_trigger(mali_kernel_memory_mmu * mmu); -static _mali_osk_errcode_t mali_mmu_probe_irq_acknowledge(mali_kernel_memory_mmu * mmu); - -/* MMU variables */ - -typedef struct mali_mmu_page_table_allocation -{ - _mali_osk_list_t list; - u32 * usage_map; - u32 usage_count; - u32 num_pages; - mali_page_table_block pages; -} mali_mmu_page_table_allocation; - -typedef struct mali_mmu_page_table_allocations -{ - _mali_osk_lock_t *lock; - _mali_osk_list_t partial; - _mali_osk_list_t full; - /* we never hold on to a empty allocation */ -} mali_mmu_page_table_allocations; - -/* Head of the list of MMUs */ -static _MALI_OSK_LIST_HEAD(mmu_head); - -/* the mmu page table cache */ -static struct mali_mmu_page_table_allocations page_table_cache; - -/* page fault queue flush helper pages - * note that the mapping pointers are currently unused outside of the initialization functions */ -static u32 mali_page_fault_flush_page_directory = MALI_INVALID_PAGE; -static mali_io_address mali_page_fault_flush_page_directory_mapping = NULL; -static u32 mali_page_fault_flush_page_table = MALI_INVALID_PAGE; -static mali_io_address mali_page_fault_flush_page_table_mapping = NULL; -static u32 mali_page_fault_flush_data_page = MALI_INVALID_PAGE; -static mali_io_address mali_page_fault_flush_data_page_mapping = NULL; - -/* an empty page directory (no address valid) which is active on any MMU not currently marked as in use */ -static u32 mali_empty_page_directory = MALI_INVALID_PAGE; - -/* - The fixed memory system's mali subsystem interface implementation. - We currently handle module and session life-time management. -*/ -struct mali_kernel_subsystem mali_subsystem_memory = -{ - mali_memory_core_initialize, /* startup */ - NULL, /*mali_memory_core_terminate,*/ /* shutdown */ - mali_memory_core_load_complete, /* load_complete */ - mali_memory_core_system_info_fill, /* system_info_fill */ - mali_memory_core_session_begin, /* session_begin */ - mali_memory_core_session_end, /* session_end */ - NULL, /* broadcast_notification */ -#if MALI_STATE_TRACKING - NULL, /* dump_state */ -#endif -}; - -static mali_kernel_mem_address_manager mali_address_manager = -{ - mali_address_manager_allocate, /* allocate */ - mali_address_manager_release, /* release */ - mali_address_manager_map, /* map_physical */ - NULL /* unmap_physical not present*/ -}; - -static mali_kernel_mem_address_manager process_address_manager = -{ - _mali_osk_mem_mapregion_init, /* allocate */ - _mali_osk_mem_mapregion_term, /* release */ - _mali_osk_mem_mapregion_map, /* map_physical */ - _mali_osk_mem_mapregion_unmap /* unmap_physical */ -}; - -static mali_allocation_engine memory_engine = NULL; -static mali_physical_memory_allocator * physical_memory_allocators = NULL; - -static dedicated_memory_info * mem_region_registrations = NULL; - -/* Initialized when this subsystem is initialized. This is determined by the - * position in subsystems[], and so the value used to initialize this is - * determined at compile time */ -static mali_kernel_subsystem_identifier mali_subsystem_memory_id = (mali_kernel_subsystem_identifier)-1; - -/* called during module init */ -static _mali_osk_errcode_t mali_memory_core_initialize(mali_kernel_subsystem_identifier id) -{ - MALI_DEBUG_PRINT(2, ("MMU memory system initializing\n")); - - /* save our subsystem id for later for use in slot lookup during session activation */ - mali_subsystem_memory_id = id; - - _MALI_OSK_INIT_LIST_HEAD(&mmu_head); - - MALI_CHECK_NO_ERROR( mali_mmu_page_table_cache_create() ); - - /* register our handlers */ - MALI_CHECK_NO_ERROR( _mali_kernel_core_register_resource_handler(MMU, mali_memory_core_resource_mmu) ); - - MALI_CHECK_NO_ERROR( _mali_kernel_core_register_resource_handler(FPGA_FRAMEWORK, mali_memory_core_resource_fpga) ); - - MALI_CHECK_NO_ERROR( _mali_kernel_core_register_resource_handler(MEMORY, mali_memory_core_resource_dedicated_memory) ); - - MALI_CHECK_NO_ERROR( _mali_kernel_core_register_resource_handler(OS_MEMORY, mali_memory_core_resource_os_memory) ); - - memory_engine = mali_allocation_engine_create(&mali_address_manager, &process_address_manager); - MALI_CHECK_NON_NULL( memory_engine, _MALI_OSK_ERR_FAULT); - - MALI_SUCCESS; -} - -/* called if/when our module is unloaded */ -static void mali_memory_core_terminate(mali_kernel_subsystem_identifier id) -{ - mali_kernel_memory_mmu * mmu, *temp_mmu; - - MALI_DEBUG_PRINT(2, ("MMU memory system terminating\n")); - - /* loop over all MMU units and shut them down */ - _MALI_OSK_LIST_FOREACHENTRY(mmu, temp_mmu, &mmu_head, mali_kernel_memory_mmu, list) - { - /* reset to defaults */ - mali_mmu_raw_reset(mmu); - - /* unregister the irq */ - _mali_osk_irq_term(mmu->irq); - - /* remove from the list of MMU's on the system */ - _mali_osk_list_del(&mmu->list); - - /* release resources */ - _mali_osk_mem_unmapioregion(mmu->base, mmu->mapping_size, mmu->mapped_registers); - _mali_osk_mem_unreqregion(mmu->base, mmu->mapping_size); - _mali_osk_lock_term(mmu->lock); - _mali_osk_free(mmu); - } - - /* free global helper pages */ - mali_free_empty_page_directory(); - mali_free_fault_flush_pages(); - - /* destroy the page table cache before shutting down backends in case we have a page table leak to report */ - mali_mmu_page_table_cache_destroy(); - - while ( NULL != mem_region_registrations) - { - dedicated_memory_info * m; - m = mem_region_registrations; - mem_region_registrations = m->next; - _mali_osk_mem_unreqregion(m->base, m->size); - _mali_osk_free(m); - } - - while ( NULL != physical_memory_allocators) - { - mali_physical_memory_allocator * m; - m = physical_memory_allocators; - physical_memory_allocators = m->next; - m->destroy(m); - } - - if (NULL != memory_engine) - { - mali_allocation_engine_destroy(memory_engine); - memory_engine = NULL; - } - -} - -static _mali_osk_errcode_t mali_memory_core_session_begin(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue) -{ - memory_session * session_data; - _mali_osk_errcode_t err; - int i; - mali_io_address pd_mapped; - - /* validate input */ - if (NULL == slot) - { - MALI_DEBUG_PRINT(1, ("NULL slot given to memory session begin\n")); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - - if (NULL != *slot) - { - MALI_DEBUG_PRINT(1, ("The slot given to memory session begin already contains data")); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - - MALI_DEBUG_PRINT(2, ("MMU session begin\n")); - - /* create the session data object */ - session_data = _mali_osk_calloc(1, sizeof(memory_session)); - MALI_CHECK_NON_NULL( session_data, _MALI_OSK_ERR_NOMEM ); - - /* create descriptor mapping table */ - session_data->descriptor_mapping = mali_descriptor_mapping_create(MALI_MEM_DESCRIPTORS_INIT, MALI_MEM_DESCRIPTORS_MAX); - - if (NULL == session_data->descriptor_mapping) - { - _mali_osk_free(session_data); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - err = mali_mmu_get_table_page(&session_data->page_directory, &pd_mapped); - - session_data->page_directory_mapped = pd_mapped; - if (_MALI_OSK_ERR_OK != err) - { - mali_descriptor_mapping_destroy(session_data->descriptor_mapping); - _mali_osk_free(session_data); - MALI_ERROR(err); - } - MALI_DEBUG_ASSERT_POINTER( session_data->page_directory_mapped ); - - MALI_DEBUG_PRINT(2, ("Page directory for session 0x%x placed at physical address 0x%08X\n", mali_session_data, session_data->page_directory)); - - for (i = 0; i < MALI_MMU_PAGE_SIZE/4; i++) - { - /* mark each page table as not present */ - _mali_osk_mem_iowrite32_relaxed(session_data->page_directory_mapped, sizeof(u32) * i, 0); - } - _mali_osk_write_mem_barrier(); - - /* page_table_mapped[] is already set to NULL by _mali_osk_calloc call */ - - _MALI_OSK_INIT_LIST_HEAD(&session_data->active_mmus); - session_data->lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_ONELOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, 128); - if (NULL == session_data->lock) - { - mali_mmu_release_table_page(session_data->page_directory); - mali_descriptor_mapping_destroy(session_data->descriptor_mapping); - _mali_osk_free(session_data); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* Init the session's memory allocation list */ - _MALI_OSK_INIT_LIST_HEAD( &session_data->memory_head ); - - *slot = session_data; /* slot will point to our data object */ - MALI_DEBUG_PRINT(2, ("MMU session begin: success\n")); - MALI_SUCCESS; -} - -static void descriptor_table_cleanup_callback(int descriptor_id, void* map_target) -{ - mali_memory_allocation * descriptor; - - descriptor = (mali_memory_allocation*)map_target; - - MALI_DEBUG_PRINT(1, ("Cleanup of descriptor %d mapping to 0x%x in descriptor table\n", descriptor_id, map_target)); - MALI_DEBUG_ASSERT(descriptor); - - mali_allocation_engine_release_memory(memory_engine, descriptor); - _mali_osk_free(descriptor); -} - -static void mali_memory_core_session_end(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot) -{ - memory_session * session_data; - int i; - const int num_page_table_entries = sizeof(session_data->page_entries_mapped) / sizeof(session_data->page_entries_mapped[0]); - - MALI_DEBUG_PRINT(2, ("MMU session end\n")); - - /* validate input */ - if (NULL == slot) - { - MALI_DEBUG_PRINT(1, ("NULL slot given to memory session begin\n")); - return; - } - - session_data = (memory_session *)*slot; - - if (NULL == session_data) - { - MALI_DEBUG_PRINT(1, ("No session data found during session end\n")); - return; - } - /* Lock the session so we can modify the memory list */ - _mali_osk_lock_wait( session_data->lock, _MALI_OSK_LOCKMODE_RW ); - /* Noninterruptable spinlock type, so must always have locked. Checking should've been done in OSK function. */ - -#ifndef MALI_UKK_HAS_IMPLICIT_MMAP_CLEANUP -#if _MALI_OSK_SPECIFIC_INDIRECT_MMAP -#error Indirect MMAP specified, but UKK does not have implicit MMAP cleanup. Current implementation does not handle this. -#else - - /* Free all memory engine allocations */ - if (0 == _mali_osk_list_empty(&session_data->memory_head)) - { - mali_memory_allocation *descriptor; - mali_memory_allocation *temp; - _mali_uk_mem_munmap_s unmap_args; - - MALI_DEBUG_PRINT(1, ("Memory found on session usage list during session termination\n")); - - unmap_args.ctx = mali_session_data; - - /* use the 'safe' list iterator, since freeing removes the active block from the list we're iterating */ - _MALI_OSK_LIST_FOREACHENTRY(descriptor, temp, &session_data->memory_head, mali_memory_allocation, list) - { - MALI_DEBUG_PRINT(4, ("Freeing block with mali address 0x%x size %d mapped in user space at 0x%x\n", - descriptor->mali_address, descriptor->size, descriptor->size, descriptor->mapping) - ); - /* ASSERT that the descriptor's lock references the correct thing */ - MALI_DEBUG_ASSERT( descriptor->lock == session_data->lock ); - /* Therefore, we have already locked the descriptor */ - - unmap_args.size = descriptor->size; - unmap_args.mapping = descriptor->mapping; - unmap_args.cookie = (u32)descriptor; - - /* - * This removes the descriptor from the list, and frees the descriptor - * - * Does not handle the _MALI_OSK_SPECIFIC_INDIRECT_MMAP case, since - * the only OS we are aware of that requires indirect MMAP also has - * implicit mmap cleanup. - */ - _mali_ukk_mem_munmap_internal( &unmap_args ); - } - } - - /* Assert that we really did free everything */ - MALI_DEBUG_ASSERT( _mali_osk_list_empty(&session_data->memory_head) ); -#endif /* _MALI_OSK_SPECIFIC_INDIRECT_MMAP */ -#endif /* MALI_UKK_HAS_IMPLICIT_MMAP_CLEANUP */ - - if (NULL != session_data->descriptor_mapping) - { - mali_descriptor_mapping_call_for_each(session_data->descriptor_mapping, descriptor_table_cleanup_callback); - mali_descriptor_mapping_destroy(session_data->descriptor_mapping); - session_data->descriptor_mapping = NULL; - } - - for (i = 0; i < num_page_table_entries; i++) - { - /* free PTE memory */ - if (session_data->page_directory_mapped && (_mali_osk_mem_ioread32(session_data->page_directory_mapped, sizeof(u32)*i) & MALI_MMU_FLAGS_PRESENT)) - { - mali_mmu_release_table_page( _mali_osk_mem_ioread32(session_data->page_directory_mapped, i*sizeof(u32)) & ~MALI_MMU_FLAGS_MASK); - _mali_osk_mem_iowrite32(session_data->page_directory_mapped, i * sizeof(u32), 0); - } - } - - if (MALI_INVALID_PAGE != session_data->page_directory) - { - mali_mmu_release_table_page(session_data->page_directory); - session_data->page_directory = MALI_INVALID_PAGE; - } - - _mali_osk_lock_signal( session_data->lock, _MALI_OSK_LOCKMODE_RW ); - - /** - * @note Could the VMA close handler mean that we use the session data after it was freed? - * In which case, would need to refcount the session data, and free on VMA close - */ - - /* Free the lock */ - _mali_osk_lock_term( session_data->lock ); - /* free the session data object */ - _mali_osk_free(session_data); - - /* clear our slot */ - *slot = NULL; - - return; -} - -static _mali_osk_errcode_t mali_allocate_empty_page_directory(void) -{ - _mali_osk_errcode_t err; - mali_io_address mapping; - - MALI_CHECK_NO_ERROR(mali_mmu_get_table_page(&mali_empty_page_directory, &mapping)); - - MALI_DEBUG_ASSERT_POINTER( mapping ); - - err = fill_page(mapping, 0); - if (_MALI_OSK_ERR_OK != err) - { - mali_mmu_release_table_page(mali_empty_page_directory); - mali_empty_page_directory = MALI_INVALID_PAGE; - } - return err; -} - -static void mali_free_empty_page_directory(void) -{ - if (MALI_INVALID_PAGE != mali_empty_page_directory) - { - mali_mmu_release_table_page(mali_empty_page_directory); - mali_empty_page_directory = MALI_INVALID_PAGE; - } -} - -static _mali_osk_errcode_t fill_page(mali_io_address mapping, u32 data) -{ - int i; - MALI_DEBUG_ASSERT_POINTER( mapping ); - - for(i = 0; i < MALI_MMU_PAGE_SIZE/4; i++) - { - _mali_osk_mem_iowrite32_relaxed( mapping, i * sizeof(u32), data); - } - _mali_osk_mem_barrier(); - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_allocate_fault_flush_pages(void) -{ - _mali_osk_errcode_t err; - - err = mali_mmu_get_table_page(&mali_page_fault_flush_data_page, &mali_page_fault_flush_data_page_mapping); - if (_MALI_OSK_ERR_OK == err) - { - err = mali_mmu_get_table_page(&mali_page_fault_flush_page_table, &mali_page_fault_flush_page_table_mapping); - if (_MALI_OSK_ERR_OK == err) - { - err = mali_mmu_get_table_page(&mali_page_fault_flush_page_directory, &mali_page_fault_flush_page_directory_mapping); - if (_MALI_OSK_ERR_OK == err) - { - fill_page(mali_page_fault_flush_data_page_mapping, 0); - fill_page(mali_page_fault_flush_page_table_mapping, mali_page_fault_flush_data_page | MALI_MMU_FLAGS_WRITE_PERMISSION | MALI_MMU_FLAGS_READ_PERMISSION | MALI_MMU_FLAGS_PRESENT); - fill_page(mali_page_fault_flush_page_directory_mapping, mali_page_fault_flush_page_table | MALI_MMU_FLAGS_PRESENT); - MALI_SUCCESS; - } - mali_mmu_release_table_page(mali_page_fault_flush_page_table); - mali_page_fault_flush_page_table = MALI_INVALID_PAGE; - mali_page_fault_flush_page_table_mapping = NULL; - } - mali_mmu_release_table_page(mali_page_fault_flush_data_page); - mali_page_fault_flush_data_page = MALI_INVALID_PAGE; - mali_page_fault_flush_data_page_mapping = NULL; - } - MALI_ERROR(err); -} - -static void mali_free_fault_flush_pages(void) -{ - if (MALI_INVALID_PAGE != mali_page_fault_flush_page_directory) - { - mali_mmu_release_table_page(mali_page_fault_flush_page_directory); - mali_page_fault_flush_page_directory = MALI_INVALID_PAGE; - } - - if (MALI_INVALID_PAGE != mali_page_fault_flush_page_table) - { - mali_mmu_release_table_page(mali_page_fault_flush_page_table); - mali_page_fault_flush_page_table = MALI_INVALID_PAGE; - } - - if (MALI_INVALID_PAGE != mali_page_fault_flush_data_page) - { - mali_mmu_release_table_page(mali_page_fault_flush_data_page); - mali_page_fault_flush_data_page = MALI_INVALID_PAGE; - } -} - -static _mali_osk_errcode_t mali_memory_core_load_complete(mali_kernel_subsystem_identifier id) -{ - mali_kernel_memory_mmu * mmu, * temp_mmu; - - /* Report the allocators */ - mali_allocation_engine_report_allocators( physical_memory_allocators ); - - /* allocate the helper pages */ - MALI_CHECK_NO_ERROR( mali_allocate_empty_page_directory() ); - if (_MALI_OSK_ERR_OK != mali_allocate_fault_flush_pages()) - { - mali_free_empty_page_directory(); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* activate the empty page directory on all MMU's */ - _MALI_OSK_LIST_FOREACHENTRY(mmu, temp_mmu, &mmu_head, mali_kernel_memory_mmu, list) - { - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_DTE_ADDR, mali_empty_page_directory); - mali_mmu_enable_paging(mmu); - } - - MALI_DEBUG_PRINT(4, ("MMUs activated\n")); - /* the MMU system is now active */ - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_memory_core_system_info_fill(_mali_system_info* info) -{ - _mali_mem_info * mem_info; - - /* Make sure we won't leak any memory. It could also be that it's an - * uninitialized variable, but the caller should have zeroed the - * variable. */ - MALI_DEBUG_ASSERT(NULL == info->mem_info); - - info->has_mmu = 1; - - mem_info = _mali_osk_calloc(1,sizeof(_mali_mem_info)); - MALI_CHECK_NON_NULL( mem_info, _MALI_OSK_ERR_NOMEM ); - - mem_info->size = 2048UL * 1024UL * 1024UL; - mem_info->maximum_order_supported = 30; - mem_info->flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE |_MALI_GP_READABLE | _MALI_GP_WRITEABLE; - mem_info->identifier = 0; - - info->mem_info = mem_info; - - /* all OK */ - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_memory_core_resource_mmu(_mali_osk_resource_t * resource) -{ - mali_kernel_memory_mmu * mmu; - - MALI_DEBUG_PRINT(4, ("MMU '%s' @ (0x%08X - 0x%08X)\n", - resource->description, resource->base, resource->base + MALI_MMU_REGISTERS_SIZE - 1 - )); - - if (NULL != mali_memory_core_mmu_lookup(resource->mmu_id)) - { - MALI_DEBUG_PRINT(1, ("Duplicate MMU ids found. The id %d is already in use\n", resource->mmu_id)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - if (_MALI_OSK_ERR_OK != _mali_osk_mem_reqregion(resource->base, MALI_MMU_REGISTERS_SIZE, resource->description)) - { - /* specified addresses are already in used by another driver / the kernel */ - MALI_DEBUG_PRINT( - 1, ("Failed to request MMU '%s' register address space at (0x%08X - 0x%08X)\n", - resource->description, resource->base, resource->base + MALI_MMU_REGISTERS_SIZE - 1 - )); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - mmu = _mali_osk_calloc(1, sizeof(mali_kernel_memory_mmu)); - - if (NULL == mmu) - { - MALI_DEBUG_PRINT(1, ("Failed to allocate memory for handling a MMU unit")); - _mali_osk_mem_unreqregion(resource->base, MALI_MMU_REGISTERS_SIZE); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - /* basic setup */ - _MALI_OSK_INIT_LIST_HEAD(&mmu->list); - - mmu->id = resource->mmu_id; - mmu->irq_nr = resource->irq; - mmu->flags = resource->flags; - mmu->base = resource->base; - mmu->mapping_size = MALI_MMU_REGISTERS_SIZE; - mmu->description = resource->description; /* no need to copy */ - _MALI_OSK_INIT_LIST_HEAD(&mmu->callbacks); - _MALI_OSK_INIT_LIST_HEAD(&mmu->session_link); - mmu->in_page_fault_handler = 0; - - mmu->lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_ONELOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, 127-mmu->id); - if (NULL == mmu->lock) - { - MALI_DEBUG_PRINT(1, ("Failed to create mmu lock\n")); - _mali_osk_mem_unreqregion(mmu->base, mmu->mapping_size); - _mali_osk_free(mmu); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* map the registers */ - mmu->mapped_registers = _mali_osk_mem_mapioregion( mmu->base, mmu->mapping_size, mmu->description ); - if (NULL == mmu->mapped_registers) - { - /* failed to map the registers */ - MALI_DEBUG_PRINT(1, ("Failed to map MMU registers at 0x%08X\n", mmu->base)); - _mali_osk_lock_term(mmu->lock); - _mali_osk_mem_unreqregion(mmu->base, MALI_MMU_REGISTERS_SIZE); - _mali_osk_free(mmu); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - MALI_DEBUG_PRINT(4, ("MMU '%s' @ (0x%08X - 0x%08X) mapped to 0x%08X\n", - resource->description, resource->base, resource->base + MALI_MMU_REGISTERS_SIZE - 1, mmu->mapped_registers - )); - - /* setup MMU interrupt mask */ - /* set all values to known defaults */ - mali_mmu_raw_reset(mmu); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_MASK, MALI_MMU_INTERRUPT_PAGE_FAULT | MALI_MMU_INTERRUPT_READ_BUS_ERROR); - /* setup MMU page directory pointer */ - /* The mali_page_directory pointer is guaranteed to be 4kb aligned because we've used get_zeroed_page to accquire it */ - /* convert the kernel virtual address into a physical address and set */ - - /* add to our list of MMU's */ - _mali_osk_list_addtail(&mmu->list, &mmu_head); - - mmu->irq = _mali_osk_irq_init( - mmu->irq_nr, - mali_kernel_memory_mmu_interrupt_handler_upper_half, - mali_kernel_memory_mmu_interrupt_handler_bottom_half, - (_mali_osk_irq_trigger_t)mali_mmu_probe_irq_trigger, - (_mali_osk_irq_ack_t)mali_mmu_probe_irq_acknowledge, - mmu, - "mali_mmu_irq_handlers" - ); - if (NULL == mmu->irq) - { - _mali_osk_list_del(&mmu->list); - _mali_osk_lock_term(mmu->lock); - _mali_osk_mem_unmapioregion( mmu->base, mmu->mapping_size, mmu->mapped_registers ); - _mali_osk_mem_unreqregion(resource->base, MALI_MMU_REGISTERS_SIZE); - _mali_osk_free(mmu); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* set to a known state */ - mali_mmu_raw_reset(mmu); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_MASK, MALI_MMU_INTERRUPT_PAGE_FAULT | MALI_MMU_INTERRUPT_READ_BUS_ERROR); - - MALI_DEBUG_PRINT(2, ("MMU registered\n")); - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_memory_core_resource_fpga(_mali_osk_resource_t * resource) -{ - mali_io_address mapping; - - MALI_DEBUG_PRINT(5, ("FPGA framework '%s' @ (0x%08X - 0x%08X)\n", - resource->description, resource->base, resource->base + sizeof(u32) * 2 - 1 - )); - - mapping = _mali_osk_mem_mapioregion(resource->base + 0x1000, sizeof(u32) * 2, "fpga framework"); - if (mapping) - { - MALI_DEBUG_CODE(u32 data = ) - _mali_osk_mem_ioread32(mapping, 0); - MALI_DEBUG_PRINT(2, ("FPGA framwork '%s' @ 0x%08X:\n", resource->description, resource->base)); - MALI_DEBUG_PRINT(2, ("\tBitfile date: %d%02d%02d_%02d%02d\n", - (data >> 20), - (data >> 16) & 0xF, - (data >> 11) & 0x1F, - (data >> 6) & 0x1F, - (data >> 0) & 0x3F)); - MALI_DEBUG_CODE(data = ) - _mali_osk_mem_ioread32(mapping, sizeof(u32)); - MALI_DEBUG_PRINT(2, ("\tBitfile SCCS rev: %d\n", data)); - - _mali_osk_mem_unmapioregion(resource->base + 0x1000, sizeof(u32) *2, mapping); - } - else MALI_DEBUG_PRINT(1, ("Failed to access FPGA framwork '%s' @ 0x%08X\n", resource->description, resource->base)); - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_memory_core_resource_os_memory(_mali_osk_resource_t * resource) -{ - mali_physical_memory_allocator * allocator; - mali_physical_memory_allocator ** next_allocator_list; - - u32 alloc_order = resource->alloc_order; - - allocator = mali_os_allocator_create(resource->size, resource->cpu_usage_adjust, resource->description); - if (NULL == allocator) - { - MALI_DEBUG_PRINT(1, ("Failed to create OS memory allocator\n")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - allocator->alloc_order = alloc_order; - - /* link in the allocator: insertion into ordered list - * resources of the same alloc_order will be Last-in-first */ - next_allocator_list = &physical_memory_allocators; - - while ( NULL != *next_allocator_list && - (*next_allocator_list)->alloc_order < alloc_order ) - { - next_allocator_list = &((*next_allocator_list)->next); - } - - allocator->next = (*next_allocator_list); - (*next_allocator_list) = allocator; - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_memory_core_resource_dedicated_memory(_mali_osk_resource_t * resource) -{ - mali_physical_memory_allocator * allocator; - mali_physical_memory_allocator ** next_allocator_list; - dedicated_memory_info * cleanup_data; - - u32 alloc_order = resource->alloc_order; - - /* do the lowlevel linux operation first */ - - /* Request ownership of the memory */ - if (_MALI_OSK_ERR_OK != _mali_osk_mem_reqregion(resource->base, resource->size, resource->description)) - { - MALI_DEBUG_PRINT(1, ("Failed to request memory region %s (0x%08X - 0x%08X)\n", resource->description, resource->base, resource->base + resource->size - 1)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* create generic block allocator object to handle it */ - allocator = mali_block_allocator_create(resource->base, resource->cpu_usage_adjust, resource->size, resource->description ); - - if (NULL == allocator) - { - MALI_DEBUG_PRINT(1, ("Memory bank registration failed\n")); - _mali_osk_mem_unreqregion(resource->base, resource->size); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* save lowlevel cleanup info */ - allocator->alloc_order = alloc_order; - - cleanup_data = _mali_osk_malloc(sizeof(dedicated_memory_info)); - - if (NULL == cleanup_data) - { - _mali_osk_mem_unreqregion(resource->base, resource->size); - allocator->destroy(allocator); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - cleanup_data->base = resource->base; - cleanup_data->size = resource->size; - - cleanup_data->next = mem_region_registrations; - mem_region_registrations = cleanup_data; - - /* link in the allocator: insertion into ordered list - * resources of the same alloc_order will be Last-in-first */ - next_allocator_list = &physical_memory_allocators; - - while ( NULL != *next_allocator_list && - (*next_allocator_list)->alloc_order < alloc_order ) - { - next_allocator_list = &((*next_allocator_list)->next); - } - - allocator->next = (*next_allocator_list); - (*next_allocator_list) = allocator; - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t mali_kernel_memory_mmu_interrupt_handler_upper_half(void * data) -{ - mali_kernel_memory_mmu * mmu; - u32 int_stat; - mali_core_renderunit *core; - - if (mali_benchmark) MALI_SUCCESS; - - mmu = (mali_kernel_memory_mmu *)data; - - MALI_DEBUG_ASSERT_POINTER(mmu); - - /* Pointer to core holding this MMU */ - core = (mali_core_renderunit *)mmu->core; - if(core && (CORE_OFF == core->state)) - { - MALI_SUCCESS; - } - - - /* check if it was our device which caused the interrupt (we could be sharing the IRQ line) */ - int_stat = mali_mmu_register_read(mmu, MALI_MMU_REGISTER_INT_STATUS); - if (0 == int_stat) - { - MALI_ERROR(_MALI_OSK_ERR_FAULT); /* no bits set, we are sharing the IRQ line and someone else caused the interrupt */ - } - - - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_MASK, 0); - - mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS); - - if (int_stat & MALI_MMU_INTERRUPT_PAGE_FAULT) - { - _mali_osk_irq_schedulework(mmu->irq); - } - if (int_stat & MALI_MMU_INTERRUPT_READ_BUS_ERROR) - { - /* clear interrupt flag */ - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_CLEAR, MALI_MMU_INTERRUPT_READ_BUS_ERROR); - /* reenable it */ - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_MASK, mali_mmu_register_read(mmu, MALI_MMU_REGISTER_INT_MASK) | MALI_MMU_INTERRUPT_READ_BUS_ERROR); - } - - MALI_SUCCESS; -} - - -static void mali_kernel_mmu_bus_reset(mali_kernel_memory_mmu * mmu) -{ - -#if defined(USING_MALI200) - int i; - const int replay_buffer_check_interval = 10; /* must be below 1000 */ - const int replay_buffer_max_number_of_checks = 100; -#endif - - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - /* add an extra reference while handling the page fault */ - mmu->usage_count++; - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - - MALI_DEBUG_PRINT(4, ("Sending stop bus request to cores\n")); - /* request to stop the bus, but don't wait for it to actually stop */ - _mali_kernel_core_broadcast_subsystem_message(MMU_KILL_STEP1_STOP_BUS_FOR_ALL_CORES, (u32)mmu); - -#if defined(USING_MALI200) - /* no new request will come from any of the connected cores from now - * we must now flush the playback buffer for any requests queued already - */ - - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - - MALI_DEBUG_PRINT(4, ("Switching to the special page fault flush page directory\n")); - /* don't use the mali_mmu_activate_address_space function here as we can't stall the MMU */ - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_DTE_ADDR, mali_page_fault_flush_page_directory); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE); - /* resume the MMU */ - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_CLEAR, MALI_MMU_INTERRUPT_PAGE_FAULT); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_PAGE_FAULT_DONE); - /* the MMU will now play back all the requests, all going to our special page fault flush data page */ - - /* just to be safe, check that the playback buffer is empty before continuing */ - if (!mali_benchmark) { - for (i = 0; i < replay_buffer_max_number_of_checks; i++) - { - if (mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS) & MALI_MMU_STATUS_BIT_REPLAY_BUFFER_EMPTY) break; - _mali_osk_time_ubusydelay(replay_buffer_check_interval); - } - - MALI_DEBUG_PRINT_IF(1, i == replay_buffer_max_number_of_checks, ("MMU: %s: Failed to flush replay buffer on page fault\n", mmu->description)); - MALI_DEBUG_PRINT(1, ("Replay playback took %ld usec\n", i * replay_buffer_check_interval)); - } - - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - -#endif - /* notify all subsystems that the core should be reset once the bus is actually stopped */ - MALI_DEBUG_PRINT(4,("Sending job abort command to subsystems\n")); - _mali_kernel_core_broadcast_subsystem_message(MMU_KILL_STEP2_RESET_ALL_CORES_AND_ABORT_THEIR_JOBS, (u32)mmu); - - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - - /* reprogram the MMU */ - mali_mmu_raw_reset(mmu); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_MASK, MALI_MMU_INTERRUPT_PAGE_FAULT | MALI_MMU_INTERRUPT_READ_BUS_ERROR); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_DTE_ADDR, mali_empty_page_directory); /* no session is active, so just activate the empty page directory */ - mali_mmu_enable_paging(mmu); - - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - - /* release the extra address space reference, will schedule */ - mali_memory_core_mmu_release_address_space_reference(mmu); - - /* resume normal operation */ - _mali_kernel_core_broadcast_subsystem_message(MMU_KILL_STEP3_CONTINUE_JOB_HANDLING, (u32)mmu); - MALI_DEBUG_PRINT(4, ("Page fault handling complete\n")); -} - -static void mali_mmu_raw_reset(mali_kernel_memory_mmu * mmu) -{ - const int max_loop_count = 100; - const int delay_in_usecs = 1; - - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_DTE_ADDR, 0xCAFEBABE); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_SOFT_RESET); - - if (!mali_benchmark) - { - int i; - for (i = 0; i < max_loop_count; ++i) - { - if (mali_mmu_register_read(mmu, MALI_MMU_REGISTER_DTE_ADDR) == 0) - { - break; - } - _mali_osk_time_ubusydelay(delay_in_usecs); - } - MALI_DEBUG_PRINT_IF(1, (max_loop_count == i), ("Reset request failed, MMU status is 0x%08X\n", mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS))); - } -} - -static void mali_mmu_enable_paging(mali_kernel_memory_mmu * mmu) -{ - const int max_loop_count = 100; - const int delay_in_usecs = 1; - - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ENABLE_PAGING); - - if (!mali_benchmark) - { - int i; - for (i = 0; i < max_loop_count; ++i) - { - if (mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS) & MALI_MMU_STATUS_BIT_PAGING_ENABLED) - { - break; - } - _mali_osk_time_ubusydelay(delay_in_usecs); - } - MALI_DEBUG_PRINT_IF(1, (max_loop_count == i), ("Enable paging request failed, MMU status is 0x%08X\n", mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS))); - } -} - -static mali_bool mali_mmu_enable_stall(mali_kernel_memory_mmu * mmu) -{ - const int max_loop_count = 100; - const int delay_in_usecs = 999; - int i; - - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ENABLE_STALL); - - if (!mali_benchmark) - { - for (i = 0; i < max_loop_count; ++i) - { - if (mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS) & MALI_MMU_STATUS_BIT_STALL_ACTIVE) - { - break; - } - _mali_osk_time_ubusydelay(delay_in_usecs); - } - MALI_DEBUG_PRINT_IF(1, (max_loop_count == i), ("Enable stall request failed, MMU status is 0x%08X\n", mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS))); - if (max_loop_count == i) - { - return MALI_FALSE; - } - } - - return MALI_TRUE; -} - -static void mali_mmu_disable_stall(mali_kernel_memory_mmu * mmu) -{ - const int max_loop_count = 100; - const int delay_in_usecs = 1; - int i; - - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_DISABLE_STALL); - - if (!mali_benchmark) - { - for (i = 0; i < max_loop_count; ++i) - { - if ((mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS) & MALI_MMU_STATUS_BIT_STALL_ACTIVE) == 0) - { - break; - } - _mali_osk_time_ubusydelay(delay_in_usecs); - } - MALI_DEBUG_PRINT_IF(1, (max_loop_count == i), ("Disable stall request failed, MMU status is 0x%08X\n", mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS))); - } -} - -void mali_kernel_mmu_reset(void * input_mmu) -{ - mali_kernel_memory_mmu * mmu; - MALI_DEBUG_ASSERT_POINTER(input_mmu); - mmu = (mali_kernel_memory_mmu *)input_mmu; - - MALI_DEBUG_PRINT(4, ("Mali MMU: mali_kernel_mmu_reset: %s\n", mmu->description)); - - if ( 0 != mmu->in_page_fault_handler) - { - /* This is possible if the bus can never be stopped for some reason */ - MALI_PRINT_ERROR(("Stopping the Memory bus not possible. Mali reset could not be performed.")); - return; - } - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - mali_mmu_raw_reset(mmu); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_MASK, MALI_MMU_INTERRUPT_PAGE_FAULT | MALI_MMU_INTERRUPT_READ_BUS_ERROR); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_DTE_ADDR, mali_empty_page_directory); /* no session is active, so just activate the empty page directory */ - mali_mmu_enable_paging(mmu); - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - -} - -void mali_kernel_mmu_force_bus_reset(void * input_mmu) -{ - mali_kernel_memory_mmu * mmu; - MALI_DEBUG_ASSERT_POINTER(input_mmu); - mmu = (mali_kernel_memory_mmu *)input_mmu; - if ( 0 != mmu->in_page_fault_handler) - { - /* This is possible if the bus can never be stopped for some reason */ - MALI_PRINT_ERROR(("Stopping the Memory bus not possible. Mali reset could not be performed.")); - return; - } - MALI_DEBUG_PRINT(1, ("Mali MMU: Force_bus_reset.\n")); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_MASK, 0); - mali_kernel_mmu_bus_reset(mmu); -} - - -static void mali_kernel_memory_mmu_interrupt_handler_bottom_half(void * data) -{ - mali_kernel_memory_mmu * mmu; - u32 raw, fault_address, status; - mali_core_renderunit *core; - - MALI_DEBUG_PRINT(1, ("mali_kernel_memory_mmu_interrupt_handler_bottom_half\n")); - if (NULL == data) - { - MALI_PRINT_ERROR(("MMU IRQ work queue: NULL argument")); - return; /* Error */ - } - mmu = (mali_kernel_memory_mmu*)data; - - MALI_DEBUG_PRINT(4, ("Locking subsystems\n")); - /* lock all subsystems */ - _mali_kernel_core_broadcast_subsystem_message(MMU_KILL_STEP0_LOCK_SUBSYSTEM, (u32)mmu); - - /* Pointer to core holding this MMU */ - core = (mali_core_renderunit *)mmu->core; - - if(CORE_OFF == core->state) - { - _mali_kernel_core_broadcast_subsystem_message(MMU_KILL_STEP4_UNLOCK_SUBSYSTEM, (u32)mmu); - return; - } - - raw = mali_mmu_register_read(mmu, MALI_MMU_REGISTER_INT_RAWSTAT); - status = mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS); - - if ( (0==(raw & MALI_MMU_INTERRUPT_PAGE_FAULT)) && (0==(status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE)) ) - { - MALI_DEBUG_PRINT(1, ("MMU: Page fault bottom half: No Irq found.\n")); - MALI_DEBUG_PRINT(4, ("Unlocking subsystems")); - _mali_kernel_core_broadcast_subsystem_message(MMU_KILL_STEP4_UNLOCK_SUBSYSTEM, (u32)mmu); - return; - } - - mmu->in_page_fault_handler = 1; - - fault_address = mali_mmu_register_read(mmu, MALI_MMU_REGISTER_PAGE_FAULT_ADDR); - MALI_PRINT(("Page fault detected at 0x%x from bus id %d of type %s on %s\n", - (void*)fault_address, - (status >> 6) & 0x1F, - (status & 32) ? "write" : "read", - mmu->description) - ); - - if (NULL == mmu->active_session) - { - MALI_PRINT(("Spurious memory access detected from MMU %s\n", mmu->description)); - } - else - { - MALI_PRINT(("Active page directory at 0x%08X\n", mmu->active_session->page_directory)); - MALI_PRINT(("Info from page table for VA 0x%x:\n", (void*)fault_address)); - MALI_PRINT(("DTE entry: PTE at 0x%x marked as %s\n", - (void*)(_mali_osk_mem_ioread32(mmu->active_session->page_directory_mapped, - MALI_MMU_PDE_ENTRY(fault_address) * sizeof(u32)) & ~MALI_MMU_FLAGS_MASK), - _mali_osk_mem_ioread32(mmu->active_session->page_directory_mapped, - MALI_MMU_PDE_ENTRY(fault_address) * sizeof(u32)) & MALI_MMU_FLAGS_PRESENT ? "present" : "not present" - )); - - if (_mali_osk_mem_ioread32(mmu->active_session->page_directory_mapped, MALI_MMU_PDE_ENTRY(fault_address) * sizeof(u32)) & MALI_MMU_FLAGS_PRESENT) - { - mali_io_address pte; - u32 data; - pte = mmu->active_session->page_entries_mapped[MALI_MMU_PDE_ENTRY(fault_address)]; - data = _mali_osk_mem_ioread32(pte, MALI_MMU_PTE_ENTRY(fault_address) * sizeof(u32)); - MALI_PRINT(("PTE entry: Page at 0x%x, %s %s %s\n", - (void*)(data & ~MALI_MMU_FLAGS_MASK), - data & MALI_MMU_FLAGS_PRESENT ? "present" : "not present", - data & MALI_MMU_FLAGS_READ_PERMISSION ? "readable" : "", - data & MALI_MMU_FLAGS_WRITE_PERMISSION ? "writable" : "" - )); - } - else - { - MALI_PRINT(("PTE entry: Not present\n")); - } - } - - - mali_kernel_mmu_bus_reset(mmu); - - mmu->in_page_fault_handler = 0; - - /* unlock all subsystems */ - MALI_DEBUG_PRINT(4, ("Unlocking subsystems")); - _mali_kernel_core_broadcast_subsystem_message(MMU_KILL_STEP4_UNLOCK_SUBSYSTEM, (u32)mmu); - -} - - -static u32 mali_mmu_register_read(mali_kernel_memory_mmu * unit, mali_mmu_register reg) -{ - u32 val; - - if (mali_benchmark) return 0; - - val = _mali_osk_mem_ioread32(unit->mapped_registers, (u32)reg * sizeof(u32)); - - MALI_DEBUG_PRINT(6, ("mali_mmu_register_read addr:0x%04X val:0x%08x\n", (u32)reg * sizeof(u32),val)); - - return val; -} - -static void mali_mmu_register_write(mali_kernel_memory_mmu * unit, mali_mmu_register reg, u32 val) -{ - if (mali_benchmark) return; - - MALI_DEBUG_PRINT(6, ("mali_mmu_register_write addr:0x%04X val:0x%08x\n", (u32)reg * sizeof(u32), val)); - - _mali_osk_mem_iowrite32(unit->mapped_registers, (u32)reg * sizeof(u32), val); -} - -#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 -static mali_physical_memory_allocation_result ump_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info) -{ - ump_dd_handle ump_mem; - u32 nr_blocks; - u32 i; - ump_dd_physical_block * ump_blocks; - ump_mem_allocation *ret_allocation; - - MALI_DEBUG_ASSERT_POINTER(ctx); - MALI_DEBUG_ASSERT_POINTER(engine); - MALI_DEBUG_ASSERT_POINTER(descriptor); - MALI_DEBUG_ASSERT_POINTER(alloc_info); - - ret_allocation = _mali_osk_malloc( sizeof( ump_mem_allocation ) ); - if ( NULL==ret_allocation ) return MALI_MEM_ALLOC_INTERNAL_FAILURE; - - ump_mem = (ump_dd_handle)ctx; - - MALI_DEBUG_PRINT(4, ("In ump_memory_commit\n")); - - nr_blocks = ump_dd_phys_block_count_get(ump_mem); - - MALI_DEBUG_PRINT(4, ("Have %d blocks\n", nr_blocks)); - - if (nr_blocks == 0) - { - MALI_DEBUG_PRINT(1, ("No block count\n")); - _mali_osk_free( ret_allocation ); - return MALI_MEM_ALLOC_INTERNAL_FAILURE; - } - - ump_blocks = _mali_osk_malloc(sizeof(*ump_blocks)*nr_blocks ); - if ( NULL==ump_blocks ) - { - _mali_osk_free( ret_allocation ); - return MALI_MEM_ALLOC_INTERNAL_FAILURE; - } - - if (UMP_DD_INVALID == ump_dd_phys_blocks_get(ump_mem, ump_blocks, nr_blocks)) - { - _mali_osk_free(ump_blocks); - _mali_osk_free( ret_allocation ); - return MALI_MEM_ALLOC_INTERNAL_FAILURE; - } - - /* Store away the initial offset for unmapping purposes */ - ret_allocation->initial_offset = *offset; - - for(i=0; i<nr_blocks; ++i) - { - MALI_DEBUG_PRINT(4, ("Mapping in 0x%08x size %d\n", ump_blocks[i].addr , ump_blocks[i].size)); - if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, ump_blocks[i].addr , 0, ump_blocks[i].size )) - { - u32 size_allocated = *offset - ret_allocation->initial_offset; - MALI_DEBUG_PRINT(1, ("Mapping of external memory failed\n")); - - /* unmap all previous blocks (if any) */ - mali_allocation_engine_unmap_physical(engine, descriptor, ret_allocation->initial_offset, size_allocated, (_mali_osk_mem_mapregion_flags_t)0 ); - - _mali_osk_free(ump_blocks); - _mali_osk_free(ret_allocation); - return MALI_MEM_ALLOC_INTERNAL_FAILURE; - } - *offset += ump_blocks[i].size; - } - - if (descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE) - { - /* Map in an extra virtual guard page at the end of the VMA */ - MALI_DEBUG_PRINT(4, ("Mapping in extra guard page\n")); - if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, ump_blocks[0].addr , 0, _MALI_OSK_MALI_PAGE_SIZE )) - { - u32 size_allocated = *offset - ret_allocation->initial_offset; - MALI_DEBUG_PRINT(1, ("Mapping of external memory (guard page) failed\n")); - - /* unmap all previous blocks (if any) */ - mali_allocation_engine_unmap_physical(engine, descriptor, ret_allocation->initial_offset, size_allocated, (_mali_osk_mem_mapregion_flags_t)0 ); - - _mali_osk_free(ump_blocks); - _mali_osk_free(ret_allocation); - return MALI_MEM_ALLOC_INTERNAL_FAILURE; - } - *offset += _MALI_OSK_MALI_PAGE_SIZE; - } - - _mali_osk_free( ump_blocks ); - - ret_allocation->engine = engine; - ret_allocation->descriptor = descriptor; - ret_allocation->ump_mem = ump_mem; - ret_allocation->size_allocated = *offset - ret_allocation->initial_offset; - - alloc_info->ctx = NULL; - alloc_info->handle = ret_allocation; - alloc_info->next = NULL; - alloc_info->release = ump_memory_release; - - return MALI_MEM_ALLOC_FINISHED; -} - -static void ump_memory_release(void * ctx, void * handle) -{ - ump_dd_handle ump_mem; - ump_mem_allocation *allocation; - - allocation = (ump_mem_allocation *)handle; - - MALI_DEBUG_ASSERT_POINTER( allocation ); - - ump_mem = allocation->ump_mem; - - MALI_DEBUG_ASSERT(UMP_DD_HANDLE_INVALID!=ump_mem); - - /* At present, this is a no-op. But, it allows the mali_address_manager to - * do unmapping of a subrange in future. */ - mali_allocation_engine_unmap_physical( allocation->engine, - allocation->descriptor, - allocation->initial_offset, - allocation->size_allocated, - (_mali_osk_mem_mapregion_flags_t)0 - ); - _mali_osk_free( allocation ); - - - ump_dd_reference_release(ump_mem) ; - return; -} - -_mali_osk_errcode_t _mali_ukk_attach_ump_mem( _mali_uk_attach_ump_mem_s *args ) -{ - ump_dd_handle ump_mem; - mali_physical_memory_allocator external_memory_allocator; - memory_session * session_data; - mali_memory_allocation * descriptor; - int md; - - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - - session_data = (memory_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_memory_id); - MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); - - /* check arguments */ - /* NULL might be a valid Mali address */ - if ( ! args->size) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - - /* size must be a multiple of the system page size */ - if ( args->size % _MALI_OSK_MALI_PAGE_SIZE ) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - - MALI_DEBUG_PRINT(3, - ("Requested to map ump memory with secure id %d into virtual memory 0x%08X, size 0x%08X\n", - args->secure_id, args->mali_address, args->size)); - - ump_mem = ump_dd_handle_create_from_secure_id( (int)args->secure_id ) ; - - if ( UMP_DD_HANDLE_INVALID==ump_mem ) MALI_ERROR(_MALI_OSK_ERR_FAULT); - - descriptor = _mali_osk_calloc(1, sizeof(mali_memory_allocation)); - if (NULL == descriptor) - { - ump_dd_reference_release(ump_mem); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - descriptor->size = args->size; - descriptor->mapping = NULL; - descriptor->mali_address = args->mali_address; - descriptor->mali_addr_mapping_info = (void*)session_data; - descriptor->process_addr_mapping_info = NULL; /* do not map to process address space */ - descriptor->lock = session_data->lock; - if (args->flags & _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE) - { - descriptor->flags = MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE; - } - _mali_osk_list_init( &descriptor->list ); - - if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session_data->descriptor_mapping, descriptor, &md)) - { - ump_dd_reference_release(ump_mem); - _mali_osk_free(descriptor); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - external_memory_allocator.allocate = ump_memory_commit; - external_memory_allocator.allocate_page_table_block = NULL; - external_memory_allocator.ctx = ump_mem; - external_memory_allocator.name = "UMP Memory"; - external_memory_allocator.next = NULL; - - _mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - if (_MALI_OSK_ERR_OK != mali_allocation_engine_allocate_memory(memory_engine, descriptor, &external_memory_allocator, NULL)) - { - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - mali_descriptor_mapping_free(session_data->descriptor_mapping, md); - ump_dd_reference_release(ump_mem); - _mali_osk_free(descriptor); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - args->cookie = md; - - MALI_DEBUG_PRINT(5,("Returning from UMP attach\n")); - - /* All OK */ - MALI_SUCCESS; -} - - -_mali_osk_errcode_t _mali_ukk_release_ump_mem( _mali_uk_release_ump_mem_s *args ) -{ - mali_memory_allocation * descriptor; - memory_session * session_data; - - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - - session_data = (memory_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_memory_id); - MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); - - if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_get(session_data->descriptor_mapping, args->cookie, (void**)&descriptor)) - { - MALI_DEBUG_PRINT(1, ("Invalid memory descriptor %d used to release ump memory\n", args->cookie)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - mali_descriptor_mapping_free(session_data->descriptor_mapping, args->cookie); - - _mali_osk_lock_wait( session_data->lock, _MALI_OSK_LOCKMODE_RW ); - - mali_allocation_engine_release_memory(memory_engine, descriptor); - - _mali_osk_lock_signal( session_data->lock, _MALI_OSK_LOCKMODE_RW ); - - _mali_osk_free(descriptor); - - MALI_SUCCESS; - -} -#endif /* MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 */ - - -static mali_physical_memory_allocation_result external_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info) -{ - u32 * data; - external_mem_allocation * ret_allocation; - - MALI_DEBUG_ASSERT_POINTER(ctx); - MALI_DEBUG_ASSERT_POINTER(engine); - MALI_DEBUG_ASSERT_POINTER(descriptor); - MALI_DEBUG_ASSERT_POINTER(alloc_info); - - ret_allocation = _mali_osk_malloc( sizeof(external_mem_allocation) ); - - if ( NULL == ret_allocation ) - { - return MALI_MEM_ALLOC_INTERNAL_FAILURE; - } - - data = (u32*)ctx; - - ret_allocation->engine = engine; - ret_allocation->descriptor = descriptor; - ret_allocation->initial_offset = *offset; - - alloc_info->ctx = NULL; - alloc_info->handle = ret_allocation; - alloc_info->next = NULL; - alloc_info->release = external_memory_release; - - MALI_DEBUG_PRINT(3, ("External map: mapping phys 0x%08X at mali virtual address 0x%08X staring at offset 0x%08X length 0x%08X\n", data[0], descriptor->mali_address, *offset, data[1])); - - if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, data[0], 0, data[1])) - { - MALI_DEBUG_PRINT(1, ("Mapping of external memory failed\n")); - _mali_osk_free(ret_allocation); - return MALI_MEM_ALLOC_INTERNAL_FAILURE; - } - *offset += data[1]; - - if (descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE) - { - /* Map in an extra virtual guard page at the end of the VMA */ - MALI_DEBUG_PRINT(4, ("Mapping in extra guard page\n")); - if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, data[0], 0, _MALI_OSK_MALI_PAGE_SIZE)) - { - u32 size_allocated = *offset - ret_allocation->initial_offset; - MALI_DEBUG_PRINT(1, ("Mapping of external memory (guard page) failed\n")); - - /* unmap what we previously mapped */ - mali_allocation_engine_unmap_physical(engine, descriptor, ret_allocation->initial_offset, size_allocated, (_mali_osk_mem_mapregion_flags_t)0 ); - _mali_osk_free(ret_allocation); - return MALI_MEM_ALLOC_INTERNAL_FAILURE; - } - *offset += _MALI_OSK_MALI_PAGE_SIZE; - } - - ret_allocation->size = *offset - ret_allocation->initial_offset; - - return MALI_MEM_ALLOC_FINISHED; -} - -static void external_memory_release(void * ctx, void * handle) -{ - external_mem_allocation * allocation; - - allocation = (external_mem_allocation *) handle; - MALI_DEBUG_ASSERT_POINTER( allocation ); - - /* At present, this is a no-op. But, it allows the mali_address_manager to - * do unmapping of a subrange in future. */ - - mali_allocation_engine_unmap_physical( allocation->engine, - allocation->descriptor, - allocation->initial_offset, - allocation->size, - (_mali_osk_mem_mapregion_flags_t)0 - ); - - _mali_osk_free( allocation ); - - return; -} - -_mali_osk_errcode_t _mali_ukk_map_external_mem( _mali_uk_map_external_mem_s *args ) -{ - mali_physical_memory_allocator external_memory_allocator; - memory_session * session_data; - u32 info[2]; - mali_memory_allocation * descriptor; - int md; - - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - - session_data = (memory_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_memory_id); - MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); - - external_memory_allocator.allocate = external_memory_commit; - external_memory_allocator.allocate_page_table_block = NULL; - external_memory_allocator.ctx = &info[0]; - external_memory_allocator.name = "External Memory"; - external_memory_allocator.next = NULL; - - /* check arguments */ - /* NULL might be a valid Mali address */ - if ( ! args->size) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - - /* size must be a multiple of the system page size */ - if ( args->size % _MALI_OSK_MALI_PAGE_SIZE ) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - - MALI_DEBUG_PRINT(3, - ("Requested to map physical memory 0x%x-0x%x into virtual memory 0x%x\n", - (void*)args->phys_addr, - (void*)(args->phys_addr + args->size -1), - (void*)args->mali_address) - ); - - /* Validate the mali physical range */ - MALI_CHECK_NO_ERROR( mali_kernel_core_validate_mali_phys_range( args->phys_addr, args->size ) ); - - info[0] = args->phys_addr; - info[1] = args->size; - - descriptor = _mali_osk_calloc(1, sizeof(mali_memory_allocation)); - if (NULL == descriptor) MALI_ERROR(_MALI_OSK_ERR_NOMEM); - - descriptor->size = args->size; - descriptor->mapping = NULL; - descriptor->mali_address = args->mali_address; - descriptor->mali_addr_mapping_info = (void*)session_data; - descriptor->process_addr_mapping_info = NULL; /* do not map to process address space */ - descriptor->lock = session_data->lock; - if (args->flags & _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE) - { - descriptor->flags = MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE; - } - _mali_osk_list_init( &descriptor->list ); - - if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session_data->descriptor_mapping, descriptor, &md)) - { - _mali_osk_free(descriptor); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - _mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - if (_MALI_OSK_ERR_OK != mali_allocation_engine_allocate_memory(memory_engine, descriptor, &external_memory_allocator, NULL)) - { - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - mali_descriptor_mapping_free(session_data->descriptor_mapping, md); - _mali_osk_free(descriptor); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - args->cookie = md; - - MALI_DEBUG_PRINT(5,("Returning from range_map_external_memory\n")); - - /* All OK */ - MALI_SUCCESS; -} - - -_mali_osk_errcode_t _mali_ukk_unmap_external_mem( _mali_uk_unmap_external_mem_s *args ) -{ - mali_memory_allocation * descriptor; - memory_session * session_data; - - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - - session_data = (memory_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_memory_id); - MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); - - if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_get(session_data->descriptor_mapping, args->cookie, (void**)&descriptor)) - { - MALI_DEBUG_PRINT(1, ("Invalid memory descriptor %d used to unmap external memory\n", args->cookie)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - mali_descriptor_mapping_free(session_data->descriptor_mapping, args->cookie); - - _mali_osk_lock_wait( session_data->lock, _MALI_OSK_LOCKMODE_RW ); - - mali_allocation_engine_release_memory(memory_engine, descriptor); - - _mali_osk_lock_signal( session_data->lock, _MALI_OSK_LOCKMODE_RW ); - - _mali_osk_free(descriptor); - - MALI_SUCCESS; -} - -_mali_osk_errcode_t _mali_ukk_init_mem( _mali_uk_init_mem_s *args ) -{ - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - - args->memory_size = 2 * 1024 * 1024 * 1024UL; /* 2GB address space */ - args->mali_address_base = 1 * 1024 * 1024 * 1024UL; /* staring at 1GB, causing this layout: (0-1GB unused)(1GB-3G usage by Mali)(3G-4G unused) */ - MALI_SUCCESS; -} - -_mali_osk_errcode_t _mali_ukk_term_mem( _mali_uk_term_mem_s *args ) -{ - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - MALI_SUCCESS; -} - -_mali_osk_errcode_t mali_mmu_page_table_cache_create(void) -{ - page_table_cache.lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_ONELOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, 110); - MALI_CHECK_NON_NULL( page_table_cache.lock, _MALI_OSK_ERR_FAULT ); - _MALI_OSK_INIT_LIST_HEAD(&page_table_cache.partial); - _MALI_OSK_INIT_LIST_HEAD(&page_table_cache.full); - MALI_SUCCESS; -} - -void mali_mmu_page_table_cache_destroy(void) -{ - mali_mmu_page_table_allocation * alloc, *temp; - - _MALI_OSK_LIST_FOREACHENTRY(alloc, temp, &page_table_cache.partial, mali_mmu_page_table_allocation, list) - { - MALI_DEBUG_PRINT_IF(1, 0 != alloc->usage_count, ("Destroying page table cache while pages are tagged as in use. %d allocations still marked as in use.\n", alloc->usage_count)); - _mali_osk_list_del(&alloc->list); - alloc->pages.release(&alloc->pages); - _mali_osk_free(alloc->usage_map); - _mali_osk_free(alloc); - } - - MALI_DEBUG_PRINT_IF(1, 0 == _mali_osk_list_empty(&page_table_cache.full), ("Page table cache full list contains one or more elements \n")); - - _MALI_OSK_LIST_FOREACHENTRY(alloc, temp, &page_table_cache.full, mali_mmu_page_table_allocation, list) - { - MALI_DEBUG_PRINT(1, ("Destroy alloc 0x%08X with usage count %d\n", (u32)alloc, alloc->usage_count)); - _mali_osk_list_del(&alloc->list); - alloc->pages.release(&alloc->pages); - _mali_osk_free(alloc->usage_map); - _mali_osk_free(alloc); - } - - _mali_osk_lock_term(page_table_cache.lock); -} - -_mali_osk_errcode_t mali_mmu_get_table_page(u32 *table_page, mali_io_address *mapping) -{ - _mali_osk_lock_wait(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); - - if (0 == _mali_osk_list_empty(&page_table_cache.partial)) - { - mali_mmu_page_table_allocation * alloc = _MALI_OSK_LIST_ENTRY(page_table_cache.partial.next, mali_mmu_page_table_allocation, list); - int page_number = _mali_osk_find_first_zero_bit(alloc->usage_map, alloc->num_pages); - MALI_DEBUG_PRINT(6, ("Partial page table allocation found, using page offset %d\n", page_number)); - _mali_osk_set_nonatomic_bit(page_number, alloc->usage_map); - alloc->usage_count++; - if (alloc->num_pages == alloc->usage_count) - { - /* full, move alloc to full list*/ - _mali_osk_list_move(&alloc->list, &page_table_cache.full); - } - _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); - - *table_page = (MALI_MMU_PAGE_SIZE * page_number) + alloc->pages.phys_base; - *mapping = (mali_io_address)((MALI_MMU_PAGE_SIZE * page_number) + (u32)alloc->pages.mapping); - MALI_DEBUG_PRINT(4, ("Page table allocated for VA=0x%08X, MaliPA=0x%08X\n", *mapping, *table_page )); - MALI_SUCCESS; - } - else - { - mali_mmu_page_table_allocation * alloc; - /* no free pages, allocate a new one */ - - alloc = (mali_mmu_page_table_allocation *)_mali_osk_calloc(1, sizeof(mali_mmu_page_table_allocation)); - if (NULL == alloc) - { - _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); - *table_page = MALI_INVALID_PAGE; - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - _MALI_OSK_INIT_LIST_HEAD(&alloc->list); - - if (_MALI_OSK_ERR_OK != mali_allocation_engine_allocate_page_tables(memory_engine, &alloc->pages, physical_memory_allocators)) - { - MALI_DEBUG_PRINT(1, ("No more memory for page tables\n")); - _mali_osk_free(alloc); - _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); - *table_page = MALI_INVALID_PAGE; - *mapping = NULL; - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - /* create the usage map */ - alloc->num_pages = alloc->pages.size / MALI_MMU_PAGE_SIZE; - alloc->usage_count = 1; - MALI_DEBUG_PRINT(3, ("New page table cache expansion, %d pages in new cache allocation\n", alloc->num_pages)); - alloc->usage_map = _mali_osk_calloc(1, ((alloc->num_pages + BITS_PER_LONG - 1) & ~(BITS_PER_LONG-1) / BITS_PER_LONG) * sizeof(unsigned long)); - if (NULL == alloc->usage_map) - { - MALI_DEBUG_PRINT(1, ("Failed to allocate memory to describe MMU page table cache usage\n")); - alloc->pages.release(&alloc->pages); - _mali_osk_free(alloc); - _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); - *table_page = MALI_INVALID_PAGE; - *mapping = NULL; - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - - /* clear memory allocation */ - fill_page(alloc->pages.mapping, 0); - - _mali_osk_set_nonatomic_bit(0, alloc->usage_map); - - if (alloc->num_pages > 1) - { - _mali_osk_list_add(&alloc->list, &page_table_cache.partial); - } - else - { - _mali_osk_list_add(&alloc->list, &page_table_cache.full); - } - - _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); - *table_page = alloc->pages.phys_base; /* return the first page */ - *mapping = alloc->pages.mapping; /* Mapping for first page */ - MALI_DEBUG_PRINT(4, ("Page table allocated for VA=0x%08X, MaliPA=0x%08X\n", *mapping, *table_page )); - MALI_SUCCESS; - } -} - -void mali_mmu_release_table_page(u32 pa) -{ - mali_mmu_page_table_allocation * alloc, * temp_alloc; - - MALI_DEBUG_PRINT_IF(1, pa & 4095, ("Bad page address 0x%x given to mali_mmu_release_table_page\n", (void*)pa)); - - MALI_DEBUG_PRINT(4, ("Releasing table page 0x%08X to the cache\n", pa)); - - _mali_osk_lock_wait(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); - - /* find the entry this address belongs to */ - /* first check the partial list */ - _MALI_OSK_LIST_FOREACHENTRY(alloc, temp_alloc, &page_table_cache.partial, mali_mmu_page_table_allocation, list) - { - u32 start = alloc->pages.phys_base; - u32 last = start + (alloc->num_pages - 1) * MALI_MMU_PAGE_SIZE; - if (pa >= start && pa <= last) - { - MALI_DEBUG_ASSERT(0 != _mali_osk_test_bit((pa - start)/MALI_MMU_PAGE_SIZE, alloc->usage_map)); - _mali_osk_clear_nonatomic_bit((pa - start)/MALI_MMU_PAGE_SIZE, alloc->usage_map); - alloc->usage_count--; - - _mali_osk_memset((void*)( ((u32)alloc->pages.mapping) + (pa - start) ), 0, MALI_MMU_PAGE_SIZE); - - if (0 == alloc->usage_count) - { - /* empty, release whole page alloc */ - _mali_osk_list_del(&alloc->list); - alloc->pages.release(&alloc->pages); - _mali_osk_free(alloc->usage_map); - _mali_osk_free(alloc); - } - _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); - MALI_DEBUG_PRINT(4, ("(partial list)Released table page 0x%08X to the cache\n", pa)); - return; - } - } - - /* the check the full list */ - _MALI_OSK_LIST_FOREACHENTRY(alloc, temp_alloc, &page_table_cache.full, mali_mmu_page_table_allocation, list) - { - u32 start = alloc->pages.phys_base; - u32 last = start + (alloc->num_pages - 1) * MALI_MMU_PAGE_SIZE; - if (pa >= start && pa <= last) - { - _mali_osk_clear_nonatomic_bit((pa - start)/MALI_MMU_PAGE_SIZE, alloc->usage_map); - alloc->usage_count--; - - _mali_osk_memset((void*)( ((u32)alloc->pages.mapping) + (pa - start) ), 0, MALI_MMU_PAGE_SIZE); - - - if (0 == alloc->usage_count) - { - /* empty, release whole page alloc */ - _mali_osk_list_del(&alloc->list); - alloc->pages.release(&alloc->pages); - _mali_osk_free(alloc->usage_map); - _mali_osk_free(alloc); - } - else - { - /* transfer to partial list */ - _mali_osk_list_move(&alloc->list, &page_table_cache.partial); - } - - _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); - MALI_DEBUG_PRINT(4, ("(full list)Released table page 0x%08X to the cache\n", pa)); - return; - } - } - - MALI_DEBUG_PRINT(1, ("pa 0x%x not found in the page table cache\n", (void*)pa)); - - _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); -} - -void* mali_memory_core_mmu_lookup(u32 id) -{ - mali_kernel_memory_mmu * mmu, * temp_mmu; - - /* find an MMU with a matching id */ - _MALI_OSK_LIST_FOREACHENTRY(mmu, temp_mmu, &mmu_head, mali_kernel_memory_mmu, list) - { - if (id == mmu->id) return mmu; - } - - /* not found */ - return NULL; -} - -void mali_memory_core_mmu_owner(void *core, void *mmu_ptr) -{ - mali_kernel_memory_mmu *mmu; - - MALI_DEBUG_ASSERT_POINTER(mmu_ptr); - MALI_DEBUG_ASSERT_POINTER(core); - - mmu = (mali_kernel_memory_mmu *)mmu_ptr; - mmu->core = core; -} - -void mali_mmu_activate_address_space(mali_kernel_memory_mmu * mmu, u32 page_directory) -{ - mali_mmu_enable_stall(mmu); /* this might fail, but changing the DTE address and ZAP should work anyway... */ - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_DTE_ADDR, page_directory); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE); - mali_mmu_disable_stall(mmu); -} - -_mali_osk_errcode_t mali_memory_core_mmu_activate_page_table(void* mmu_ptr, struct mali_session_data * mali_session_data, void(*callback)(void*), void * callback_argument) -{ - memory_session * requested_memory_session; - _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; - mali_kernel_memory_mmu * mmu; - - MALI_DEBUG_ASSERT_POINTER(mmu_ptr); - MALI_DEBUG_ASSERT_POINTER(mali_session_data); - - mmu = (mali_kernel_memory_mmu *)mmu_ptr; - - MALI_DEBUG_PRINT(4, ("Asked to activate page table for session 0x%x on MMU %s\n", mali_session_data, mmu->description)); - requested_memory_session = mali_kernel_session_manager_slot_get(mali_session_data, mali_subsystem_memory_id); - MALI_DEBUG_PRINT(5, ("Session 0x%x looked up as using memory session 0x%x\n", mali_session_data, requested_memory_session)); - - MALI_DEBUG_ASSERT_POINTER(requested_memory_session); - - MALI_DEBUG_PRINT(7, ("Taking locks\n")); - - _mali_osk_lock_wait(requested_memory_session->lock, _MALI_OSK_LOCKMODE_RW); - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - if (0 == mmu->usage_count) - { - /* no session currently active, activate the requested session */ - MALI_DEBUG_ASSERT(NULL == mmu->active_session); - mmu->active_session = requested_memory_session; - mmu->usage_count = 1; - MALI_DEBUG_PRINT(4, ("MMU idle, activating page directory 0x%08X on MMU %s\n", requested_memory_session->page_directory, mmu->description)); - mali_mmu_activate_address_space(mmu, requested_memory_session->page_directory); - { - /* Insert mmu into the right place in the active_mmus list so that - * it is still sorted. The list must be sorted by ID so we can get - * the mutexes in the right order in - * _mali_ukk_mem_munmap_internal(). - */ - _mali_osk_list_t *entry; - for (entry = requested_memory_session->active_mmus.next; - entry != &requested_memory_session->active_mmus; - entry = entry->next) - { - mali_kernel_memory_mmu *temp = _MALI_OSK_LIST_ENTRY(entry, mali_kernel_memory_mmu, session_link); - if (mmu->id < temp->id) - break; - } - /* If we broke out, then 'entry' points to the list node of the - * first mmu with a greater ID; otherwise, it points to - * active_mmus. We want to add *before* this node. - */ - _mali_osk_list_addtail(&mmu->session_link, entry); - } - err = _MALI_OSK_ERR_OK; - } - - /* Allow two cores to run in parallel if they come from the same session */ - else if ( - (mmu->in_page_fault_handler == 0) && - (requested_memory_session == mmu->active_session ) && - (0==(MALI_MMU_DISALLOW_PARALLELL_WORK_OF_MALI_CORES & mmu->flags)) - ) - { - /* nested activation detected, just update the reference count */ - MALI_DEBUG_PRINT(4, ("Nested activation detected, %d previous activations found\n", mmu->usage_count)); - mmu->usage_count++; - err = _MALI_OSK_ERR_OK; - } - - else if (NULL != callback) - { - /* can't activate right now, notify caller on idle via callback */ - mali_kernel_memory_mmu_idle_callback * callback_object, * temp_callback_object; - int found = 0; - - MALI_DEBUG_PRINT(3, ("The MMU is busy and is using a different address space, callback given\n")); - /* check for existing registration */ - _MALI_OSK_LIST_FOREACHENTRY(callback_object, temp_callback_object, &mmu->callbacks, mali_kernel_memory_mmu_idle_callback, link) - { - if (callback_object->callback == callback) - { - found = 1; - break; - } - } - - if (found) - { - MALI_DEBUG_PRINT(5, ("Duplicate callback registration found, ignoring\n")); - /* callback already registered */ - err = _MALI_OSK_ERR_BUSY; - } - else - { - MALI_DEBUG_PRINT(5,("New callback, registering\n")); - /* register the new callback */ - callback_object = _mali_osk_malloc(sizeof(mali_kernel_memory_mmu_idle_callback)); - if (NULL != callback_object) - { - MALI_DEBUG_PRINT(7,("Callback struct setup\n")); - callback_object->callback = callback; - callback_object->callback_argument = callback_argument; - _mali_osk_list_addtail(&callback_object->link, &mmu->callbacks); - err = _MALI_OSK_ERR_BUSY; - } - } - } - - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - _mali_osk_lock_signal(requested_memory_session->lock, _MALI_OSK_LOCKMODE_RW); - - MALI_ERROR(err); -} - -void mali_memory_core_mmu_release_address_space_reference(void* mmu_ptr) -{ - mali_kernel_memory_mmu_idle_callback * callback_object, * temp; - mali_kernel_memory_mmu * mmu; - memory_session * session; - - _MALI_OSK_LIST_HEAD(callbacks); - - MALI_DEBUG_ASSERT_POINTER(mmu_ptr); - mmu = (mali_kernel_memory_mmu *)mmu_ptr; - - session = mmu->active_session; - - /* support that we handle spurious page faults */ - if (NULL != session) - { - _mali_osk_lock_wait(session->lock, _MALI_OSK_LOCKMODE_RW); - } - - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - MALI_DEBUG_PRINT(4, ("Deactivation of address space on MMU %s, %d references exists\n", mmu->description, mmu->usage_count)); - MALI_DEBUG_ASSERT(0 != mmu->usage_count); - mmu->usage_count--; - if (0 != mmu->usage_count) - { - MALI_DEBUG_PRINT(4, ("MMU still in use by this address space, %d references still exists\n", mmu->usage_count)); - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - /* support that we handle spurious page faults */ - if (NULL != session) - { - _mali_osk_lock_signal(session->lock, _MALI_OSK_LOCKMODE_RW); - } - return; - } - - MALI_DEBUG_PRINT(4, ("Activating the empty page directory on %s\n", mmu->description)); - - /* last reference gone, deactivate current address space */ - mali_mmu_activate_address_space(mmu, mali_empty_page_directory); - - /* unlink from session */ - _mali_osk_list_delinit(&mmu->session_link); - /* remove the active session pointer */ - mmu->active_session = NULL; - - /* Notify all registered callbacks. - * We have to be clever here: - * We must call the callbacks with the spinlock unlocked and - * the callback list emptied to allow them to re-register. - * So we make a copy of the list, clears the list and then later call the callbacks on the local copy - */ - /* copy list */ - _MALI_OSK_INIT_LIST_HEAD(&callbacks); - _mali_osk_list_splice(&mmu->callbacks, &callbacks); - /* clear the original, allowing new registrations during the callback */ - _MALI_OSK_INIT_LIST_HEAD(&mmu->callbacks); - - /* end of mmu manipulation, so safe to unlock */ - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - - /* then finally remove the (possible) session lock, supporting that no session was active (spurious page fault handling) */ - if (NULL != session) - { - _mali_osk_lock_signal(session->lock, _MALI_OSK_LOCKMODE_RW); - } - - _MALI_OSK_LIST_FOREACHENTRY(callback_object, temp, &callbacks, mali_kernel_memory_mmu_idle_callback, link) - { - MALI_DEBUG_ASSERT_POINTER(callback_object->callback); - (callback_object->callback)(callback_object->callback_argument); - _mali_osk_list_del(&callback_object->link); - _mali_osk_free(callback_object); - } -} - -void mali_memory_core_mmu_unregister_callback(void* mmu_ptr, void(*callback)(void*)) -{ - mali_kernel_memory_mmu_idle_callback * callback_object, * temp_callback_object; - mali_kernel_memory_mmu * mmu; - MALI_DEBUG_ASSERT_POINTER(mmu_ptr); - - MALI_DEBUG_ASSERT_POINTER(callback); - MALI_DEBUG_ASSERT_POINTER(mmu_ptr); - - mmu = (mali_kernel_memory_mmu *)mmu_ptr; - - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - _MALI_OSK_LIST_FOREACHENTRY(callback_object, temp_callback_object, &mmu->callbacks, mali_kernel_memory_mmu_idle_callback, link) - { - MALI_DEBUG_ASSERT_POINTER(callback_object->callback); - if (callback_object->callback == callback) - { - _mali_osk_list_del(&callback_object->link); - _mali_osk_free(callback_object); - break; - } - } - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); -} - -static _mali_osk_errcode_t mali_address_manager_allocate(mali_memory_allocation * descriptor) -{ - /* allocate page tables, if needed */ - int i; - const int first_pde_idx = MALI_MMU_PDE_ENTRY(descriptor->mali_address); - int last_pde_idx; - memory_session * session_data; -#if defined USING_MALI400_L2_CACHE - int has_active_mmus = 0; - int page_dir_updated = 0; -#endif - - - if (descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE) - { - last_pde_idx = MALI_MMU_PDE_ENTRY(descriptor->mali_address + _MALI_OSK_MALI_PAGE_SIZE + descriptor->size - 1); - } - else - { - last_pde_idx = MALI_MMU_PDE_ENTRY(descriptor->mali_address + descriptor->size - 1); - } - - session_data = (memory_session*)descriptor->mali_addr_mapping_info; - MALI_DEBUG_ASSERT_POINTER(session_data); - - MALI_DEBUG_PRINT(4, ("allocating page tables for Mali virtual address space 0x%08X to 0x%08X\n", descriptor->mali_address, descriptor->mali_address + descriptor->size - 1)); - -#if defined USING_MALI400_L2_CACHE - if (0 == _mali_osk_list_empty(&session_data->active_mmus)) - { - /* - * We have active MMUs, so we are probably in the process of alocating more memory for a suspended GP job (PLBU heap) - * From Mali-400 MP r1p0, MMU page directory/tables are also cached by the Mali L2 cache, thus we need to invalidate the page directory - * from the L2 cache if we add new page directory entries (PDEs) to the page directory. - * We only need to do this when we have an active MMU, because we otherwise invalidate the entire Mali L2 cache before at job start - */ - has_active_mmus = 1; - } -#endif - - for (i = first_pde_idx; i <= last_pde_idx; i++) - { - if ( 0 == (_mali_osk_mem_ioread32(session_data->page_directory_mapped, i * sizeof(u32)) & MALI_MMU_FLAGS_PRESENT) ) - { - u32 pte_phys; - mali_io_address pte_mapped; - _mali_osk_errcode_t err; - - /* allocate a new page table */ - MALI_DEBUG_ASSERT(0 == session_data->page_entries_usage_count[i]); - MALI_DEBUG_ASSERT(NULL == session_data->page_entries_mapped[i]); - - err = mali_mmu_get_table_page(&pte_phys, &pte_mapped); - if (_MALI_OSK_ERR_OK == err) - { - session_data->page_entries_mapped[i] = pte_mapped; - MALI_DEBUG_ASSERT_POINTER( session_data->page_entries_mapped[i] ); - - _mali_osk_mem_iowrite32(session_data->page_directory_mapped, i * sizeof(u32), pte_phys | MALI_MMU_FLAGS_PRESENT); /* mark page table as present */ - - /* update usage count */ - session_data->page_entries_usage_count[i]++; -#if defined USING_MALI400_L2_CACHE - page_dir_updated = 1; -#endif - continue; /* continue loop */ - } - - MALI_DEBUG_PRINT(1, ("Page table alloc failed\n")); - break; /* abort loop, failed to allocate one or more page tables */ - } - else - { - session_data->page_entries_usage_count[i]++; - } - } - - if (i <= last_pde_idx) - { - /* one or more pages could not be allocated, release reference count for the ones we added one for */ - /* adjust for the one which caused the for loop to be aborted */ - i--; - - while (i >= first_pde_idx) - { - MALI_DEBUG_ASSERT(0 != session_data->page_entries_usage_count[i]); - session_data->page_entries_usage_count[i]--; - if (0 == session_data->page_entries_usage_count[i]) - { - /* last reference removed */ - mali_mmu_release_table_page(MALI_MMU_ENTRY_ADDRESS(_mali_osk_mem_ioread32(session_data->page_directory_mapped, i * sizeof(u32)))); - session_data->page_entries_mapped[i] = NULL; - _mali_osk_mem_iowrite32(session_data->page_directory_mapped, i * sizeof(u32), 0); /* mark as not present in the page directory */ - } - i--; - } - - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - -#if defined USING_MALI400_L2_CACHE - if (1 == has_active_mmus && 1 == page_dir_updated) - { - /* - * We have updated the page directory and have an active MMU using it, so invalidate it in the Mali L2 cache. - */ - mali_kernel_l2_cache_invalidate_page(session_data->page_directory); - } -#endif - - /* all OK */ - MALI_SUCCESS; -} - -static void mali_address_manager_release(mali_memory_allocation * descriptor) -{ - int first_pde_idx; - int last_pde_idx; - memory_session * session_data; - u32 mali_address; - u32 mali_address_end; - u32 left; - int i; -#if defined USING_MALI400_L2_CACHE - int has_active_mmus = 0; - int page_dir_updated = 0; -#endif - - MALI_DEBUG_ASSERT_POINTER(descriptor); - session_data = (memory_session*)descriptor->mali_addr_mapping_info; - MALI_DEBUG_ASSERT_POINTER(session_data); - MALI_DEBUG_ASSERT_POINTER(session_data->page_directory_mapped); - - mali_address = descriptor->mali_address; - mali_address_end = descriptor->mali_address + descriptor->size; - left = descriptor->size; - - first_pde_idx = MALI_MMU_PDE_ENTRY(mali_address); - last_pde_idx = MALI_MMU_PDE_ENTRY(mali_address_end - 1); - - MALI_DEBUG_PRINT(3, ("Zapping Mali MMU table for address 0x%08X size 0x%08X\n", mali_address, left)); - MALI_DEBUG_PRINT(4, ("Zapping PDE %d through %d\n", first_pde_idx, last_pde_idx)); - -#if defined USING_MALI400_L2_CACHE - if (0 == _mali_osk_list_empty(&session_data->active_mmus)) - { - /* - * From Mali-400 MP r1p0, MMU page directory/tables are also cached by the Mali L2 cache, thus we need to invalidate the page tables - * from the L2 cache to ensure that the memory is unmapped. - * We only need to do this when we have an active MMU, because we otherwise invalidate the entire Mali L2 cache before at job start - */ - has_active_mmus = 1; - } -#endif - - - for (i = first_pde_idx; i <= last_pde_idx; i++) - { - int size_inside_pte = left < 0x400000 ? left : 0x400000; - const int first_pte_idx = MALI_MMU_PTE_ENTRY(mali_address); - int last_pte_idx = MALI_MMU_PTE_ENTRY(mali_address + size_inside_pte - 1); - - if (last_pte_idx < first_pte_idx) - { - /* The last_pte_idx is into the next PTE, crop it to fit into this */ - last_pte_idx = 1023; /* 1024 PTE entries, so 1023 is the last one */ - size_inside_pte = MALI_MMU_ADDRESS(i + 1, 0) - mali_address; - } - - MALI_DEBUG_ASSERT_POINTER(session_data->page_entries_mapped[i]); - MALI_DEBUG_ASSERT(0 != session_data->page_entries_usage_count[i]); - MALI_DEBUG_PRINT(4, ("PDE %d: zapping entries %d through %d, address 0x%08X, size 0x%08X, left 0x%08X (page table at 0x%08X)\n", - i, first_pte_idx, last_pte_idx, mali_address, size_inside_pte, left, - MALI_MMU_ENTRY_ADDRESS(_mali_osk_mem_ioread32(session_data->page_directory_mapped, i * sizeof(u32))))); - - session_data->page_entries_usage_count[i]--; - - if (0 == session_data->page_entries_usage_count[i]) - { - MALI_DEBUG_PRINT(4, ("Releasing page table as this is the last reference\n")); - /* last reference removed, no need to zero out each PTE */ - mali_mmu_release_table_page(MALI_MMU_ENTRY_ADDRESS(_mali_osk_mem_ioread32(session_data->page_directory_mapped, i * sizeof(u32)))); - session_data->page_entries_mapped[i] = NULL; - _mali_osk_mem_iowrite32(session_data->page_directory_mapped, i * sizeof(u32), 0); /* mark as not present in the page directory */ -#if defined USING_MALI400_L2_CACHE - page_dir_updated = 1; -#endif - } - else - { - int j; - - for (j = first_pte_idx; j <= last_pte_idx; j++) - { - _mali_osk_mem_iowrite32(session_data->page_entries_mapped[i], j * sizeof(u32), 0); - } - -#if defined USING_MALI400_L2_CACHE - if (1 == has_active_mmus) - { - /* Invalidate the page we've just modified */ - mali_kernel_l2_cache_invalidate_page( _mali_osk_mem_ioread32(session_data->page_directory_mapped, i*sizeof(u32)) & ~MALI_MMU_FLAGS_MASK); - } -#endif - } - left -= size_inside_pte; - mali_address += size_inside_pte; - } - -#if defined USING_MALI400_L2_CACHE - if ((1 == page_dir_updated) && (1== has_active_mmus)) - { - /* The page directory was also updated */ - mali_kernel_l2_cache_invalidate_page(session_data->page_directory); - } -#endif -} - -static _mali_osk_errcode_t mali_address_manager_map(mali_memory_allocation * descriptor, u32 offset, u32 *phys_addr, u32 size) -{ - memory_session * session_data; - u32 mali_address; - u32 mali_address_end; - u32 current_phys_addr; -#if defined USING_MALI400_L2_CACHE - int has_active_mmus = 0; -#endif - - MALI_DEBUG_ASSERT_POINTER(descriptor); - - MALI_DEBUG_ASSERT_POINTER( phys_addr ); - - current_phys_addr = *phys_addr; - - session_data = (memory_session*)descriptor->mali_addr_mapping_info; - MALI_DEBUG_ASSERT_POINTER(session_data); - - mali_address = descriptor->mali_address + offset; - mali_address_end = descriptor->mali_address + offset + size; - -#if defined USING_MALI400_L2_CACHE - if (0 == _mali_osk_list_empty(&session_data->active_mmus)) - { - /* - * We have active MMUs, so we are probably in the process of alocating more memory for a suspended GP job (PLBU heap) - * From Mali-400 MP r1p0, MMU page directory/tables are also cached by the Mali L2 cache, thus we need to invalidate the page tables - * from the L2 cache when we have allocated more heap memory. - * We only need to do this when we have an active MMU, because we otherwise invalidate the entire Mali L2 cache before at job start - */ - has_active_mmus = 1; - } -#endif - - MALI_DEBUG_PRINT(6, ("Mali map: mapping 0x%08X to Mali address 0x%08X length 0x%08X\n", current_phys_addr, mali_address, size)); - - MALI_DEBUG_ASSERT_POINTER(session_data->page_entries_mapped); - - for ( ; mali_address < mali_address_end; mali_address += MALI_MMU_PAGE_SIZE, current_phys_addr += MALI_MMU_PAGE_SIZE) - { - MALI_DEBUG_ASSERT_POINTER(session_data->page_entries_mapped[MALI_MMU_PDE_ENTRY(mali_address)]); - _mali_osk_mem_iowrite32_relaxed(session_data->page_entries_mapped[MALI_MMU_PDE_ENTRY(mali_address)], MALI_MMU_PTE_ENTRY(mali_address) * sizeof(u32), current_phys_addr | MALI_MMU_FLAGS_WRITE_PERMISSION | MALI_MMU_FLAGS_READ_PERMISSION | MALI_MMU_FLAGS_PRESENT); - } - _mali_osk_write_mem_barrier(); - -#if defined USING_MALI400_L2_CACHE - if (1 == has_active_mmus) - { - int i; - const int first_pde_idx = MALI_MMU_PDE_ENTRY(mali_address); - const int last_pde_idx = MALI_MMU_PDE_ENTRY(mali_address_end - 1); - - /* - * Invalidate the updated page table(s), incase they have been used for something - * else since last job start (invalidation of entire Mali L2 cache) - */ - for (i = first_pde_idx; i <= last_pde_idx; i++) - { - mali_kernel_l2_cache_invalidate_page( _mali_osk_mem_ioread32(session_data->page_directory_mapped, i*sizeof(u32)) & ~MALI_MMU_FLAGS_MASK); - } - } -#endif - - MALI_SUCCESS; -} - -/* This handler registered to mali_mmap for MMU builds */ -_mali_osk_errcode_t _mali_ukk_mem_mmap( _mali_uk_mem_mmap_s *args ) -{ - struct mali_session_data * mali_session_data; - mali_memory_allocation * descriptor; - memory_session * session_data; - - /* validate input */ - if (NULL == args) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: args was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); } - - /* Unpack arguments */ - mali_session_data = (struct mali_session_data *)args->ctx; - - if (NULL == mali_session_data) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: mali_session data was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); } - - MALI_DEBUG_ASSERT( mali_subsystem_memory_id >= 0 ); - - session_data = mali_kernel_session_manager_slot_get(mali_session_data, mali_subsystem_memory_id); - /* validate input */ - if (NULL == session_data) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: session data was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_FAULT); } - - descriptor = (mali_memory_allocation*) _mali_osk_calloc( 1, sizeof(mali_memory_allocation) ); - if (NULL == descriptor) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: descriptor was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_NOMEM); } - - descriptor->size = args->size; - descriptor->mali_address = args->phys_addr; - descriptor->mali_addr_mapping_info = (void*)session_data; - - descriptor->process_addr_mapping_info = args->ukk_private; /* save to be used during physical manager callback */ - descriptor->flags = MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE; - descriptor->lock = session_data->lock; - _mali_osk_list_init( &descriptor->list ); - - _mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - if (0 == mali_allocation_engine_allocate_memory(memory_engine, descriptor, physical_memory_allocators, &session_data->memory_head)) - { - mali_kernel_memory_mmu * mmu, * temp_mmu; - - _MALI_OSK_LIST_FOREACHENTRY(mmu, temp_mmu, &session_data->active_mmus, mali_kernel_memory_mmu, session_link) - { - /* no need to lock the MMU as we own it already */ - MALI_DEBUG_PRINT(5, ("Zapping the cache of mmu %s as it's using the page table we have updated\n", mmu->description)); - - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - - mali_mmu_enable_stall(mmu); /* this might fail, but ZAP should work anyway... */ - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE); - mali_mmu_disable_stall(mmu); - - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - } - - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - - /* All ok, write out any information generated from this call */ - args->mapping = descriptor->mapping; - args->cookie = (u32)descriptor; - - MALI_DEBUG_PRINT(7, ("MMAP OK\n")); - /* All done */ - MALI_SUCCESS; - } - else - { - _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - /* OOM, but not a fatal error */ - MALI_DEBUG_PRINT(4, ("Memory allocation failure, OOM\n")); - _mali_osk_free(descriptor); - /* Linux will free the CPU address allocation, userspace client the Mali address allocation */ - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } -} - -static _mali_osk_errcode_t _mali_ukk_mem_munmap_internal( _mali_uk_mem_munmap_s *args ) -{ - memory_session * session_data; - mali_kernel_memory_mmu * mmu, * temp_mmu; - mali_memory_allocation * descriptor; - - descriptor = (mali_memory_allocation *)args->cookie; - MALI_DEBUG_ASSERT_POINTER(descriptor); - - /** @note args->context unused; we use the memory_session from the cookie */ - /* args->mapping and args->size are also discarded. They are only necessary - for certain do_munmap implementations. However, they could be used to check the - descriptor at this point. */ - - session_data = (memory_session*)descriptor->mali_addr_mapping_info; - MALI_DEBUG_ASSERT_POINTER(session_data); - - /* Stall the MMU(s) which is using the address space we're operating on. - * Note that active_mmus must be sorted in order of ID to avoid a mutex - * ordering violation. - */ - _MALI_OSK_LIST_FOREACHENTRY(mmu, temp_mmu, &session_data->active_mmus, mali_kernel_memory_mmu, session_link) - { - u32 status; - status = mali_mmu_register_read(mmu, MALI_MMU_REGISTER_STATUS); - if ( MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE == (status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE) ) { - MALI_DEBUG_PRINT(2, ("Stopped stall attempt for mmu with id %d since it is in page fault mode.\n", mmu->id)); - continue; - } - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - - /* - * If we're unable to stall, then make sure we tell our caller that, - * the caller should then release the session lock for a while, - * then this function again. - * This function will fail if we're in page fault mode, and to get - * out of page fault mode, the page fault handler must be able to - * take the session lock. - */ - if (!mali_mmu_enable_stall(mmu)) - { - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - return _MALI_OSK_ERR_BUSY; - } - - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - } - - _MALI_OSK_LIST_FOREACHENTRY(mmu, temp_mmu, &session_data->active_mmus, mali_kernel_memory_mmu, session_link) - { - _mali_osk_lock_wait(mmu->lock, _MALI_OSK_LOCKMODE_RW); - } - - /* This function also removes the memory from the session's memory list */ - mali_allocation_engine_release_memory(memory_engine, descriptor); - _mali_osk_free(descriptor); - - /* any L2 maintenance was done during mali_allocation_engine_release_memory */ - /* the session is locked, so the active mmu list should be the same */ - /* zap the TLB and resume operation */ - _MALI_OSK_LIST_FOREACHENTRY(mmu, temp_mmu, &session_data->active_mmus, mali_kernel_memory_mmu, session_link) - { - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE); - mali_mmu_disable_stall(mmu); - - _mali_osk_lock_signal(mmu->lock, _MALI_OSK_LOCKMODE_RW); - } - - return _MALI_OSK_ERR_OK; -} - -/* Handler for unmapping memory for MMU builds */ -_mali_osk_errcode_t _mali_ukk_mem_munmap( _mali_uk_mem_munmap_s *args ) -{ - mali_memory_allocation * descriptor; - _mali_osk_lock_t *descriptor_lock; - _mali_osk_errcode_t err; - - descriptor = (mali_memory_allocation *)args->cookie; - MALI_DEBUG_ASSERT_POINTER(descriptor); - - /** @note args->context unused; we use the memory_session from the cookie */ - /* args->mapping and args->size are also discarded. They are only necessary - for certain do_munmap implementations. However, they could be used to check the - descriptor at this point. */ - - MALI_DEBUG_ASSERT_POINTER((memory_session*)descriptor->mali_addr_mapping_info); - - descriptor_lock = descriptor->lock; /* should point to the session data lock... */ - - err = _MALI_OSK_ERR_BUSY; - while (err == _MALI_OSK_ERR_BUSY) - { - if (descriptor_lock) - { - _mali_osk_lock_wait( descriptor_lock, _MALI_OSK_LOCKMODE_RW ); - } - - err = _mali_ukk_mem_munmap_internal( args ); - - if (descriptor_lock) - { - _mali_osk_lock_signal( descriptor_lock, _MALI_OSK_LOCKMODE_RW ); - } - - if (err == _MALI_OSK_ERR_BUSY) - { - /* - * Reason for this; - * We where unable to stall the MMU, probably because we are in page fault handling. - * Sleep for a while with the session lock released, then try again. - * Abnormal termination of programs with running Mali jobs is a normal reason for this. - */ - _mali_osk_time_ubusydelay(10); - } - } - - return err; -} - -/* Is called when the rendercore wants the mmu to give an interrupt */ -static void mali_mmu_probe_irq_trigger(mali_kernel_memory_mmu * mmu) -{ - MALI_DEBUG_PRINT(2, ("mali_mmu_probe_irq_trigger\n")); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_RAWSTAT, MALI_MMU_INTERRUPT_PAGE_FAULT|MALI_MMU_INTERRUPT_READ_BUS_ERROR); -} - -/* Is called when the irq probe wants the mmu to acknowledge an interrupt from the hw */ -static _mali_osk_errcode_t mali_mmu_probe_irq_acknowledge(mali_kernel_memory_mmu * mmu) -{ - u32 int_stat; - - int_stat = mali_mmu_register_read(mmu, MALI_MMU_REGISTER_INT_STATUS); - - MALI_DEBUG_PRINT(2, ("mali_mmu_probe_irq_acknowledge: intstat 0x%x\n", int_stat)); - if (int_stat & MALI_MMU_INTERRUPT_PAGE_FAULT) - { - MALI_DEBUG_PRINT(2, ("Probe: Page fault detect: PASSED\n")); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_CLEAR, MALI_MMU_INTERRUPT_PAGE_FAULT); - } - else MALI_DEBUG_PRINT(1, ("Probe: Page fault detect: FAILED\n")); - - if (int_stat & MALI_MMU_INTERRUPT_READ_BUS_ERROR) - { - MALI_DEBUG_PRINT(2, ("Probe: Bus read error detect: PASSED\n")); - mali_mmu_register_write(mmu, MALI_MMU_REGISTER_INT_CLEAR, MALI_MMU_INTERRUPT_READ_BUS_ERROR); - } - else MALI_DEBUG_PRINT(1, ("Probe: Bus read error detect: FAILED\n")); - - if ( (int_stat & (MALI_MMU_INTERRUPT_PAGE_FAULT|MALI_MMU_INTERRUPT_READ_BUS_ERROR)) == - (MALI_MMU_INTERRUPT_PAGE_FAULT|MALI_MMU_INTERRUPT_READ_BUS_ERROR)) - { - MALI_SUCCESS; - } - - MALI_ERROR(_MALI_OSK_ERR_FAULT); -} - -struct dump_info -{ - u32 buffer_left; - u32 register_writes_size; - u32 page_table_dump_size; - u32 *buffer; -}; - -static _mali_osk_errcode_t writereg(u32 where, u32 what, const char * comment, struct dump_info * info, int dump_to_serial) -{ - if (dump_to_serial) MALI_DEBUG_PRINT(1, ("writereg %08X %08X # %s\n", where, what, comment)); - - if (NULL != info) - { - info->register_writes_size += sizeof(u32)*2; /* two 32-bit words */ - - if (NULL != info->buffer) - { - /* check that we have enough space */ - if (info->buffer_left < sizeof(u32)*2) MALI_ERROR(_MALI_OSK_ERR_NOMEM); - - *info->buffer = where; - info->buffer++; - - *info->buffer = what; - info->buffer++; - - info->buffer_left -= sizeof(u32)*2; - } - } - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t dump_page(mali_io_address page, u32 phys_addr, struct dump_info * info, int dump_to_serial) -{ - if (dump_to_serial) - { - int i; - for (i = 0; i < 256; i++) - { - MALI_DEBUG_PRINT(1, ("%08X: %08X %08X %08X %08X\n", phys_addr + 16*i, _mali_osk_mem_ioread32(page, (i*4 + 0) * sizeof(u32)), - _mali_osk_mem_ioread32(page, (i*4 + 1) * sizeof(u32)), - _mali_osk_mem_ioread32(page, (i*4 + 2) * sizeof(u32)), - _mali_osk_mem_ioread32(page, (i*4 + 3) * sizeof(u32)))); - - } - } - - if (NULL != info) - { - /* 4096 for the page and 4 bytes for the address */ - const u32 page_size_in_elements = MALI_MMU_PAGE_SIZE / 4; - const u32 page_size_in_bytes = MALI_MMU_PAGE_SIZE; - const u32 dump_size_in_bytes = MALI_MMU_PAGE_SIZE + 4; - - info->page_table_dump_size += dump_size_in_bytes; - - if (NULL != info->buffer) - { - if (info->buffer_left < dump_size_in_bytes) MALI_ERROR(_MALI_OSK_ERR_NOMEM); - - *info->buffer = phys_addr; - info->buffer++; - - _mali_osk_memcpy(info->buffer, page, page_size_in_bytes); - info->buffer += page_size_in_elements; - - info->buffer_left -= dump_size_in_bytes; - } - } - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t dump_mmu_page_table(memory_session * session_data, struct dump_info * info) -{ - MALI_DEBUG_ASSERT_POINTER(session_data); - MALI_DEBUG_ASSERT_POINTER(info); - - if (NULL != session_data->page_directory_mapped) - { - int i; - - MALI_CHECK_NO_ERROR( - dump_page(session_data->page_directory_mapped, session_data->page_directory, info, 0) - ); - - for (i = 0; i < 1024; i++) - { - if (NULL != session_data->page_entries_mapped[i]) - { - MALI_CHECK_NO_ERROR( - dump_page(session_data->page_entries_mapped[i], _mali_osk_mem_ioread32(session_data->page_directory_mapped, i * sizeof(u32)) & ~MALI_MMU_FLAGS_MASK, info, 0) - ); - } - } - } - - MALI_SUCCESS; -} - -static _mali_osk_errcode_t dump_mmu_registers(memory_session * session_data, struct dump_info * info) -{ - MALI_CHECK_NO_ERROR(writereg(0x00000000, session_data->page_directory, "set the page directory address", info, 0)); - MALI_CHECK_NO_ERROR(writereg(0x00000008, 4, "zap???", info, 0)); - MALI_CHECK_NO_ERROR(writereg(0x00000008, 0, "enable paging", info, 0)); - MALI_SUCCESS; -} - -_mali_osk_errcode_t _mali_ukk_query_mmu_page_table_dump_size( _mali_uk_query_mmu_page_table_dump_size_s *args ) -{ - struct dump_info info = { 0, 0, 0, NULL }; - memory_session * session_data; - - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - - session_data = (memory_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_memory_id); - - MALI_CHECK_NO_ERROR(dump_mmu_registers(session_data, &info)); - MALI_CHECK_NO_ERROR(dump_mmu_page_table(session_data, &info)); - args->size = info.register_writes_size + info.page_table_dump_size; - MALI_SUCCESS; -} - -_mali_osk_errcode_t _mali_ukk_dump_mmu_page_table( _mali_uk_dump_mmu_page_table_s * args ) -{ - struct dump_info info = { 0, 0, 0, NULL }; - memory_session * session_data; - - MALI_DEBUG_ASSERT_POINTER(args); - MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); - MALI_CHECK_NON_NULL(args->buffer, _MALI_OSK_ERR_INVALID_ARGS); - - session_data = (memory_session *)mali_kernel_session_manager_slot_get(args->ctx, mali_subsystem_memory_id); - - info.buffer_left = args->size; - info.buffer = args->buffer; - - args->register_writes = info.buffer; - MALI_CHECK_NO_ERROR(dump_mmu_registers(session_data, &info)); - - args->page_table_dump = info.buffer; - MALI_CHECK_NO_ERROR(dump_mmu_page_table(session_data, &info)); - - args->register_writes_size = info.register_writes_size; - args->page_table_dump_size = info.page_table_dump_size; - - MALI_SUCCESS; -} - -/** - * Stub function to satisfy UDD interface exclusion requirement. - * This is because the Base code compiles in \b both MMU and non-MMU calls, - * so both sets must be declared (but the 'unused' set may be stub) - */ -_mali_osk_errcode_t _mali_ukk_get_big_block( _mali_uk_get_big_block_s *args ) -{ - MALI_IGNORE( args ); - return _MALI_OSK_ERR_FAULT; -} - -/** - * Stub function to satisfy UDD interface exclusion requirement. - * This is because the Base code compiles in \b both MMU and non-MMU calls, - * so both sets must be declared (but the 'unused' set may be stub) - */ -_mali_osk_errcode_t _mali_ukk_free_big_block( _mali_uk_free_big_block_s *args ) -{ - MALI_IGNORE( args ); - return _MALI_OSK_ERR_FAULT; -} - -u32 _mali_ukk_report_memory_usage(void) -{ - return mali_allocation_engine_memory_usage(physical_memory_allocators); -} diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_mem_mmu.h b/drivers/media/video/samsung/mali/common/mali_kernel_mem_mmu.h deleted file mode 100644 index 6a110d0..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_mem_mmu.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __MALI_KERNEL_MEM_MMU_H__ -#define __MALI_KERNEL_MEM_MMU_H__ - -#include "mali_kernel_session_manager.h" - -/** - * Lookup a MMU core by ID. - * @param id ID of the MMU to find - * @return NULL if ID not found or valid, non-NULL if a core was found. - */ -void* mali_memory_core_mmu_lookup(u32 id); - -/** - * Set the core pointer of MMU to core owner of MMU - * - * @param core Core holding this MMU - * @param mmu_ptr The MMU whose core pointer needs set to core holding the MMU - * - */ -void mali_memory_core_mmu_owner(void *core, void *mmu_ptr); - -/** - * Activate a user session with its address space on the given MMU. - * If the session can't be activated due to that the MMU is busy and - * a callback pointer is given, the callback will be called once the MMU becomes idle. - * If the same callback pointer is registered multiple time it will only be called once. - * Nested activations are supported. - * Each call must be matched by a call to @see mali_memory_core_mmu_release_address_space_reference - * - * @param mmu The MMU to activate the address space on - * @param mali_session_data The user session object which address space to activate - * @param callback Pointer to the function to call when the MMU becomes idle - * @param callback_arg Argument given to the callback - * @return 0 if the address space was activated, -EBUSY if the MMU was busy, -EFAULT in all other cases. - */ -int mali_memory_core_mmu_activate_page_table(void* mmu_ptr, struct mali_session_data * mali_session_data, void(*callback)(void*), void * callback_argument); - -/** - * Release a reference to the current active address space. - * Once the last reference is released any callback(s) registered will be called before the function returns - * - * @note Caution must be shown calling this function with locks held due to that callback can be called - * @param mmu The mmu to release a reference to the active address space of - */ -void mali_memory_core_mmu_release_address_space_reference(void* mmu); - -/** - * Soft reset of MMU - needed after power up - * - * @param mmu_ptr The MMU pointer registered with the relevant core - */ -void mali_kernel_mmu_reset(void * mmu_ptr); - -void mali_kernel_mmu_force_bus_reset(void * mmu_ptr); - -/** - * Unregister a previously registered callback. - * @param mmu The MMU to unregister the callback on - * @param callback The function to unregister - */ -void mali_memory_core_mmu_unregister_callback(void* mmu, void(*callback)(void*)); - - - -#endif /* __MALI_KERNEL_MEM_MMU_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_mem_os.c b/drivers/media/video/samsung/mali/common/mali_kernel_mem_os.c index 324fcab..7462a6d 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_mem_os.c +++ b/drivers/media/video/samsung/mali/common/mali_kernel_mem_os.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -65,19 +65,19 @@ mali_physical_memory_allocator * mali_os_allocator_create(u32 max_allocation, u3 info->num_pages_allocated = 0; info->cpu_usage_adjust = cpu_usage_adjust; - info->mutex = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE | _MALI_OSK_LOCKFLAG_ORDERED, 0, 106); - if (NULL != info->mutex) - { - allocator->allocate = os_allocator_allocate; - allocator->allocate_page_table_block = os_allocator_allocate_page_table_block; - allocator->destroy = os_allocator_destroy; + info->mutex = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE | _MALI_OSK_LOCKFLAG_ORDERED, 0, _MALI_OSK_LOCK_ORDER_MEM_INFO); + if (NULL != info->mutex) + { + allocator->allocate = os_allocator_allocate; + allocator->allocate_page_table_block = os_allocator_allocate_page_table_block; + allocator->destroy = os_allocator_destroy; allocator->stat = os_allocator_stat; - allocator->ctx = info; + allocator->ctx = info; allocator->name = name; - return allocator; - } - _mali_osk_free(info); + return allocator; + } + _mali_osk_free(info); } _mali_osk_free(allocator); } @@ -132,7 +132,7 @@ static mali_physical_memory_allocation_result os_allocator_allocate(void* ctx, m allocation->num_pages = ((left + _MALI_OSK_CPU_PAGE_SIZE - 1) & ~(_MALI_OSK_CPU_PAGE_SIZE - 1)) >> _MALI_OSK_CPU_PAGE_ORDER; MALI_DEBUG_PRINT(6, ("Allocating page array of size %d bytes\n", allocation->num_pages * sizeof(struct page*))); - while (left > 0 && ((info->num_pages_allocated + pages_allocated) < info->num_pages_max) && _mali_osk_mem_check_allocated(os_mem_max_usage)) + while (left > 0) { err = mali_allocation_engine_map_physical(engine, descriptor, *offset, MALI_MEMORY_ALLOCATION_OS_ALLOCATED_PHYSADDR_MAGIC, info->cpu_usage_adjust, _MALI_OSK_CPU_PAGE_SIZE); if ( _MALI_OSK_ERR_OK != err) @@ -243,7 +243,7 @@ static void os_allocator_release(void * ctx, void * handle) static mali_physical_memory_allocation_result os_allocator_allocate_page_table_block(void * ctx, mali_page_table_block * block) { - int allocation_order = 11; /* _MALI_OSK_CPU_PAGE_SIZE << 6 */ + int allocation_order = 11; /* _MALI_OSK_CPU_PAGE_SIZE << 11 */ void *virt = NULL; u32 size = _MALI_OSK_CPU_PAGE_SIZE << allocation_order; os_allocator * info; diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_memory_engine.c b/drivers/media/video/samsung/mali/common/mali_kernel_memory_engine.c index ff105a4..1377560 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_memory_engine.c +++ b/drivers/media/video/samsung/mali/common/mali_kernel_memory_engine.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -161,13 +161,28 @@ _mali_osk_errcode_t mali_allocation_engine_allocate_memory(mali_allocation_engin void mali_allocation_engine_release_memory(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor) { + mali_allocation_engine_release_pt1_mali_pagetables_unmap(mem_engine, descriptor); + mali_allocation_engine_release_pt2_physical_memory_free(mem_engine, descriptor); +} + +void mali_allocation_engine_release_pt1_mali_pagetables_unmap(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor) +{ memory_engine * engine = (memory_engine*)mem_engine; - mali_physical_memory_allocation * active_allocation_tracker; MALI_DEBUG_ASSERT_POINTER(engine); MALI_DEBUG_ASSERT_POINTER(descriptor); - /* Determine whether we need to remove this from a tracking list */ + /* Calling: mali_address_manager_release() */ + /* This function is allowed to be called several times, and it only does the release on the first call. */ + engine->mali_address->release(descriptor); +} + +void mali_allocation_engine_release_pt2_physical_memory_free(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor) +{ + memory_engine * engine = (memory_engine*)mem_engine; + mali_physical_memory_allocation * active_allocation_tracker; + + /* Remove this from a tracking list in session_data->memory_head */ if ( ! _mali_osk_list_empty( &descriptor->list ) ) { _mali_osk_list_del( &descriptor->list ); @@ -175,8 +190,6 @@ void mali_allocation_engine_release_memory(mali_allocation_engine mem_engine, ma MALI_DEBUG_CODE( descriptor->list.next = descriptor->list.prev = NULL; ) } - engine->mali_address->release(descriptor); - active_allocation_tracker = &descriptor->physical_allocation; while (NULL != active_allocation_tracker) { @@ -199,7 +212,6 @@ void mali_allocation_engine_release_memory(mali_allocation_engine mem_engine, ma } } - _mali_osk_errcode_t mali_allocation_engine_map_physical(mali_allocation_engine mem_engine, mali_memory_allocation * descriptor, u32 offset, u32 phys, u32 cpu_usage_adjust, u32 size) { _mali_osk_errcode_t err; @@ -244,7 +256,7 @@ _mali_osk_errcode_t mali_allocation_engine_map_physical(mali_allocation_engine m } } - MALI_DEBUG_PRINT(4, ("Mapping phys 0x%08X length 0x%08X at offset 0x%08X to CPUVA 0x%08X\n", phys, size, offset, (u32)(descriptor->mapping) + offset)); + MALI_DEBUG_PRINT(7, ("Mapping phys 0x%08X length 0x%08X at offset 0x%08X to CPUVA 0x%08X\n", phys, size, offset, (u32)(descriptor->mapping) + offset)); /* Mali address manager must use the physical address - no point in asking * it to allocate another one for us */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_memory_engine.h b/drivers/media/video/samsung/mali/common/mali_kernel_memory_engine.h index 0173c78..cda74c3 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_memory_engine.h +++ b/drivers/media/video/samsung/mali/common/mali_kernel_memory_engine.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -136,6 +136,9 @@ void mali_allocation_engine_destroy(mali_allocation_engine engine); int mali_allocation_engine_allocate_memory(mali_allocation_engine engine, mali_memory_allocation * descriptor, mali_physical_memory_allocator * physical_provider, _mali_osk_list_t *tracking_list ); void mali_allocation_engine_release_memory(mali_allocation_engine engine, mali_memory_allocation * descriptor); +void mali_allocation_engine_release_pt1_mali_pagetables_unmap(mali_allocation_engine engine, mali_memory_allocation * descriptor); +void mali_allocation_engine_release_pt2_physical_memory_free(mali_allocation_engine engine, mali_memory_allocation * descriptor); + int mali_allocation_engine_map_physical(mali_allocation_engine engine, mali_memory_allocation * descriptor, u32 offset, u32 phys, u32 cpu_usage_adjust, u32 size); void mali_allocation_engine_unmap_physical(mali_allocation_engine engine, mali_memory_allocation * descriptor, u32 offset, u32 size, _mali_osk_mem_mapregion_flags_t unmap_flags); diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_rendercore.c b/drivers/media/video/samsung/mali/common/mali_kernel_rendercore.c deleted file mode 100644 index cfc5ec1..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_rendercore.c +++ /dev/null @@ -1,2031 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "mali_kernel_common.h" -#include "mali_kernel_core.h" -#include "mali_osk.h" -#include "mali_kernel_subsystem.h" -#include "mali_kernel_rendercore.h" -#include "mali_osk_list.h" -#if MALI_GPU_UTILIZATION -#include "mali_kernel_utilization.h" -#endif -#if MALI_TIMELINE_PROFILING_ENABLED -#include "mali_kernel_profiling.h" -#endif -#if USING_MMU -#include "mali_kernel_mem_mmu.h" -#endif /* USING_MMU */ -#if defined USING_MALI400_L2_CACHE -#include "mali_kernel_l2_cache.h" -#endif /* USING_MALI400_L2_CACHE */ - -#define HANG_CHECK_MSECS_MIN 100 -#define HANG_CHECK_MSECS_MAX 2000 /* 2 secs */ -#define HANG_CHECK_MSECS_DEFAULT 500 /* 500 ms */ - -#define WATCHDOG_MSECS_MIN (10*HANG_CHECK_MSECS_MIN) -#define WATCHDOG_MSECS_MAX 3600000 /* 1 hour */ -#define WATCHDOG_MSECS_DEFAULT 4000 /* 4 secs */ - -/* max value that will be converted from jiffies to micro seconds and written to job->render_time_usecs */ -#define JOB_MAX_JIFFIES 100000 - -int mali_hang_check_interval = HANG_CHECK_MSECS_DEFAULT; -int mali_max_job_runtime = WATCHDOG_MSECS_DEFAULT; - -#if MALI_TIMELINE_PROFILING_ENABLED -int mali_boot_profiling = 0; -#endif - -#ifdef MALI_REBOOTNOTIFIER -extern _mali_osk_atomic_t mali_shutdown_state; -#endif - -/* Subsystem entrypoints: */ -static _mali_osk_errcode_t rendercore_subsystem_startup(mali_kernel_subsystem_identifier id); -static void rendercore_subsystem_terminate(mali_kernel_subsystem_identifier id); -#if USING_MMU -static void rendercore_subsystem_broadcast_notification(mali_core_notification_message message, u32 data); -#endif - - -static void mali_core_subsystem_cleanup_all_renderunits(struct mali_core_subsystem* subsys); -static void mali_core_subsystem_move_core_set_idle(struct mali_core_renderunit *core); - -static mali_core_session * mali_core_subsystem_get_waiting_session(mali_core_subsystem *subsystem); -static mali_core_job * mali_core_subsystem_release_session_get_job(mali_core_subsystem *subsystem, mali_core_session * session); - -static void find_and_abort(mali_core_session* session, u32 abort_id); - -static void mali_core_job_start_on_core(mali_core_job *job, mali_core_renderunit *core); -#if USING_MMU -static void mali_core_subsystem_callback_schedule_wrapper(void* sub); -#endif -static void mali_core_subsystem_schedule(mali_core_subsystem*subsystem); -static void mali_core_renderunit_detach_job_from_core(mali_core_renderunit* core, mali_subsystem_reschedule_option reschedule, mali_subsystem_job_end_code end_status); - -static void mali_core_renderunit_irq_handler_remove(struct mali_core_renderunit *core); - -static _mali_osk_errcode_t mali_core_irq_handler_upper_half (void * data); -static void mali_core_irq_handler_bottom_half ( void *data ); - -#if USING_MMU -static void lock_subsystem(struct mali_core_subsystem * subsys); -static void unlock_subsystem(struct mali_core_subsystem * subsys); -#endif - - -/** - * This will be one of the subsystems in the array of subsystems: - * static struct mali_kernel_subsystem * subsystems[]; - * found in file: mali_kernel_core.c - * - * This subsystem is necessary for operations common to all rendercore - * subsystems. For example, mali_subsystem_mali200 and mali_subsystem_gp2 may - * share a mutex when RENDERCORES_USE_GLOBAL_MUTEX is non-zero. - */ -struct mali_kernel_subsystem mali_subsystem_rendercore= -{ - rendercore_subsystem_startup, /* startup */ - NULL, /*rendercore_subsystem_terminate,*/ /* shutdown */ - NULL, /* load_complete */ - NULL, /* system_info_fill */ - NULL, /* session_begin */ - NULL, /* session_end */ -#if USING_MMU - rendercore_subsystem_broadcast_notification, /* broadcast_notification */ -#else - NULL, -#endif -#if MALI_STATE_TRACKING - NULL, /* dump_state */ -#endif -} ; - -static _mali_osk_lock_t *rendercores_global_mutex = NULL; -static u32 rendercores_global_mutex_is_held = 0; -static u32 rendercores_global_mutex_owner = 0; - -/** The 'dummy' rendercore subsystem to allow global subsystem mutex to be - * locked for all subsystems that extend the ''rendercore'' */ -static mali_core_subsystem rendercore_dummy_subsystem = {0,}; - -/* - * Rendercore Subsystem functions. - * - * These are exposed by mali_subsystem_rendercore - */ - -/** - * @brief Initialize the Rendercore subsystem. - * - * This must be called before any other subsystem that extends the - * ''rendercore'' may be initialized. For example, this must be called before - * the following functions: - * - mali200_subsystem_startup(), from mali_subsystem_mali200 - * - maligp_subsystem_startup(), from mali_subsystem_gp2 - * - * @note This function is separate from mali_core_subsystem_init(). They - * are related, in that mali_core_subsystem_init() may use the structures - * initialized by rendercore_subsystem_startup() - */ -static _mali_osk_errcode_t rendercore_subsystem_startup(mali_kernel_subsystem_identifier id) -{ - rendercores_global_mutex_is_held = 0; - rendercores_global_mutex = _mali_osk_lock_init( - (_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_NONINTERRUPTABLE | _MALI_OSK_LOCKFLAG_ORDERED), - 0, 129); - - if (NULL == rendercores_global_mutex) - { - MALI_PRINT_ERROR(("Failed: _mali_osk_lock_init\n")) ; - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - rendercore_dummy_subsystem.name = "Rendercore Global Subsystem"; /* On the constant pool, do not free */ - rendercore_dummy_subsystem.magic_nr = SUBSYSTEM_MAGIC_NR; /* To please the Subsystem Mutex code */ - -#if MALI_GPU_UTILIZATION - if (mali_utilization_init() != _MALI_OSK_ERR_OK) - { - _mali_osk_lock_term(rendercores_global_mutex); - rendercores_global_mutex = NULL; - MALI_PRINT_ERROR(("Failed: mali_utilization_init\n")) ; - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } -#endif - -#if MALI_TIMELINE_PROFILING_ENABLED - if (_mali_profiling_init(mali_boot_profiling ? MALI_TRUE : MALI_FALSE) != _MALI_OSK_ERR_OK) - { - /* No biggie if we wheren't able to initialize the profiling */ - MALI_PRINT_ERROR(("Rendercore: Failed to initialize profiling, feature will be unavailable\n")) ; - } -#endif - - MALI_DEBUG_PRINT(2, ("Rendercore: subsystem global mutex initialized\n")) ; - MALI_SUCCESS; -} - -/** - * @brief Terminate the Rendercore subsystem. - * - * This must only be called \b after any other subsystem that extends the - * ''rendercore'' has been terminated. For example, this must be called \b after - * the following functions: - * - mali200_subsystem_terminate(), from mali_subsystem_mali200 - * - maligp_subsystem_terminate(), from mali_subsystem_gp2 - * - * @note This function is separate from mali_core_subsystem_cleanup(), though, - * the subsystems that extend ''rendercore'' must still call - * mali_core_subsystem_cleanup() when they terminate. - */ -static void rendercore_subsystem_terminate(mali_kernel_subsystem_identifier id) -{ - /* Catch double-terminate */ - MALI_DEBUG_ASSERT_POINTER( rendercores_global_mutex ); - -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_term(); -#endif - -#if MALI_GPU_UTILIZATION - mali_utilization_term(); -#endif - - rendercore_dummy_subsystem.name = NULL; /* The original string was on the constant pool, do not free */ - rendercore_dummy_subsystem.magic_nr = 0; - - /* ASSERT that no-one's holding this */ - MALI_DEBUG_PRINT_ASSERT( 0 == rendercores_global_mutex_is_held, - ("Rendercores' Global Mutex was held at termination time. Have the subsystems that extend ''rendercore'' been terminated?\n") ); - - _mali_osk_lock_term( rendercores_global_mutex ); - rendercores_global_mutex = NULL; - - MALI_DEBUG_PRINT(2, ("Rendercore: subsystem global mutex terminated\n")) ; -} - - -#if USING_MMU -/** - * @brief Handle certain Rendercore subsystem broadcast notifications - * - * When RENDERCORES_USE_GLOBAL_MUTEX is non-zero, this handles the following messages: - * - MMU_KILL_STEP0_LOCK_SUBSYSTEM - * - MMU_KILL_STEP4_UNLOCK_SUBSYSTEM - * - * The purpose is to manage the Rendercode Global Mutex, which cannot be - * managed by any system that extends the ''rendercore''. - * - * All other messages must be handled by mali_core_subsystem_broadcast_notification() - * - * - * When RENDERCORES_USE_GLOBAL_MUTEX is 0, this function does nothing. - * Instead, the subsystem that extends the ''rendercore' \b must handle its - * own mutexes - refer to mali_core_subsystem_broadcast_notification(). - * - * Used currently only for signalling when MMU has a pagefault - */ -static void rendercore_subsystem_broadcast_notification(mali_core_notification_message message, u32 data) -{ - switch(message) - { - case MMU_KILL_STEP0_LOCK_SUBSYSTEM: - lock_subsystem( &rendercore_dummy_subsystem ); - break; - case MMU_KILL_STEP4_UNLOCK_SUBSYSTEM: - unlock_subsystem( &rendercore_dummy_subsystem ); - break; - - case MMU_KILL_STEP1_STOP_BUS_FOR_ALL_CORES: - /** FALLTHROUGH */ - case MMU_KILL_STEP2_RESET_ALL_CORES_AND_ABORT_THEIR_JOBS: - /** FALLTHROUGH */ - case MMU_KILL_STEP3_CONTINUE_JOB_HANDLING: - break; - - default: - MALI_PRINT_ERROR(("Illegal message: 0x%x, data: 0x%x\n", (u32)message, data)); - break; - } - -} -#endif - -/* - * Functions inherited by the subsystems that extend the ''rendercore''. - */ - -void mali_core_renderunit_timeout_function_hang_detection(void *arg) -{ - mali_bool action = MALI_FALSE; - mali_core_renderunit * core; - - core = (mali_core_renderunit *) arg; - if( !core ) return; - - /* if NOT idle OR NOT powered off OR has TIMED_OUT */ - if ( !((CORE_WATCHDOG_TIMEOUT == core->state ) || (CORE_IDLE== core->state) || (CORE_OFF == core->state)) ) - { - core->state = CORE_HANG_CHECK_TIMEOUT; - action = MALI_TRUE; - } - - if(action) _mali_osk_irq_schedulework(core->irq); -} - - -void mali_core_renderunit_timeout_function(void *arg) -{ - mali_core_renderunit * core; - mali_bool is_watchdog; - - core = (mali_core_renderunit *)arg; - if( !core ) return; - - is_watchdog = MALI_TRUE; - if (mali_benchmark) - { - /* poll based core */ - mali_core_job *job; - job = core->current_job; - if ( (NULL != job) && - (0 != _mali_osk_time_after(job->watchdog_jiffies,_mali_osk_time_tickcount())) - ) - { - core->state = CORE_POLL; - is_watchdog = MALI_FALSE; - } - } - - if (is_watchdog) - { - MALI_DEBUG_PRINT(3, ("SW-Watchdog timeout: Core:%s\n", core->description)); - core->state = CORE_WATCHDOG_TIMEOUT; - } - - _mali_osk_irq_schedulework(core->irq); -} - -/* Used by external renderunit_create<> function */ -_mali_osk_errcode_t mali_core_renderunit_init(mali_core_renderunit * core) -{ - MALI_DEBUG_PRINT(5, ("Core: renderunit_init: Core:%s\n", core->description)); - - _MALI_OSK_INIT_LIST_HEAD(&core->list) ; - core->timer = _mali_osk_timer_init(); - if (NULL == core->timer) - { - MALI_PRINT_ERROR(("Core: renderunit_init: Core:%s -- cannot init timer\n", core->description)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - _mali_osk_timer_setcallback(core->timer, mali_core_renderunit_timeout_function, (void *)core); - - core->timer_hang_detection = _mali_osk_timer_init(); - if (NULL == core->timer_hang_detection) - { - _mali_osk_timer_term(core->timer); - MALI_PRINT_ERROR(("Core: renderunit_init: Core:%s -- cannot init hang detection timer\n", core->description)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - _mali_osk_timer_setcallback(core->timer_hang_detection, mali_core_renderunit_timeout_function_hang_detection, (void *)core); - -#if USING_MALI_PMM - /* Init no pending power downs */ - core->pend_power_down = MALI_FALSE; - - /* Register the core with the PMM - which powers it up */ - if (_MALI_OSK_ERR_OK != malipmm_core_register( core->pmm_id )) - { - _mali_osk_timer_term(core->timer); - _mali_osk_timer_term(core->timer_hang_detection); - MALI_PRINT_ERROR(("Core: renderunit_init: Core:%s -- cannot register with PMM\n", core->description)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } -#endif /* USING_MALI_PMM */ - - core->error_recovery = MALI_FALSE; - core->in_detach_function = MALI_FALSE; - core->state = CORE_IDLE; - core->current_job = NULL; - core->magic_nr = CORE_MAGIC_NR; -#if USING_MMU - core->mmu = NULL; -#endif /* USING_MMU */ - - MALI_SUCCESS; -} - -void mali_core_renderunit_term(mali_core_renderunit * core) -{ - MALI_DEBUG_PRINT(5, ("Core: renderunit_term: Core:%s\n", core->description)); - - if (NULL != core->timer) - { - _mali_osk_timer_term(core->timer); - core->timer = NULL; - } - if (NULL != core->timer_hang_detection) - { - _mali_osk_timer_term(core->timer_hang_detection); - core->timer_hang_detection = NULL; - } - -#if USING_MALI_PMM - /* Unregister the core with the PMM */ - malipmm_core_unregister( core->pmm_id ); -#endif -} - -/* Used by external renderunit_create<> function */ -_mali_osk_errcode_t mali_core_renderunit_map_registers(mali_core_renderunit *core) -{ - MALI_DEBUG_PRINT(3, ("Core: renderunit_map_registers: Core:%s\n", core->description)) ; - if( (0 == core->registers_base_addr) || - (0 == core->size) || - (NULL == core->description) - ) - { - MALI_PRINT_ERROR(("Missing fields in the core structure %u %u 0x%x;\n", core->registers_base_addr, core->size, core->description)); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - - if (_MALI_OSK_ERR_OK != _mali_osk_mem_reqregion(core->registers_base_addr, core->size, core->description)) - { - MALI_PRINT_ERROR(("Could not request register region (0x%08X - 0x%08X) to core: %s\n", - core->registers_base_addr, core->registers_base_addr + core->size - 1, core->description)); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - else - { - MALI_DEBUG_PRINT(6, ("Success: request_mem_region: (0x%08X - 0x%08X) Core:%s\n", - core->registers_base_addr, core->registers_base_addr + core->size - 1, core->description)); - } - - core->registers_mapped = _mali_osk_mem_mapioregion( core->registers_base_addr, core->size, core->description ); - - if ( 0 == core->registers_mapped ) - { - MALI_PRINT_ERROR(("Could not ioremap registers for %s .\n", core->description)); - _mali_osk_mem_unreqregion(core->registers_base_addr, core->size); - MALI_ERROR(_MALI_OSK_ERR_NOMEM); - } - else - { - MALI_DEBUG_PRINT(6, ("Success: ioremap_nocache: Internal ptr: (0x%08X - 0x%08X) Core:%s\n", - (u32) core->registers_mapped, - ((u32)core->registers_mapped)+ core->size - 1, - core->description)); - } - - MALI_DEBUG_PRINT(4, ("Success: Mapping registers to core: %s\n",core->description)); - - MALI_SUCCESS; -} - -/* Used by external renderunit_create<> function + other places */ -void mali_core_renderunit_unmap_registers(mali_core_renderunit *core) -{ - MALI_DEBUG_PRINT(3, ("Core: renderunit_unmap_registers: Core:%s\n", core->description)); - if (0 == core->registers_mapped) - { - MALI_PRINT_ERROR(("Trying to unmap register-mapping with NULL from core: %s\n", core->description)); - return; - } - _mali_osk_mem_unmapioregion(core->registers_base_addr, core->size, core->registers_mapped); - core->registers_mapped = 0; - _mali_osk_mem_unreqregion(core->registers_base_addr, core->size); -} - -static void mali_core_renderunit_irq_handler_remove(mali_core_renderunit *core) -{ - MALI_DEBUG_PRINT(3, ("Core: renderunit_irq_handler_remove: Core:%s\n", core->description)); - _mali_osk_irq_term(core->irq); -} - -mali_core_renderunit * mali_core_renderunit_get_mali_core_nr(mali_core_subsystem *subsys, u32 mali_core_nr) -{ - mali_core_renderunit * core; - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); - if (subsys->number_of_cores <= mali_core_nr) - { - MALI_PRINT_ERROR(("Trying to get illegal mali_core_nr: 0x%x for %s", mali_core_nr, subsys->name)); - return NULL; - } - core = (subsys->mali_core_array)[mali_core_nr]; - MALI_DEBUG_PRINT(6, ("Core: renderunit_get_mali_core_nr: Core:%s\n", core->description)); - MALI_CHECK_CORE(core); - return core; -} - -/* Is used by external function: - subsystem_startup<> */ -_mali_osk_errcode_t mali_core_subsystem_init(mali_core_subsystem* new_subsys) -{ - int i; - - /* These function pointers must have been set on before calling this function */ - if ( - ( NULL == new_subsys->name ) || - ( NULL == new_subsys->start_job ) || - ( NULL == new_subsys->irq_handler_upper_half ) || - ( NULL == new_subsys->irq_handler_bottom_half ) || - ( NULL == new_subsys->get_new_job_from_user ) || - ( NULL == new_subsys->return_job_to_user ) - ) - { - MALI_PRINT_ERROR(("Missing functions in subsystem.")); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - MALI_DEBUG_PRINT(2, ("Core: subsystem_init: %s\n", new_subsys->name)) ; - - /* Catch use-before-initialize/use-after-terminate */ - MALI_DEBUG_ASSERT_POINTER( rendercores_global_mutex ); - - new_subsys->magic_nr = SUBSYSTEM_MAGIC_NR; - - _MALI_OSK_INIT_LIST_HEAD(&new_subsys->renderunit_idle_head); /* Idle cores of this type */ - _MALI_OSK_INIT_LIST_HEAD(&new_subsys->renderunit_off_head); /* Powered off cores of this type */ - - /* Linked list for each priority of sessions with a job ready for scheduleing */ - for(i=0; i<PRIORITY_LEVELS; ++i) - { - _MALI_OSK_INIT_LIST_HEAD(&new_subsys->awaiting_sessions_head[i]); - } - - /* Linked list of all sessions connected to this coretype */ - _MALI_OSK_INIT_LIST_HEAD(&new_subsys->all_sessions_head); - - MALI_SUCCESS; -} - -#if USING_MMU -void mali_core_subsystem_attach_mmu(mali_core_subsystem* subsys) -{ - u32 i; - mali_core_renderunit * core; - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); - - for(i=0 ; i < subsys->number_of_cores ; ++i) - { - core = mali_core_renderunit_get_mali_core_nr(subsys,i); - if ( NULL==core ) break; - core->mmu = mali_memory_core_mmu_lookup(core->mmu_id); - mali_memory_core_mmu_owner(core,core->mmu); - MALI_DEBUG_PRINT(2, ("Attach mmu: 0x%x to core: %s in subsystem: %s\n", core->mmu, core->description, subsys->name)); - } - - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); -} -#endif - -/* This will register an IRQ handler, and add the core to the list of available cores for this subsystem. */ -_mali_osk_errcode_t mali_core_subsystem_register_renderunit(mali_core_subsystem* subsys, mali_core_renderunit * core) -{ - mali_core_renderunit ** mali_core_array; - u32 previous_nr; - u32 previous_size; - u32 new_nr; - u32 new_size; - _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; - - /* If any of these are 0 there is an error */ - if(0 == core->subsystem || - 0 == core->registers_base_addr || - 0 == core->size || - 0 == core->description) - { - MALI_PRINT_ERROR(("Missing fields in the core structure 0x%x 0x%x 0x%x;\n", - core->registers_base_addr, core->size, core->description)); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - - MALI_DEBUG_PRINT(3, ("Core: subsystem_register_renderunit: %s\n", core->description)); - - MALI_CHECK_NON_NULL( - core->irq = _mali_osk_irq_init( - core->irq_nr, - mali_core_irq_handler_upper_half, - mali_core_irq_handler_bottom_half, - (_mali_osk_irq_trigger_t)subsys->probe_core_irq_trigger, - (_mali_osk_irq_ack_t)subsys->probe_core_irq_acknowledge, - core, - "mali_core_irq_handlers" - ), - _MALI_OSK_ERR_FAULT - ); - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); - - /* Update which core number this is */ - core->core_number = subsys->number_of_cores; - - /* Update the array of cores in the subsystem. */ - previous_nr = subsys->number_of_cores; - previous_size = sizeof(mali_core_renderunit*)*previous_nr; - new_nr = previous_nr + 1; - new_size = sizeof(mali_core_renderunit*)*new_nr; - - if (0 != previous_nr) - { - if (NULL == subsys->mali_core_array) - { - MALI_PRINT_ERROR(("Internal error")); - goto exit_function; - } - - mali_core_array = (mali_core_renderunit **) _mali_osk_malloc( new_size ); - if (NULL == mali_core_array ) - { - MALI_PRINT_ERROR(("Out of mem")); - err = _MALI_OSK_ERR_NOMEM; - goto exit_function; - } - _mali_osk_memcpy(mali_core_array, subsys->mali_core_array, previous_size); - _mali_osk_free( subsys->mali_core_array); - MALI_DEBUG_PRINT(5, ("Success: adding a new core to subsystem array %s\n", core->description) ) ; - } - else - { - mali_core_array = (mali_core_renderunit **) _mali_osk_malloc( new_size ); - if (NULL == mali_core_array ) - { - MALI_PRINT_ERROR(("Out of mem")); - err = _MALI_OSK_ERR_NOMEM; - goto exit_function; - } - MALI_DEBUG_PRINT(6, ("Success: adding first core to subsystem array %s\n", core->description) ) ; - } - subsys->mali_core_array = mali_core_array; - mali_core_array[previous_nr] = core; - - /* Add the core to the list of available cores on the system */ - _mali_osk_list_add(&(core->list), &(subsys->renderunit_idle_head)); - - /* Update total number of cores */ - subsys->number_of_cores = new_nr; - MALI_DEBUG_PRINT(6, ("Success: mali_core_subsystem_register_renderunit %s\n", core->description)); - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - MALI_SUCCESS; - -exit_function: - mali_core_renderunit_irq_handler_remove(core); - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - MALI_ERROR(err); -} - - -/** - * Called by the core when a system info update is needed - * We fill in info about all the core types available - * @param subsys Pointer to the core's @a mali_core_subsystem data structure - * @param info Pointer to system info struct to update - * @return _MALI_OSK_ERR_OK on success, or another _mali_osk_errcode_t error code on failure - */ -_mali_osk_errcode_t mali_core_subsystem_system_info_fill(mali_core_subsystem* subsys, _mali_system_info* info) -{ - u32 i; - _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; /* OK if no cores to update info for */ - mali_core_renderunit * core; - _mali_core_info **core_info_nextp; - _mali_core_info * cinfo; - - MALI_DEBUG_PRINT(4, ("mali_core_subsystem_system_info_fill: %s\n", subsys->name) ) ; - - /* check input */ - MALI_CHECK_NON_NULL(info, _MALI_OSK_ERR_INVALID_ARGS); - - core_info_nextp = &(info->core_info); - cinfo = info->core_info; - - while(NULL!=cinfo) - { - core_info_nextp = &(cinfo->next); - cinfo = cinfo->next; - } - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); - for(i=0 ; i < subsys->number_of_cores ; ++i) - { - core = mali_core_renderunit_get_mali_core_nr(subsys,i); - if ( NULL==core ) - { - err = _MALI_OSK_ERR_FAULT; - goto early_exit; - } - cinfo = (_mali_core_info *)_mali_osk_calloc(1, sizeof(_mali_core_info)); - if ( NULL==cinfo ) - { - err = _MALI_OSK_ERR_NOMEM; - goto early_exit; - } - cinfo->version = core->core_version; - cinfo->type =subsys->core_type; - cinfo->reg_address = core->registers_base_addr; - cinfo->core_nr = i; - cinfo->next = NULL; - /* Writing this address to the previous' *(&next) ptr */ - *core_info_nextp = cinfo; - /* Setting the next_ptr to point to &this->next_ptr */ - core_info_nextp = &(cinfo->next); - } -early_exit: - if ( _MALI_OSK_ERR_OK != err) MALI_PRINT_ERROR(("Error: In mali_core_subsystem_system_info_fill %d\n", err)); - MALI_DEBUG_CODE( - cinfo = info->core_info; - - MALI_DEBUG_PRINT(3, ("Current list of cores\n")); - while( NULL != cinfo ) - { - MALI_DEBUG_PRINT(3, ("Type: 0x%x\n", cinfo->type)); - MALI_DEBUG_PRINT(3, ("Version: 0x%x\n", cinfo->version)); - MALI_DEBUG_PRINT(3, ("Reg_addr: 0x%x\n", cinfo->reg_address)); - MALI_DEBUG_PRINT(3, ("Core_nr: 0x%x\n", cinfo->core_nr)); - MALI_DEBUG_PRINT(3, ("Flags: 0x%x\n", cinfo->flags)); - MALI_DEBUG_PRINT(3, ("*****\n")); - cinfo = cinfo->next; - } - ); - - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - MALI_ERROR(err); -} - - -/* Is used by external function: - subsystem_terminate<> */ -void mali_core_subsystem_cleanup(mali_core_subsystem* subsys) -{ - u32 i; - mali_core_renderunit * core; - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); - MALI_DEBUG_PRINT(2, ("Core: subsystem_cleanup: %s\n", subsys->name )) ; - - for(i=0 ; i < subsys->number_of_cores ; ++i) - { - core = mali_core_renderunit_get_mali_core_nr(subsys,i); - -#if USING_MMU - if (NULL != core->mmu) - { - /* the MMU is attached in the load_complete callback, which will never be called if the module fails to load, handle that case */ - mali_memory_core_mmu_unregister_callback(core->mmu, mali_core_subsystem_callback_schedule_wrapper); - } -#endif - - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - - mali_core_renderunit_irq_handler_remove(core); - - /* When a process terminates, all cores running jobs from that process is reset and put to idle. - That means that when the module is unloading (this code) we are guaranteed that all cores are idle. - However: if something (we can't think of) is really wrong, a core may give an interrupt during this - unloading, and we may now in the code have a bottom-half-processing pending from the interrupts - we deregistered above. To be sure that the bottom halves do not access the structures after they - are deallocated we flush the bottom-halves processing here, before the deallocation. */ - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); - -#if USING_MALI_PMM - /* Only reset when we are using PMM and the core is not off */ -#if MALI_PMM_NO_PMU - /* We need to reset when there is no PMU - but this will - * cause the register read/write functions to report an - * error (hence the if to check for CORE_OFF below) we - * change state to allow the reset to happen. - */ - core->state = CORE_IDLE; -#endif - if( core->state != CORE_OFF ) - { - subsys->reset_core( core, MALI_CORE_RESET_STYLE_DISABLE ); - } -#else - /* Always reset the core */ - subsys->reset_core( core, MALI_CORE_RESET_STYLE_DISABLE ); -#endif - - mali_core_renderunit_unmap_registers(core); - - _mali_osk_list_delinit(&core->list); - - mali_core_renderunit_term(core); - - subsys->renderunit_delete(core); - } - - mali_core_subsystem_cleanup_all_renderunits(subsys); - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - MALI_DEBUG_PRINT(6, ("SUCCESS: mali_core_subsystem_cleanup: %s\n", subsys->name )) ; -} - -_mali_osk_errcode_t mali_core_subsystem_ioctl_number_of_cores_get(mali_core_session * session, u32 *number_of_cores) -{ - mali_core_subsystem * subsystem; - - subsystem = session->subsystem; - if ( NULL != number_of_cores ) - { - *number_of_cores = subsystem->number_of_cores; - - MALI_DEBUG_PRINT(4, ("Core: ioctl_number_of_cores_get: %s: %u\n", subsystem->name, *number_of_cores) ) ; - } - - MALI_SUCCESS; -} - -_mali_osk_errcode_t mali_core_subsystem_ioctl_start_job(mali_core_session * session, void *job_data) -{ - mali_core_subsystem * subsystem; - _mali_osk_errcode_t err; - - /* need the subsystem to run callback function */ - subsystem = session->subsystem; - MALI_CHECK_NON_NULL(subsystem, _MALI_OSK_ERR_FAULT); - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsystem); - err = subsystem->get_new_job_from_user(session, job_data); - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsystem); - - MALI_ERROR(err); -} - - -/* We return the version number to the first core in this subsystem */ -_mali_osk_errcode_t mali_core_subsystem_ioctl_core_version_get(mali_core_session * session, _mali_core_version *version) -{ - mali_core_subsystem * subsystem; - mali_core_renderunit * core0; - u32 nr_return; - - subsystem = session->subsystem; - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsystem); - - core0 = mali_core_renderunit_get_mali_core_nr(subsystem, 0); - - if( NULL == core0 ) - { - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsystem); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - nr_return = core0->core_version; - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsystem); - - MALI_DEBUG_PRINT(4, ("Core: ioctl_core_version_get: %s: %u\n", subsystem->name, nr_return )) ; - - *version = nr_return; - - MALI_SUCCESS; -} - -void mali_core_subsystem_ioctl_abort_job(mali_core_session * session, u32 id) -{ - find_and_abort(session, id); -} - -static mali_bool job_should_be_aborted(mali_core_job *job, u32 abort_id) -{ - if ( job->abort_id == abort_id ) return MALI_TRUE; - else return MALI_FALSE; -} - -static void find_and_abort(mali_core_session* session, u32 abort_id) -{ - mali_core_subsystem * subsystem; - mali_core_renderunit *core; - mali_core_renderunit *tmp; - mali_core_job *job; - - subsystem = session->subsystem; - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB( subsystem ); - - job = mali_job_queue_abort_job(session, abort_id); - if (NULL != job) - { - MALI_DEBUG_PRINT(3, ("Core: Aborting %s job, with id nr: %u, from the waiting_to_run slot.\n", subsystem->name, abort_id )); - if (mali_job_queue_empty(session)) - { - _mali_osk_list_delinit(&(session->awaiting_sessions_list)); - } - subsystem->awaiting_sessions_sum_all_priorities--; - subsystem->return_job_to_user(job , JOB_STATUS_END_ABORT); - } - - _MALI_OSK_LIST_FOREACHENTRY( core, tmp, &session->renderunits_working_head, mali_core_renderunit, list ) - { - job = core->current_job; - if ( (job!=NULL) && (job_should_be_aborted (job, abort_id) ) ) - { - MALI_DEBUG_PRINT(3, ("Core: Aborting %s job, with id nr: %u, which is currently running on mali.\n", subsystem->name, abort_id )); - if ( core->state==CORE_IDLE ) - { - MALI_PRINT_ERROR(("Aborting core with running job which is idle. Must be something very wrong.")); - goto end_bug; - } - mali_core_renderunit_detach_job_from_core(core, SUBSYSTEM_RESCHEDULE, JOB_STATUS_END_ABORT); - } - } -end_bug: - - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE( subsystem ); -} - - -_mali_osk_errcode_t mali_core_subsystem_ioctl_suspend_response(mali_core_session * session, void *argument) -{ - mali_core_subsystem * subsystem; - _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; - - /* need the subsystem to run callback function */ - subsystem = session->subsystem; - MALI_CHECK_NON_NULL(subsystem, _MALI_OSK_ERR_FAULT); - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsystem); - if ( NULL != subsystem->suspend_response) - { - MALI_DEBUG_PRINT(4, ("MALI_IOC_CORE_CMD_SUSPEND_RESPONSE start\n")); - err = subsystem->suspend_response(session, argument); - MALI_DEBUG_PRINT(4, ("MALI_IOC_CORE_CMD_SUSPEND_RESPONSE end\n")); - } - - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsystem); - - return err; -} - - -/* Is used by internal function: - mali_core_subsystem_cleanup<>s */ -/* All cores should be removed before calling this function -Must hold subsystem_mutex before entering this function */ -static void mali_core_subsystem_cleanup_all_renderunits(mali_core_subsystem* subsys) -{ - int i; - _mali_osk_free(subsys->mali_core_array); - subsys->number_of_cores = 0; - - MALI_DEBUG_PRINT(5, ("Core: subsystem_cleanup_all_renderunits: %s\n", subsys->name) ) ; - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); - - if ( ! _mali_osk_list_empty(&(subsys->renderunit_idle_head))) - { - MALI_PRINT_ERROR(("List renderunit_list_idle should be empty.")); - _MALI_OSK_INIT_LIST_HEAD(&(subsys->renderunit_idle_head)) ; - } - - if ( ! _mali_osk_list_empty(&(subsys->renderunit_off_head))) - { - MALI_PRINT_ERROR(("List renderunit_list_off should be empty.")); - _MALI_OSK_INIT_LIST_HEAD(&(subsys->renderunit_off_head)) ; - } - - for(i=0; i<PRIORITY_LEVELS; ++i) - { - if ( ! _mali_osk_list_empty(&(subsys->awaiting_sessions_head[i]))) - { - MALI_PRINT_ERROR(("List awaiting_sessions_linkedlist should be empty.")); - _MALI_OSK_INIT_LIST_HEAD(&(subsys->awaiting_sessions_head[i])) ; - subsys->awaiting_sessions_sum_all_priorities = 0; - } - } - - if ( ! _mali_osk_list_empty(&(subsys->all_sessions_head))) - { - MALI_PRINT_ERROR(("List all_sessions_linkedlist should be empty.")); - _MALI_OSK_INIT_LIST_HEAD(&(subsys->all_sessions_head)) ; - } -} - -/* Is used by internal functions: - mali_core_irq_handler_bottom_half<>; - mali_core_subsystem_schedule<>; */ -/* Will release the core.*/ -/* Must hold subsystem_mutex before entering this function */ -static void mali_core_subsystem_move_core_set_idle(mali_core_renderunit *core) -{ - mali_core_subsystem *subsystem; -#if USING_MALI_PMM - mali_core_status oldstatus; -#endif - subsystem = core->subsystem; - MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); - MALI_CHECK_CORE(core); - MALI_CHECK_SUBSYSTEM(subsystem); - - _mali_osk_timer_del(core->timer); - _mali_osk_timer_del(core->timer_hang_detection); - - MALI_DEBUG_PRINT(5, ("Core: subsystem_move_core_set_idle: %s\n", core->description) ) ; - - core->current_job = NULL ; - -#if USING_MALI_PMM - - oldstatus = core->state; - - if ( !core->pend_power_down ) - { - core->state = CORE_IDLE ; - _mali_osk_list_move( &core->list, &subsystem->renderunit_idle_head ); - } - - if( CORE_OFF != oldstatus ) - { - /* Message that this core is now idle or in fact off */ - _mali_uk_pmm_message_s event = { - NULL, - MALI_PMM_EVENT_JOB_FINISHED, - 0 }; - event.data = core->pmm_id; - _mali_ukk_pmm_event_message( &event ); -#if USING_MMU - /* Only free the reference when entering idle state from - * anything other than power off - */ - mali_memory_core_mmu_release_address_space_reference(core->mmu); -#endif /* USING_MMU */ - } - - if( core->pend_power_down ) - { - core->state = CORE_OFF ; - _mali_osk_list_move( &core->list, &subsystem->renderunit_off_head ); - - /* Done the move from the active queues, so the pending power down can be done */ - core->pend_power_down = MALI_FALSE; - malipmm_core_power_down_okay( core->pmm_id ); - } - -#else /* !USING_MALI_PMM */ - - core->state = CORE_IDLE ; - _mali_osk_list_move( &core->list, &subsystem->renderunit_idle_head ); - -#if USING_MMU - mali_memory_core_mmu_release_address_space_reference(core->mmu); -#endif - -#endif /* USING_MALI_PMM */ -} - -/* Must hold subsystem_mutex before entering this function */ -static void mali_core_subsystem_move_set_working(mali_core_renderunit *core, mali_core_job *job) -{ - mali_core_subsystem *subsystem; - mali_core_session *session; - u64 time_now; - - session = job->session; - subsystem = core->subsystem; - - MALI_CHECK_CORE(core); - MALI_CHECK_JOB(job); - MALI_CHECK_SUBSYSTEM(subsystem); - - MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); - - MALI_DEBUG_PRINT(5, ("Core: subsystem_move_set_working: %s\n", core->description) ) ; - - time_now = _mali_osk_time_get_ns(); - job->start_time = time_now; -#if MALI_GPU_UTILIZATION - mali_utilization_core_start(time_now); -#endif - - core->current_job = job ; - core->state = CORE_WORKING ; - _mali_osk_list_move( &core->list, &session->renderunits_working_head ); - -} - -#if USING_MALI_PMM - -/* Must hold subsystem_mutex before entering this function */ -static void mali_core_subsystem_move_core_set_off(mali_core_renderunit *core) -{ - mali_core_subsystem *subsystem; - subsystem = core->subsystem; - MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); - MALI_CHECK_CORE(core); - MALI_CHECK_SUBSYSTEM(subsystem); - - /* Cores must be idle before powering off */ - MALI_DEBUG_ASSERT(core->state == CORE_IDLE); - - MALI_DEBUG_PRINT(5, ("Core: subsystem_move_core_set_off: %s\n", core->description) ) ; - - core->current_job = NULL ; - core->state = CORE_OFF ; - _mali_osk_list_move( &core->list, &subsystem->renderunit_off_head ); -} - -#endif /* USING_MALI_PMM */ - -/* Is used by internal function: - mali_core_subsystem_schedule<>; */ -/* Returns the job with the highest priority for the subsystem. NULL if none*/ -/* Must hold subsystem_mutex before entering this function */ -static mali_core_session * mali_core_subsystem_get_waiting_session(mali_core_subsystem *subsystem) -{ - int i; - - MALI_CHECK_SUBSYSTEM(subsystem); - MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); - - if ( 0 == subsystem->awaiting_sessions_sum_all_priorities ) - { - MALI_DEBUG_PRINT(5, ("Core: subsystem_get_waiting_job: No awaiting session found\n")); - return NULL; - } - - for( i=0; i<PRIORITY_LEVELS ; ++i) - { - if (!_mali_osk_list_empty(&subsystem->awaiting_sessions_head[i])) - { - return _MALI_OSK_LIST_ENTRY(subsystem->awaiting_sessions_head[i].next, mali_core_session, awaiting_sessions_list); - } - } - - return NULL; -} - -static mali_core_job * mali_core_subsystem_release_session_get_job(mali_core_subsystem *subsystem, mali_core_session * session) -{ - mali_core_job *job; - MALI_CHECK_SUBSYSTEM(subsystem); - MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); - - job = mali_job_queue_get_job(session); - subsystem->awaiting_sessions_sum_all_priorities--; - - if(mali_job_queue_empty(session)) - { - /* This is the last job, so remove it from the list */ - _mali_osk_list_delinit(&session->awaiting_sessions_list); - } - else - { - if (0 == (job->flags & MALI_UK_START_JOB_FLAG_MORE_JOBS_FOLLOW)) - { - /* There are more jobs, but the follow flag is not set, so let other sessions run their jobs first */ - _mali_osk_list_del(&(session->awaiting_sessions_list)); - _mali_osk_list_addtail(&(session->awaiting_sessions_list), &(subsystem->awaiting_sessions_head[ - session->queue[session->queue_head]->priority])); - } - /* else; keep on list, follow flag is set and there are more jobs in queue for this session */ - } - - MALI_CHECK_JOB(job); - return job; -} - -/* Is used by internal functions: - mali_core_subsystem_schedule<> */ -/* This will start the job on the core. It will also release the core if it did not start.*/ -/* Must hold subsystem_mutex before entering this function */ -static void mali_core_job_start_on_core(mali_core_job *job, mali_core_renderunit *core) -{ - mali_core_session *session; - mali_core_subsystem *subsystem; - _mali_osk_errcode_t err; - session = job->session; - subsystem = core->subsystem; - - MALI_CHECK_CORE(core); - MALI_CHECK_JOB(job); - MALI_CHECK_SUBSYSTEM(subsystem); - MALI_CHECK_SESSION(session); - MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); - - MALI_DEBUG_PRINT(4, ("Core: job_start_on_core: job=0x%x, session=0x%x, core=%s\n", job, session, core->description)); - - MALI_DEBUG_ASSERT(NULL == core->current_job) ; - MALI_DEBUG_ASSERT(CORE_IDLE == core->state ); - - mali_core_subsystem_move_set_working(core, job); - -#if defined USING_MALI400_L2_CACHE - if (0 == (job->flags & MALI_UK_START_JOB_FLAG_NO_FLUSH)) - { - /* Invalidate the L2 cache */ - if (_MALI_OSK_ERR_OK != mali_kernel_l2_cache_invalidate_all() ) - { - MALI_DEBUG_PRINT(4, ("Core: Clear of L2 failed, return job. System may not be usable for some reason.\n")); - mali_core_subsystem_move_core_set_idle(core); - subsystem->return_job_to_user(job,JOB_STATUS_END_SYSTEM_UNUSABLE ); - return; - } - } -#endif - - /* Tries to start job on the core. Returns MALI_FALSE if the job could not be started */ - err = subsystem->start_job(job, core); - - if ( _MALI_OSK_ERR_OK != err ) - { - /* This will happen only if there is something in the job object - which make it inpossible to start. Like if it require illegal memory.*/ - MALI_DEBUG_PRINT(4, ("Core: start_job failed, return job and putting core back into idle list\n")); - mali_core_subsystem_move_core_set_idle(core); - subsystem->return_job_to_user(job,JOB_STATUS_END_ILLEGAL_JOB ); - } - else - { - u32 delay = _mali_osk_time_mstoticks(job->watchdog_msecs)+1; - job->watchdog_jiffies = _mali_osk_time_tickcount() + delay; - if (mali_benchmark) - { - _mali_osk_timer_add(core->timer, 1); - } - else - { - _mali_osk_timer_add(core->timer, delay); - } - } -} - -#if USING_MMU -static void mali_core_subsystem_callback_schedule_wrapper(void* sub) -{ - mali_core_subsystem * subsystem; - subsystem = (mali_core_subsystem *)sub; - MALI_DEBUG_PRINT(3, ("MMU: Is schedulling subsystem: %s\n", subsystem->name)); - mali_core_subsystem_schedule(subsystem); -} -#endif - -/* Is used by internal function: - mali_core_irq_handler_bottom_half - mali_core_session_add_job -*/ -/* Must hold subsystem_mutex before entering this function */ -static void mali_core_subsystem_schedule(mali_core_subsystem * subsystem) -{ - mali_core_renderunit *core, *tmp; - mali_core_session *session; - mali_core_job *job; -#ifdef MALI_REBOOTNOTIFIER - if (_mali_osk_atomic_read(&mali_shutdown_state) > 0) { - MALI_DEBUG_PRINT(3, ("Core: mali already under shutdown process!!")) ; - return; - } -#endif - - MALI_DEBUG_PRINT(5, ("Core: subsystem_schedule: %s\n", subsystem->name )) ; - - MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); - - /* First check that there are sessions with jobs waiting to run */ - if ( 0 == subsystem->awaiting_sessions_sum_all_priorities) - { - MALI_DEBUG_PRINT(6, ("Core: No jobs available for %s\n", subsystem->name) ) ; - return; - } - - /* Returns the session with the highest priority job for the subsystem. NULL if none*/ - session = mali_core_subsystem_get_waiting_session(subsystem); - - if (NULL == session) - { - MALI_DEBUG_PRINT(6, ("Core: Schedule: No runnable job found\n")); - return; - } - - _MALI_OSK_LIST_FOREACHENTRY(core, tmp, &subsystem->renderunit_idle_head, mali_core_renderunit, list) - { -#if USING_MMU - int err = mali_memory_core_mmu_activate_page_table(core->mmu, session->mmu_session, mali_core_subsystem_callback_schedule_wrapper, subsystem); - if (0 == err) - { - /* core points to a core where the MMU page table activation succeeded */ -#endif - /* This will remove the job from queue system */ - job = mali_core_subsystem_release_session_get_job(subsystem, session); - MALI_DEBUG_ASSERT_POINTER(job); - - MALI_DEBUG_PRINT(6, ("Core: Schedule: Got a job 0x%x\n", job)); - -#if USING_MALI_PMM - { - /* Message that there is a job scheduled to run - * NOTE: mali_core_job_start_on_core() can fail to start - * the job for several reasons, but it will move the core - * back to idle which will create the FINISHED message - * so we can still say that the job is SCHEDULED - */ - _mali_uk_pmm_message_s event = { - NULL, - MALI_PMM_EVENT_JOB_SCHEDULED, - 0 }; - event.data = core->pmm_id; - _mali_ukk_pmm_event_message( &event ); - } -#endif - /* This will {remove core from freelist AND start the job on the core}*/ - mali_core_job_start_on_core(job, core); - - MALI_DEBUG_PRINT(6, ("Core: Schedule: Job started, done\n")); - return; -#if USING_MMU - } -#endif - } - MALI_DEBUG_PRINT(6, ("Core: Schedule: Could not activate MMU. Scheduelling postponed to MMU, checking next.\n")); - -#if USING_MALI_PMM - { - /* Message that there are jobs to run */ - _mali_uk_pmm_message_s event = { - NULL, - MALI_PMM_EVENT_JOB_QUEUED, - 0 }; - if( subsystem->core_type == _MALI_GP2 || subsystem->core_type == _MALI_400_GP ) - { - event.data = MALI_PMM_CORE_GP; - } - else - { - /* Check the PP is supported by the PMM */ - MALI_DEBUG_ASSERT( subsystem->core_type == _MALI_200 || subsystem->core_type == _MALI_400_PP ); - /* We state that all PP cores are scheduled to inform the PMM - * that it may need to power something up! - */ - event.data = MALI_PMM_CORE_PP_ALL; - } - _mali_ukk_pmm_event_message( &event ); - } -#endif /* USING_MALI_PMM */ - -} - -/* Is used by external function: - session_begin<> */ -void mali_core_session_begin(mali_core_session * session) -{ - mali_core_subsystem * subsystem; - int i; - - subsystem = session->subsystem; - if ( NULL == subsystem ) - { - MALI_PRINT_ERROR(("Missing data in struct\n")); - return; - } - MALI_DEBUG_PRINT(2, ("Core: session_begin: for %s\n", session->subsystem->name )) ; - - session->magic_nr = SESSION_MAGIC_NR; - - _MALI_OSK_INIT_LIST_HEAD(&session->renderunits_working_head); - - for (i = 0; i < MALI_JOB_QUEUE_SIZE; i++) - { - session->queue[i] = NULL; - } - session->queue_head = 0; - session->queue_tail = 0; - _MALI_OSK_INIT_LIST_HEAD(&session->awaiting_sessions_list); - _MALI_OSK_INIT_LIST_HEAD(&session->all_sessions_list); - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsystem); - _mali_osk_list_add(&session->all_sessions_list, &session->subsystem->all_sessions_head); - -#if MALI_STATE_TRACKING - _mali_osk_atomic_init(&session->jobs_received, 0); - _mali_osk_atomic_init(&session->jobs_returned, 0); - session->pid = _mali_osk_get_pid(); -#endif - - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsystem); - - MALI_DEBUG_PRINT(5, ("Core: session_begin: for %s DONE\n", session->subsystem->name) ) ; -} - -#if USING_MMU -static void mali_core_renderunit_stop_bus(mali_core_renderunit* core) -{ - core->subsystem->stop_bus(core); -} -#endif - -void mali_core_session_close(mali_core_session * session) -{ - mali_core_subsystem * subsystem; - mali_core_renderunit *core; - - subsystem = session->subsystem; - MALI_DEBUG_ASSERT_POINTER(subsystem); - - MALI_DEBUG_PRINT(2, ("Core: session_close: for %s\n", session->subsystem->name) ) ; - - /* We must grab subsystem mutex since the list this session belongs to - is owned by the subsystem */ - MALI_CORE_SUBSYSTEM_MUTEX_GRAB( subsystem ); - - /* Remove this session from the global sessionlist */ - _mali_osk_list_delinit(&session->all_sessions_list); - - _mali_osk_list_delinit(&(session->awaiting_sessions_list)); - - /* Return the potensial waiting job to user */ - while ( !mali_job_queue_empty(session) ) - { - /* Queue not empty */ - mali_core_job *job = mali_job_queue_get_job(session); - subsystem->return_job_to_user( job, JOB_STATUS_END_SHUTDOWN ); - subsystem->awaiting_sessions_sum_all_priorities--; - } - - /* Kill active cores working for this session - freeing their jobs - Since the handling of one core also could stop jobs from another core, there is a while loop */ - while ( ! _mali_osk_list_empty(&session->renderunits_working_head) ) - { - core = _MALI_OSK_LIST_ENTRY(session->renderunits_working_head.next, mali_core_renderunit, list); - MALI_DEBUG_PRINT(3, ("Core: session_close: Core was working: %s\n", core->description )) ; - mali_core_renderunit_detach_job_from_core(core, SUBSYSTEM_RESCHEDULE, JOB_STATUS_END_SHUTDOWN ); - } - _MALI_OSK_INIT_LIST_HEAD(&session->renderunits_working_head); /* Not necessary - we will _mali_osk_free session*/ - - MALI_DEBUG_PRINT(5, ("Core: session_close: for %s FINISHED\n", session->subsystem->name )) ; - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE( subsystem ); -} - -/* Must hold subsystem_mutex before entering this function */ -_mali_osk_errcode_t mali_core_session_add_job(mali_core_session * session, mali_core_job *job, mali_core_job **job_return) -{ - mali_core_subsystem * subsystem; - - job->magic_nr = JOB_MAGIC_NR; - MALI_CHECK_SESSION(session); - - subsystem = session->subsystem; - MALI_CHECK_SUBSYSTEM(subsystem); - MALI_ASSERT_MUTEX_IS_GRABBED(subsystem); - - MALI_DEBUG_PRINT(5, ("Core: session_add_job: for %s\n", subsystem->name )) ; - - /* Setting the default value; No job to return */ - MALI_DEBUG_ASSERT_POINTER(job_return); - *job_return = NULL; - - if (mali_job_queue_empty(session)) - { - /* Add session to the wait list only if it didn't already have a job waiting. */ - _mali_osk_list_addtail( &(session->awaiting_sessions_list), &(subsystem->awaiting_sessions_head[job->priority])); - } - - - if (_MALI_OSK_ERR_OK != mali_job_queue_add_job(session, job)) - { - if (mali_job_queue_empty(session)) - { - _mali_osk_list_delinit(&(session->awaiting_sessions_list)); - } - MALI_DEBUG_PRINT(4, ("Core: session_add_job: %s queue is full\n", subsystem->name)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* Continue to add the new job as the next job from this session */ - MALI_DEBUG_PRINT(6, ("Core: session_add_job job=0x%x\n", job)); - - subsystem->awaiting_sessions_sum_all_priorities++; - - mali_core_subsystem_schedule(subsystem); - - MALI_DEBUG_PRINT(6, ("Core: session_add_job: for %s FINISHED\n", session->subsystem->name )) ; - - MALI_SUCCESS; -} - -static void mali_core_job_set_run_time(mali_core_job * job, u64 end_time) -{ - u32 time_used_nano_seconds; - - time_used_nano_seconds = end_time - job->start_time; - job->render_time_usecs = time_used_nano_seconds / 1000; -} - -static void mali_core_renderunit_detach_job_from_core(mali_core_renderunit* core, mali_subsystem_reschedule_option reschedule, mali_subsystem_job_end_code end_status) -{ - mali_core_job * job; - mali_core_subsystem * subsystem; - mali_bool already_in_detach_function; - u64 time_now; - - MALI_DEBUG_ASSERT(CORE_IDLE != core->state); - time_now = _mali_osk_time_get_ns(); - job = core->current_job; - subsystem = core->subsystem; - - /* The reset_core() called some lines below might call this detach - * funtion again. To protect the core object from being modified by - * recursive calls, the in_detach_function would track if it is an recursive call - */ - already_in_detach_function = core->in_detach_function; - - - if ( MALI_FALSE == already_in_detach_function ) - { - core->in_detach_function = MALI_TRUE; - if ( NULL != job ) - { - mali_core_job_set_run_time(job, time_now); - core->current_job = NULL; - } - } - - if (JOB_STATUS_END_SEG_FAULT == end_status) - { - subsystem->reset_core( core, MALI_CORE_RESET_STYLE_HARD ); - } - else - { - subsystem->reset_core( core, MALI_CORE_RESET_STYLE_RUNABLE ); - } - - if ( MALI_FALSE == already_in_detach_function ) - { - if ( CORE_IDLE != core->state ) - { - #if MALI_GPU_UTILIZATION - mali_utilization_core_end(time_now); - #endif - mali_core_subsystem_move_core_set_idle(core); - } - - core->in_detach_function = MALI_FALSE; - - if ( SUBSYSTEM_RESCHEDULE == reschedule ) - { - mali_core_subsystem_schedule(subsystem); - } - if ( NULL != job ) - { - core->subsystem->return_job_to_user(job, end_status); - } - } -} - -#if USING_MMU -/* This function intentionally does not release the semaphore. You must run - stop_bus_for_all_cores(), reset_all_cores_on_mmu() and continue_job_handling() - after calling this function, and then call unlock_subsystem() to release the - semaphore. */ - -static void lock_subsystem(struct mali_core_subsystem * subsys) -{ - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); -} - -/* You must run lock_subsystem() before entering this function, to ensure that - the subsystem mutex is held. - Later, unlock_subsystem() can be called to release the mutex. - - This function only stops cores behind the given MMU, unless "mmu" is NULL, in - which case all cores are stopped. -*/ -static void stop_bus_for_all_cores_on_mmu(struct mali_core_subsystem * subsys, void* mmu) -{ - u32 i; - - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); - MALI_DEBUG_PRINT(2,("Handling: bus stop %s\n", subsys->name )); - for(i=0 ; i < subsys->number_of_cores ; ++i) - { - mali_core_renderunit * core; - core = mali_core_renderunit_get_mali_core_nr(subsys,i); - - /* We stop only cores behind the given MMU, unless MMU is NULL */ - if ( (NULL!=mmu) && (core->mmu != mmu) ) continue; - - if ( CORE_IDLE != core->state ) - { - MALI_DEBUG_PRINT(4, ("Stopping bus on core %s\n", core->description)); - mali_core_renderunit_stop_bus(core); - core->error_recovery = MALI_TRUE; - } - else - { - MALI_DEBUG_PRINT(4,("Core: not active %s\n", core->description )); - } - } - /* Mutex is still being held, to prevent things to happen while we do cleanup */ - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); -} - -/* You must run lock_subsystem() before entering this function, to ensure that - the subsystem mutex is held. - Later, unlock_subsystem() can be called to release the mutex. - - This function only resets cores behind the given MMU, unless "mmu" is NULL, in - which case all cores are reset. -*/ -static void reset_all_cores_on_mmu(struct mali_core_subsystem * subsys, void* mmu) -{ - u32 i; - - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); - MALI_DEBUG_PRINT(3, ("Handling: reset cores from mmu: 0x%x on %s\n", mmu, subsys->name )); - for(i=0 ; i < subsys->number_of_cores ; ++i) - { - mali_core_renderunit * core; - core = mali_core_renderunit_get_mali_core_nr(subsys,i); - - /* We reset only cores behind the given MMU, unless MMU is NULL */ - if ( (NULL!=mmu) && (core->mmu != mmu) ) continue; - - if ( CORE_IDLE != core->state ) - { - MALI_DEBUG_PRINT(4, ("Abort and reset core: %s\n", core->description )); - mali_core_renderunit_detach_job_from_core(core, SUBSYSTEM_WAIT, JOB_STATUS_END_SEG_FAULT); - } - else - { - MALI_DEBUG_PRINT(4, ("Core: not active %s\n", core->description )); - } - } - MALI_DEBUG_PRINT(4, ("Handling: done %s\n", subsys->name )); - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); -} - -/* You must run lock_subsystem() before entering this function, to ensure that - the subsystem mutex is held. - Later, unlock_subsystem() can be called to release the mutex. */ -static void continue_job_handling(struct mali_core_subsystem * subsys) -{ - u32 i, j; - - MALI_DEBUG_PRINT(3, ("Handling: Continue: %s\n", subsys->name )); - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); - - - for(i=0 ; i < subsys->number_of_cores ; ++i) - { - mali_core_renderunit * core; - core = mali_core_renderunit_get_mali_core_nr(subsys,i); - core->error_recovery = MALI_FALSE; - } - - i = subsys->number_of_cores; - j = subsys->awaiting_sessions_sum_all_priorities; - - /* Schedule MIN(nr_waiting_jobs , number of cores) times */ - while( i-- && j--) - { - mali_core_subsystem_schedule(subsys); - } - MALI_DEBUG_PRINT(4, ("Handling: done %s\n", subsys->name )); - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); -} - -/* Unlock the subsystem. */ -static void unlock_subsystem(struct mali_core_subsystem * subsys) -{ - MALI_ASSERT_MUTEX_IS_GRABBED(subsys); - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); -} - -void mali_core_subsystem_broadcast_notification(struct mali_core_subsystem * subsys, mali_core_notification_message message, u32 data) -{ - void * mmu; - mmu = (void*) data; - - switch(message) - { - case MMU_KILL_STEP0_LOCK_SUBSYSTEM: - break; - case MMU_KILL_STEP1_STOP_BUS_FOR_ALL_CORES: - stop_bus_for_all_cores_on_mmu(subsys, mmu); - break; - case MMU_KILL_STEP2_RESET_ALL_CORES_AND_ABORT_THEIR_JOBS: - reset_all_cores_on_mmu(subsys, mmu ); - break; - case MMU_KILL_STEP3_CONTINUE_JOB_HANDLING: - continue_job_handling(subsys); - break; - case MMU_KILL_STEP4_UNLOCK_SUBSYSTEM: - break; - - default: - MALI_PRINT_ERROR(("Illegal message: 0x%x, data: 0x%x\n", (u32)message, data)); - break; - } -} -#endif /* USING_MMU */ - -void job_watchdog_set(mali_core_job * job, u32 watchdog_msecs) -{ - if (watchdog_msecs == 0) job->watchdog_msecs = mali_max_job_runtime; /* use the default */ - else if (watchdog_msecs > WATCHDOG_MSECS_MAX) job->watchdog_msecs = WATCHDOG_MSECS_MAX; /* no larger than max */ - else if (watchdog_msecs < WATCHDOG_MSECS_MIN) job->watchdog_msecs = WATCHDOG_MSECS_MIN; /* not below min */ - else job->watchdog_msecs = watchdog_msecs; -} - -u32 mali_core_hang_check_timeout_get(void) -{ - /* check the value. The user might have set the value outside the allowed range */ - if (mali_hang_check_interval > HANG_CHECK_MSECS_MAX) mali_hang_check_interval = HANG_CHECK_MSECS_MAX; /* cap to max */ - else if (mali_hang_check_interval < HANG_CHECK_MSECS_MIN) mali_hang_check_interval = HANG_CHECK_MSECS_MIN; /* cap to min */ - - /* return the active value */ - return mali_hang_check_interval; -} - -static _mali_osk_errcode_t mali_core_irq_handler_upper_half (void * data) -{ - mali_core_renderunit *core; - u32 has_pending_irq; - - core = (mali_core_renderunit * )data; - - if(core && (CORE_OFF == core->state)) - { - MALI_SUCCESS; - } - - if ( (NULL == core) || - (NULL == core->subsystem) || - (NULL == core->subsystem->irq_handler_upper_half) ) - { - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - MALI_CHECK_CORE(core); - MALI_CHECK_SUBSYSTEM(core->subsystem); - - has_pending_irq = core->subsystem->irq_handler_upper_half(core); - - if ( has_pending_irq ) - { - _mali_osk_irq_schedulework( core->irq ) ; - MALI_SUCCESS; - } - - if (mali_benchmark) MALI_SUCCESS; - - MALI_ERROR(_MALI_OSK_ERR_FAULT); -} - -static void mali_core_irq_handler_bottom_half ( void *data ) -{ - mali_core_renderunit *core; - mali_core_subsystem* subsystem; - - mali_subsystem_job_end_code job_status; - - core = (mali_core_renderunit * )data; - - MALI_CHECK_CORE(core); - subsystem = core->subsystem; - MALI_CHECK_SUBSYSTEM(subsystem); - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB( subsystem ); - if ( CORE_IDLE == core->state || CORE_OFF == core->state ) goto end_function; - - MALI_DEBUG_PRINT(5, ("IRQ: handling irq from core %s\n", core->description )) ; - - _mali_osk_cache_flushall(); - - /* This function must also update the job status flag */ - job_status = subsystem->irq_handler_bottom_half( core ); - - /* Retval is nonzero if the job is finished. */ - if ( JOB_STATUS_CONTINUE_RUN != job_status ) - { - mali_core_renderunit_detach_job_from_core(core, SUBSYSTEM_RESCHEDULE, job_status); - } - else - { - switch ( core->state ) - { - case CORE_WATCHDOG_TIMEOUT: - MALI_DEBUG_PRINT(2, ("Watchdog SW Timeout of job from core: %s\n", core->description )); - mali_core_renderunit_detach_job_from_core(core, SUBSYSTEM_RESCHEDULE, JOB_STATUS_END_TIMEOUT_SW ); - break; - - case CORE_POLL: - MALI_DEBUG_PRINT(5, ("Poll core: %s\n", core->description )) ; - core->state = CORE_WORKING; - _mali_osk_timer_add( core->timer, 1); - break; - - default: - MALI_DEBUG_PRINT(4, ("IRQ: The job on the core continue to run: %s\n", core->description )) ; - break; - } - } -end_function: - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsystem); -} - -void subsystem_flush_mapped_mem_cache(void) -{ - _mali_osk_cache_flushall(); - _mali_osk_mem_barrier(); -} - -#if USING_MALI_PMM - -_mali_osk_errcode_t mali_core_subsystem_signal_power_down(mali_core_subsystem *subsys, u32 mali_core_nr, mali_bool immediate_only) -{ - mali_core_renderunit * core = NULL; - - MALI_CHECK_SUBSYSTEM(subsys); - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); - - /* It is possible that this signal funciton can be called during a driver exit, - * and so the requested core may now be destroyed. (This is due to us not having - * the subsys lock before signalling power down). - * mali_core_renderunit_get_mali_core_nr() will report a Mali ERR because - * the core number is out of range (which is a valid error in other cases). - * So instead we check here (now that we have the subsys lock) and let the - * caller cope with the core get failure and check that the core has - * been unregistered in the PMM as part of its destruction. - */ - if ( subsys->number_of_cores > mali_core_nr ) - { - core = mali_core_renderunit_get_mali_core_nr(subsys, mali_core_nr); - } - - if ( NULL == core ) - { - /* Couldn't find the core */ - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - MALI_DEBUG_PRINT( 1, ("Core: Failed to find core to power down\n") ); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - else if ( core->state != CORE_IDLE ) - { - /* When powering down we either set a pending power down flag here so we - * can power down cleanly after the job completes or we don't set the - * flag if we have been asked to only do a power down right now - * In either case, return that the core is busy - */ - if ( !immediate_only ) core->pend_power_down = MALI_TRUE; - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - MALI_DEBUG_PRINT( 5, ("Core: No idle core to power down\n") ); - MALI_ERROR(_MALI_OSK_ERR_BUSY); - } - - /* Shouldn't have a pending power down flag set */ - MALI_DEBUG_ASSERT( !core->pend_power_down ); - - /* Move core to off queue */ - mali_core_subsystem_move_core_set_off(core); - - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - - MALI_SUCCESS; -} - -_mali_osk_errcode_t mali_core_subsystem_signal_power_up(mali_core_subsystem *subsys, u32 mali_core_nr, mali_bool queue_only) -{ - mali_core_renderunit * core; - - MALI_CHECK_SUBSYSTEM(subsys); - MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys); - - core = mali_core_renderunit_get_mali_core_nr(subsys, mali_core_nr); - - if( core == NULL ) - { - /* Couldn't find the core */ - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - MALI_DEBUG_PRINT( 1, ("Core: Failed to find core to power up\n") ); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - else if( core->state != CORE_OFF ) - { - /* This will usually happen because we are trying to cancel a pending power down */ - core->pend_power_down = MALI_FALSE; - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - MALI_DEBUG_PRINT( 1, ("Core: No powered off core to power up (cancelled power down?)\n") ); - MALI_ERROR(_MALI_OSK_ERR_BUSY); - } - - /* Shouldn't have a pending power down set */ - MALI_DEBUG_ASSERT( !core->pend_power_down ); - - /* Move core to idle queue */ - mali_core_subsystem_move_core_set_idle(core); - - if( !queue_only ) - { - /* Reset MMU & core - core must be idle to allow this */ -#if USING_MMU - if ( NULL!=core->mmu ) - { -#if defined(USING_MALI200) - if (core->pmm_id != MALI_PMM_CORE_PP0) - { -#endif - mali_kernel_mmu_reset(core->mmu); -#if defined(USING_MALI200) - } -#endif - - } -#endif /* USING_MMU */ - subsys->reset_core( core, MALI_CORE_RESET_STYLE_RUNABLE ); - } - - /* Need to schedule work to start on this core */ - mali_core_subsystem_schedule(subsys); - - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys); - - MALI_SUCCESS; -} - -#endif /* USING_MALI_PMM */ - -#if MALI_STATE_TRACKING -u32 mali_core_renderunit_dump_state(mali_core_subsystem* subsystem, char *buf, u32 size) -{ - u32 i, len = 0; - mali_core_renderunit *core; - mali_core_renderunit *tmp_core; - - mali_core_session* session; - mali_core_session* tmp_session; - - if (0 >= size) - { - return 0; - } - - MALI_CORE_SUBSYSTEM_MUTEX_GRAB( subsystem ); - - len += _mali_osk_snprintf(buf + len, size - len, "Subsystem:\n"); - len += _mali_osk_snprintf(buf + len, size - len, " Name: %s\n", subsystem->name); - - for (i = 0; i < subsystem->number_of_cores; i++) - { - len += _mali_osk_snprintf(buf + len, size - len, " Core: #%u\n", - subsystem->mali_core_array[i]->core_number); - len += _mali_osk_snprintf(buf + len, size - len, " Description: %s\n", - subsystem->mali_core_array[i]->description); - switch(subsystem->mali_core_array[i]->state) - { - case CORE_IDLE: - len += _mali_osk_snprintf(buf + len, size - len, " State: CORE_IDLE\n"); - break; - case CORE_WORKING: - len += _mali_osk_snprintf(buf + len, size - len, " State: CORE_WORKING\n"); - break; - case CORE_WATCHDOG_TIMEOUT: - len += _mali_osk_snprintf(buf + len, size - len, " State: CORE_WATCHDOG_TIMEOUT\n"); - break; - case CORE_POLL: - len += _mali_osk_snprintf(buf + len, size - len, " State: CORE_POLL\n"); - break; - case CORE_HANG_CHECK_TIMEOUT: - len += _mali_osk_snprintf(buf + len, size - len, " State: CORE_HANG_CHECK_TIMEOUT\n"); - break; - case CORE_OFF: - len += _mali_osk_snprintf(buf + len, size - len, " State: CORE_OFF\n"); - break; - default: - len += _mali_osk_snprintf(buf + len, size - len, " State: Unknown (0x%X)\n", - subsystem->mali_core_array[i]->state); - break; - } - len += _mali_osk_snprintf(buf + len, size - len, " Current job: 0x%X\n", - (u32)(subsystem->mali_core_array[i]->current_job)); - if (subsystem->mali_core_array[i]->current_job) - { - u64 time_used_nano_seconds; - u32 time_used_micro_seconds; - u64 time_now = _mali_osk_time_get_ns(); - - time_used_nano_seconds = time_now - subsystem->mali_core_array[i]->current_job->start_time; - time_used_micro_seconds = ((u32)(time_used_nano_seconds)) / 1000; - - len += _mali_osk_snprintf(buf + len, size - len, " Current job session: 0x%X\n", - subsystem->mali_core_array[i]->current_job->session); - len += _mali_osk_snprintf(buf + len, size - len, " Current job number: %d\n", - subsystem->mali_core_array[i]->current_job->job_nr); - len += _mali_osk_snprintf(buf + len, size - len, " Current job render_time micro seconds: %d\n", - time_used_micro_seconds ); - len += _mali_osk_snprintf(buf + len, size - len, " Current job start time micro seconds: %d\n", - (u32) (subsystem->mali_core_array[i]->current_job->start_time >>10) ); - } - len += _mali_osk_snprintf(buf + len, size - len, " Core version: 0x%X\n", - subsystem->mali_core_array[i]->core_version); -#if USING_MALI_PMM - len += _mali_osk_snprintf(buf + len, size - len, " PMM id: 0x%X\n", - subsystem->mali_core_array[i]->pmm_id); - len += _mali_osk_snprintf(buf + len, size - len, " Power down requested: %s\n", - subsystem->mali_core_array[i]->pend_power_down ? "TRUE" : "FALSE"); -#endif - } - - len += _mali_osk_snprintf(buf + len, size - len, " Cores on idle list:\n"); - _MALI_OSK_LIST_FOREACHENTRY(core, tmp_core, &subsystem->renderunit_idle_head, mali_core_renderunit, list) - { - len += _mali_osk_snprintf(buf + len, size - len, " Core #%u\n", core->core_number); - } - - len += _mali_osk_snprintf(buf + len, size - len, " Cores on off list:\n"); - _MALI_OSK_LIST_FOREACHENTRY(core, tmp_core, &subsystem->renderunit_off_head, mali_core_renderunit, list) - { - len += _mali_osk_snprintf(buf + len, size - len, " Core #%u\n", core->core_number); - } - - len += _mali_osk_snprintf(buf + len, size - len, " Connected sessions:\n"); - _MALI_OSK_LIST_FOREACHENTRY(session, tmp_session, &subsystem->all_sessions_head, mali_core_session, all_sessions_list) - { - len += _mali_osk_snprintf(buf + len, size - len, - " Session 0x%X:\n", (u32)session); - len += _mali_osk_snprintf(buf + len, size - len, - " Queue depth: %u\n", mali_job_queue_size(session)); - len += _mali_osk_snprintf(buf + len, size - len, - " First waiting job: 0x%p\n", session->queue[session->queue_head]); - len += _mali_osk_snprintf(buf + len, size - len, " Notification queue: %s\n", - _mali_osk_notification_queue_is_empty(session->notification_queue) ? "EMPTY" : "NON-EMPTY"); - len += _mali_osk_snprintf(buf + len, size - len, - " Jobs received:%4d\n", _mali_osk_atomic_read(&session->jobs_received)); - len += _mali_osk_snprintf(buf + len, size - len, - " Jobs started :%4d\n", _mali_osk_atomic_read(&session->jobs_started)); - len += _mali_osk_snprintf(buf + len, size - len, - " Jobs ended :%4d\n", _mali_osk_atomic_read(&session->jobs_ended)); - len += _mali_osk_snprintf(buf + len, size - len, - " Jobs returned:%4d\n", _mali_osk_atomic_read(&session->jobs_returned)); - len += _mali_osk_snprintf(buf + len, size - len, " PID: %d\n", session->pid); - } - - len += _mali_osk_snprintf(buf + len, size - len, " Waiting sessions sum all priorities: %u\n", - subsystem->awaiting_sessions_sum_all_priorities); - for (i = 0; i < PRIORITY_LEVELS; i++) - { - len += _mali_osk_snprintf(buf + len, size - len, " Waiting sessions with priority %u:\n", i); - _MALI_OSK_LIST_FOREACHENTRY(session, tmp_session, &subsystem->awaiting_sessions_head[i], - mali_core_session, awaiting_sessions_list) - { - len += _mali_osk_snprintf(buf + len, size - len, " Session 0x%X:\n", (u32)session); - len += _mali_osk_snprintf(buf + len, size - len, " Waiting job: 0x%X\n", - (u32)session->queue[session->queue_head]); - len += _mali_osk_snprintf(buf + len, size - len, " Notification queue: %s\n", - _mali_osk_notification_queue_is_empty(session->notification_queue) ? "EMPTY" : "NON-EMPTY"); - } - } - - MALI_CORE_SUBSYSTEM_MUTEX_RELEASE( subsystem ); - return len; -} -#endif diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_rendercore.h b/drivers/media/video/samsung/mali/common/mali_kernel_rendercore.h deleted file mode 100644 index 5fbe686..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_rendercore.h +++ /dev/null @@ -1,565 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __MALI_RENDERCORE_H__ -#define __MALI_RENDERCORE_H__ - -#include "mali_osk.h" -#include "mali_kernel_common.h" -#include "mali_kernel_subsystem.h" - -#define PRIORITY_LEVELS 3 -#define PRIORITY_MAX 0 -#define PRIORITY_MIN (PRIORITY_MAX+PRIORITY_LEVELS-1) - -/* This file contains what we need in kernel for all core types. */ - -typedef enum -{ - CORE_IDLE, /**< Core is ready for a new job */ - CORE_WORKING, /**< Core is working on a job */ - CORE_WATCHDOG_TIMEOUT, /**< Core is working but it has timed out */ - CORE_POLL, /**< Poll timer triggered, pending handling */ - CORE_HANG_CHECK_TIMEOUT,/**< Timeout for hang detection */ - CORE_OFF /**< Core is powered off */ -} mali_core_status; - -typedef enum -{ - SUBSYSTEM_RESCHEDULE, - SUBSYSTEM_WAIT -} mali_subsystem_reschedule_option; - -typedef enum -{ - MALI_CORE_RESET_STYLE_RUNABLE, - MALI_CORE_RESET_STYLE_DISABLE, - MALI_CORE_RESET_STYLE_HARD -} mali_core_reset_style; - -typedef enum -{ - JOB_STATUS_CONTINUE_RUN = 0x01, - JOB_STATUS_END_SUCCESS = 1<<(16+0), - JOB_STATUS_END_OOM = 1<<(16+1), - JOB_STATUS_END_ABORT = 1<<(16+2), - JOB_STATUS_END_TIMEOUT_SW = 1<<(16+3), - JOB_STATUS_END_HANG = 1<<(16+4), - JOB_STATUS_END_SEG_FAULT = 1<<(16+5), - JOB_STATUS_END_ILLEGAL_JOB = 1<<(16+6), - JOB_STATUS_END_UNKNOWN_ERR = 1<<(16+7), - JOB_STATUS_END_SHUTDOWN = 1<<(16+8), - JOB_STATUS_END_SYSTEM_UNUSABLE = 1<<(16+9) -} mali_subsystem_job_end_code; - - -struct mali_core_job; -struct mali_core_subsystem; -struct mali_core_renderunit; -struct mali_core_session; - -/* We have one of these subsystems for each core type */ -typedef struct mali_core_subsystem -{ - struct mali_core_renderunit ** mali_core_array; /* An array of all cores of this type */ - u32 number_of_cores; /* Number of cores in this list */ - - _mali_core_type core_type; - - u32 magic_nr; - - _mali_osk_list_t renderunit_idle_head; /* Idle cores of this type */ - _mali_osk_list_t renderunit_off_head; /* Powered off cores of this type */ - - /* Linked list for each priority of sessions with a job ready for scheduelling */ - _mali_osk_list_t awaiting_sessions_head[PRIORITY_LEVELS]; - u32 awaiting_sessions_sum_all_priorities; - - /* Linked list of all sessions connected to this coretype */ - _mali_osk_list_t all_sessions_head; - - /* Linked list of all sessions connected to this coretype */ - struct _mali_osk_notification_queue_t * notification_queue; - - const char * name; - mali_kernel_subsystem_identifier id; - - /**** Functions registered for this core type. Set during mali_core_init ******/ - /* Start this job on this core. Return MALI_TRUE if the job was started. */ - _mali_osk_errcode_t (*start_job)(struct mali_core_job * job, struct mali_core_renderunit * core); - - /* Check if given core has an interrupt pending. Return MALI_TRUE and set mask to 0 if pending */ - u32 (*irq_handler_upper_half)(struct mali_core_renderunit * core); - - /* This function should check if the interrupt indicates that job was finished. - If so it should update the job-struct, reset the core registers, and return MALI_TRUE, . - If the job is still working after this function it should return MALI_FALSE. - The function must also enable the bits in the interrupt mask for the core. - Called by the bottom half interrupt function. */ - int (*irq_handler_bottom_half)(struct mali_core_renderunit* core); - - /* This function is called from the ioctl function and should return a mali_core_job pointer - to a created mali_core_job object with the data given from userspace */ - _mali_osk_errcode_t (*get_new_job_from_user)(struct mali_core_session * session, void * argument); - - _mali_osk_errcode_t (*suspend_response)(struct mali_core_session * session, void * argument); - - /* This function is called from the ioctl function and should write the necessary data - to userspace telling which job was finished and the status and debuginfo for this job. - The function must also free and cleanup the input job object. */ - void (*return_job_to_user)(struct mali_core_job * job, mali_subsystem_job_end_code end_status); - - /* Is called when a subsystem shuts down. This function needs to - release internal pointers in the core struct, and free the - core struct before returning. - It is not allowed to write to any registers, since this - unmapping is already done. */ - void (*renderunit_delete)(struct mali_core_renderunit * core); - - /* Is called when we want to abort a job that is running on the core. - This is done if program exits while core is running */ - void (*reset_core)(struct mali_core_renderunit * core, mali_core_reset_style style); - - /* Is called when the rendercore wants the core to give an interrupt */ - void (*probe_core_irq_trigger)(struct mali_core_renderunit* core); - - /* Is called when the irq probe wants the core to acknowledge an interrupt from the hw */ - _mali_osk_errcode_t (*probe_core_irq_acknowledge)(struct mali_core_renderunit* core); - - /* Called when the rendercore want to issue a bus stop request to a core */ - void (*stop_bus)(struct mali_core_renderunit* core); -} mali_core_subsystem; - - -/* Per core data. This must be embedded into each core type internal core info. */ -typedef struct mali_core_renderunit -{ - struct mali_core_subsystem * subsystem; /* The core belongs to this subsystem */ - _mali_osk_list_t list; /* Is always in subsystem->idle_list OR session->renderunits_working */ - mali_core_status state; - mali_bool error_recovery; /* Indicates if the core is waiting for external help to recover (typically the MMU) */ - mali_bool in_detach_function; - struct mali_core_job * current_job; /* Current job being processed on this core ||NULL */ - u32 magic_nr; - _mali_osk_timer_t * timer; - _mali_osk_timer_t * timer_hang_detection; - - mali_io_address registers_mapped; /* IO-mapped pointer to registers */ - u32 registers_base_addr; /* Base addres of the registers */ - u32 size; /* The size of registers_mapped */ - const char * description; /* Description of this core. */ - u32 irq_nr; /* The IRQ nr for this core */ - u32 core_version; -#if USING_MMU - u32 mmu_id; - void * mmu; /* The MMU this rendercore is behind.*/ -#endif -#if USING_MALI_PMM - mali_pmm_core_id pmm_id; /* The PMM core id */ - mali_bool pend_power_down; /* Power down is requested */ -#endif - - u32 core_number; /* 0 for first detected core of this type, 1 for second and so on */ - - _mali_osk_irq_t *irq; -} mali_core_renderunit; - - -#define MALI_JOB_QUEUE_SIZE 8 -/* Per open FILE data. */ -/* You must held subsystem->mutex before any transactions to this datatype. */ -typedef struct mali_core_session -{ - struct mali_core_subsystem * subsystem; /* The session belongs to this subsystem */ - _mali_osk_list_t renderunits_working_head; /* List of renderunits working for this session */ - struct mali_core_job *queue[MALI_JOB_QUEUE_SIZE]; /* The next job from this session to run */ - int queue_head; - int queue_tail; - int queue_size; - - _mali_osk_list_t awaiting_sessions_list; /* Linked list of sessions with jobs, for each priority */ - _mali_osk_list_t all_sessions_list; /* Linked list of all sessions on the system. */ - - _mali_osk_notification_queue_t * notification_queue; /* Messages back to Base in userspace*/ -#if USING_MMU - struct mali_session_data * mmu_session; /* The session associated with the MMU page tables for this core */ -#endif - u32 magic_nr; -#if MALI_STATE_TRACKING - _mali_osk_atomic_t jobs_received; - _mali_osk_atomic_t jobs_started; - _mali_osk_atomic_t jobs_ended; - _mali_osk_atomic_t jobs_returned; - u32 pid; -#endif -} mali_core_session; - -/* This must be embedded into a specific mali_core_job struct */ -/* use this macro to get spesific mali_core_job: container_of(ptr, type, member)*/ -typedef struct mali_core_job -{ - _mali_osk_list_t list; /* Linked list of jobs. Used by struct mali_core_session */ - struct mali_core_session *session; - u32 magic_nr; - u32 priority; - u32 watchdog_msecs; - u32 render_time_usecs ; - u64 start_time; - unsigned long watchdog_jiffies; - u32 abort_id; - u32 job_nr; - _mali_uk_start_job_flags flags; -} mali_core_job; - -MALI_STATIC_INLINE mali_bool mali_job_queue_empty(mali_core_session *session) -{ - if (0 == session->queue_size) - { - return MALI_TRUE; - } - return MALI_FALSE; -} - -MALI_STATIC_INLINE mali_bool mali_job_queue_full(mali_core_session *session) -{ - if (MALI_JOB_QUEUE_SIZE == session->queue_size) - { - return MALI_TRUE; - } - return MALI_FALSE; -} - - -MALI_STATIC_INLINE _mali_osk_errcode_t mali_job_queue_add_job(mali_core_session *session, struct mali_core_job *job) -{ - if (mali_job_queue_full(session)) - { - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - session->queue[session->queue_tail] = job; - session->queue_tail = (session->queue_tail + 1) % MALI_JOB_QUEUE_SIZE; - session->queue_size++; - - MALI_SUCCESS; -} - -MALI_STATIC_INLINE struct mali_core_job *mali_job_queue_get_job(mali_core_session *session) -{ - struct mali_core_job *job; - MALI_DEBUG_ASSERT(!mali_job_queue_empty(session)); - - job = session->queue[session->queue_head]; - - MALI_DEBUG_ASSERT_POINTER(job); - - session->queue[session->queue_head] = NULL; - session->queue_head = (session->queue_head + 1) % MALI_JOB_QUEUE_SIZE; - session->queue_size--; - - return job; -} - -MALI_STATIC_INLINE u32 mali_job_queue_size(mali_core_session *session) -{ - return (u32)(session->queue_size); -} - -MALI_STATIC_INLINE struct mali_core_job *mali_job_queue_abort_job(mali_core_session *session, u32 abort_id) -{ - int i; - int n; - struct mali_core_job *job = NULL; - - for (i = session->queue_head, n = session->queue_size; n > 0; n--, i = (i+1)%MALI_JOB_QUEUE_SIZE) - { - if (session->queue[i]->abort_id == abort_id) - { - /* Remove job from queue */ - job = session->queue[i]; - session->queue[i] = NULL; - - session->queue_size -= 1; - n--; - break; - } - } - if (NULL == job) - { - return NULL; - } - - /* Rearrange queue */ - while (n > 0) - { - int next = (i + 1) % MALI_JOB_QUEUE_SIZE; - session->queue[i] = session->queue[next]; - i = next; - n--; - } - session->queue_tail = i; - - return job; -} - - -/* - * The rendercode subsystem is included in the subsystems[] array. - */ -extern struct mali_kernel_subsystem mali_subsystem_rendercore; - -void subsystem_flush_mapped_mem_cache(void); - - -#define SUBSYSTEM_MAGIC_NR 0xdeadbeef -#define CORE_MAGIC_NR 0xcafebabe -#define SESSION_MAGIC_NR 0xbabe1234 -#define JOB_MAGIC_NR 0x0123abcd - - -#define MALI_CHECK_SUBSYSTEM(subsystem)\ - do { \ - if ( SUBSYSTEM_MAGIC_NR != subsystem->magic_nr) MALI_PRINT_ERROR(("Wrong magic number"));\ - } while (0) - -#define MALI_CHECK_CORE(CORE)\ - do { \ - if ( CORE_MAGIC_NR != CORE->magic_nr) MALI_PRINT_ERROR(("Wrong magic number"));\ -} while (0) - -#define MALI_CHECK_SESSION(SESSION)\ - do { \ - if ( SESSION_MAGIC_NR != SESSION->magic_nr) MALI_PRINT_ERROR(("Wrong magic number"));\ -} while (0) - -#define MALI_CHECK_JOB(JOB)\ - do { \ - if ( JOB_MAGIC_NR != JOB->magic_nr) MALI_PRINT_ERROR(("Wrong magic number"));\ -} while (0) - - -/* Check if job_a has higher priority than job_b */ -MALI_STATIC_INLINE int job_has_higher_priority(mali_core_job * job_a, mali_core_job * job_b) -{ - /* The lowest number has the highest priority */ - return (int) (job_a->priority < job_b->priority); -} - -MALI_STATIC_INLINE void job_priority_set(mali_core_job * job, u32 priority) -{ - if (priority > PRIORITY_MIN) job->priority = PRIORITY_MIN; - else job->priority = priority; -} - -void job_watchdog_set(mali_core_job * job, u32 watchdog_msecs); - -/* For use by const default register settings (e.g. set these after reset) */ -typedef struct register_address_and_value -{ - u32 address; - u32 value; -} register_address_and_value ; - - -/* For use by dynamic default register settings (e.g. set these after reset) */ -typedef struct register_address_and_value_list -{ - _mali_osk_list_t list; - register_address_and_value item; -} register_address_and_value_list ; - -/* Used if the user wants to set a continious block of registers */ -typedef struct register_array_user -{ - u32 entries_in_array; - u32 start_address; - void __user * reg_array; -}register_array_user; - - -#define MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys) \ - do { \ - MALI_DEBUG_PRINT(5, ("MUTEX: GRAB %s() %d on %s\n",__FUNCTION__, __LINE__, subsys->name)); \ - _mali_osk_lock_wait( rendercores_global_mutex, _MALI_OSK_LOCKMODE_RW); \ - MALI_DEBUG_PRINT(5, ("MUTEX: GRABBED %s() %d on %s\n",__FUNCTION__, __LINE__, subsys->name)); \ - if ( SUBSYSTEM_MAGIC_NR != subsys->magic_nr ) MALI_PRINT_ERROR(("Wrong magic number"));\ - rendercores_global_mutex_is_held = 1; \ - rendercores_global_mutex_owner = _mali_osk_get_tid(); \ - } while (0) ; - -#define MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys) \ - do { \ - MALI_DEBUG_PRINT(5, ("MUTEX: RELEASE %s() %d on %s\n",__FUNCTION__, __LINE__, subsys->name)); \ - rendercores_global_mutex_is_held = 0; \ - rendercores_global_mutex_owner = 0; \ - if ( SUBSYSTEM_MAGIC_NR != subsys->magic_nr ) MALI_PRINT_ERROR(("Wrong magic number"));\ - _mali_osk_lock_signal( rendercores_global_mutex, _MALI_OSK_LOCKMODE_RW); \ - MALI_DEBUG_PRINT(5, ("MUTEX: RELEASED %s() %d on %s\n",__FUNCTION__, __LINE__, subsys->name)); \ - if ( SUBSYSTEM_MAGIC_NR != subsys->magic_nr ) MALI_PRINT_ERROR(("Wrong magic number"));\ - } while (0) ; - - -#define MALI_ASSERT_MUTEX_IS_GRABBED(input_pointer)\ - do { \ - if ( 0 == rendercores_global_mutex_is_held ) MALI_PRINT_ERROR(("ASSERT MUTEX SHOULD BE GRABBED"));\ - if ( SUBSYSTEM_MAGIC_NR != input_pointer->magic_nr ) MALI_PRINT_ERROR(("Wrong magic number"));\ - if ( rendercores_global_mutex_owner != _mali_osk_get_tid() ) MALI_PRINT_ERROR(("Owner mismatch"));\ - } while (0) - -MALI_STATIC_INLINE _mali_osk_errcode_t mali_core_renderunit_register_rw_check(mali_core_renderunit *core, - u32 relative_address) -{ -#if USING_MALI_PMM - if( core->state == CORE_OFF ) - { - MALI_PRINT_ERROR(("Core is OFF during access: Core: %s Addr: 0x%04X\n", - core->description,relative_address)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } -#endif - - MALI_DEBUG_ASSERT((relative_address & 0x03) == 0); - - if (mali_benchmark) MALI_ERROR(_MALI_OSK_ERR_FAULT); - - MALI_DEBUG_CODE(if (relative_address >= core->size) - { - MALI_PRINT_ERROR(("Trying to access illegal register: 0x%04x in core: %s", - relative_address, core->description)); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - }) - - MALI_SUCCESS; -} - - -MALI_STATIC_INLINE u32 mali_core_renderunit_register_read(struct mali_core_renderunit *core, u32 relative_address) -{ - u32 read_val; - - if(_MALI_OSK_ERR_FAULT == mali_core_renderunit_register_rw_check(core, relative_address)) - return 0xDEADBEEF; - - read_val = _mali_osk_mem_ioread32(core->registers_mapped, relative_address); - - MALI_DEBUG_PRINT(6, ("Core: renderunit_register_read: Core:%s Addr:0x%04X Val:0x%08x\n", - core->description,relative_address, read_val)); - - return read_val; -} - -MALI_STATIC_INLINE void mali_core_renderunit_register_read_array(struct mali_core_renderunit *core, - u32 relative_address, - u32 * result_array, - u32 nr_of_regs) -{ - /* NOTE Do not use burst reads against the registers */ - u32 i; - - MALI_DEBUG_PRINT(6, ("Core: renderunit_register_read_array: Core:%s Addr:0x%04X Nr_regs: %u\n", - core->description,relative_address, nr_of_regs)); - - for(i=0; i<nr_of_regs; ++i) - { - result_array[i] = mali_core_renderunit_register_read(core, relative_address + i*4); - } -} - -/* - * Write to a core register, and bypass implied memory barriers. - * - * On some systems, _mali_osk_mem_iowrite32() implies a memory barrier. This - * can be a performance problem when doing many writes in sequence. - * - * When using this function, ensure proper barriers are put in palce. Most - * likely a _mali_osk_mem_barrier() is needed after all related writes are - * completed. - * - */ -MALI_STATIC_INLINE void mali_core_renderunit_register_write_relaxed(mali_core_renderunit *core, - u32 relative_address, - u32 new_val) -{ - if(_MALI_OSK_ERR_FAULT == mali_core_renderunit_register_rw_check(core, relative_address)) - return; - - MALI_DEBUG_PRINT(6, ("mali_core_renderunit_register_write_relaxed: Core:%s Addr:0x%04X Val:0x%08x\n", - core->description,relative_address, new_val)); - - _mali_osk_mem_iowrite32_relaxed(core->registers_mapped, relative_address, new_val); -} - -MALI_STATIC_INLINE void mali_core_renderunit_register_write(struct mali_core_renderunit *core, - u32 relative_address, - u32 new_val) -{ - MALI_DEBUG_PRINT(6, ("mali_core_renderunit_register_write: Core:%s Addr:0x%04X Val:0x%08x\n", - core->description,relative_address, new_val)); - - if(_MALI_OSK_ERR_FAULT == mali_core_renderunit_register_rw_check(core, relative_address)) - return; - - _mali_osk_mem_iowrite32(core->registers_mapped, relative_address, new_val); -} - -MALI_STATIC_INLINE void mali_core_renderunit_register_write_array(struct mali_core_renderunit *core, - u32 relative_address, - u32 * write_array, - u32 nr_of_regs) -{ - u32 i; - MALI_DEBUG_PRINT(6, ("Core: renderunit_register_write_array: Core:%s Addr:0x%04X Nr_regs: %u\n", - core->description,relative_address, nr_of_regs)); - - /* Do not use burst writes against the registers */ - for( i = 0; i< nr_of_regs; i++) - { - mali_core_renderunit_register_write_relaxed(core, relative_address + i*4, write_array[i]); - } -} - -_mali_osk_errcode_t mali_core_renderunit_init(struct mali_core_renderunit * core); -void mali_core_renderunit_term(struct mali_core_renderunit * core); -int mali_core_renderunit_map_registers(struct mali_core_renderunit *core); -void mali_core_renderunit_unmap_registers(struct mali_core_renderunit *core); -int mali_core_renderunit_irq_handler_add(struct mali_core_renderunit *core); -mali_core_renderunit * mali_core_renderunit_get_mali_core_nr(mali_core_subsystem *subsys, u32 mali_core_nr); - -int mali_core_subsystem_init(struct mali_core_subsystem * new_subsys); -#if USING_MMU -void mali_core_subsystem_attach_mmu(mali_core_subsystem* subsys); -#endif -int mali_core_subsystem_register_renderunit(struct mali_core_subsystem * subsys, struct mali_core_renderunit * core); -int mali_core_subsystem_system_info_fill(mali_core_subsystem* subsys, _mali_system_info* info); -void mali_core_subsystem_cleanup(struct mali_core_subsystem * subsys); -#if USING_MMU -void mali_core_subsystem_broadcast_notification(struct mali_core_subsystem * subsys, mali_core_notification_message message, u32 data); -#endif -void mali_core_session_begin(mali_core_session *session); -void mali_core_session_close(mali_core_session * session); -int mali_core_session_add_job(mali_core_session * session, mali_core_job *job, mali_core_job **job_return); -u32 mali_core_hang_check_timeout_get(void); - -_mali_osk_errcode_t mali_core_subsystem_ioctl_start_job(mali_core_session * session, void *job_data); -_mali_osk_errcode_t mali_core_subsystem_ioctl_number_of_cores_get(mali_core_session * session, u32 *number_of_cores); -_mali_osk_errcode_t mali_core_subsystem_ioctl_core_version_get(mali_core_session * session, _mali_core_version *version); -_mali_osk_errcode_t mali_core_subsystem_ioctl_suspend_response(mali_core_session * session, void* argument); -void mali_core_subsystem_ioctl_abort_job(mali_core_session * session, u32 id); - -#if USING_MALI_PMM -_mali_osk_errcode_t mali_core_subsystem_signal_power_down(mali_core_subsystem *subsys, u32 mali_core_nr, mali_bool immediate_only); -_mali_osk_errcode_t mali_core_subsystem_signal_power_up(mali_core_subsystem *subsys, u32 mali_core_nr, mali_bool queue_only); -#endif - -#if MALI_STATE_TRACKING -u32 mali_core_renderunit_dump_state(mali_core_subsystem* subsystem, char *buf, u32 size); -#endif - -#endif /* __MALI_RENDERCORE_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_subsystem.h b/drivers/media/video/samsung/mali/common/mali_kernel_subsystem.h deleted file mode 100644 index 8f05216..0000000 --- a/drivers/media/video/samsung/mali/common/mali_kernel_subsystem.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** - * @file mali_kernel_subsystem.h - */ - -#ifndef __MALI_KERNEL_SUBSYSTEM_H__ -#define __MALI_KERNEL_SUBSYSTEM_H__ - -#include "mali_osk.h" -#include "mali_uk_types.h" -#include "mali_kernel_common.h" -#include "mali_kernel_session_manager.h" - -/* typedefs of the datatypes used in the hook functions */ -typedef void * mali_kernel_subsystem_session_slot; -typedef int mali_kernel_subsystem_identifier; -typedef _mali_osk_errcode_t (*mali_kernel_resource_registrator)(_mali_osk_resource_t *); - -/** - * Broadcast notification messages - */ -typedef enum mali_core_notification_message -{ - MMU_KILL_STEP0_LOCK_SUBSYSTEM, /**< Request to lock subsystem */ - MMU_KILL_STEP1_STOP_BUS_FOR_ALL_CORES, /**< Request to stop all buses */ - MMU_KILL_STEP2_RESET_ALL_CORES_AND_ABORT_THEIR_JOBS, /**< Request kill all jobs, and not start more jobs */ - MMU_KILL_STEP3_CONTINUE_JOB_HANDLING, /**< Request to continue with new jobs on all cores */ - MMU_KILL_STEP4_UNLOCK_SUBSYSTEM /**< Request to unlock subsystem */ -} mali_core_notification_message; - -/** - * A function pointer can be NULL if the subsystem isn't interested in the event. - */ -typedef struct mali_kernel_subsystem -{ - /* subsystem control */ - _mali_osk_errcode_t (*startup)(mali_kernel_subsystem_identifier id); /**< Called during module load or system startup*/ - void (*shutdown)(mali_kernel_subsystem_identifier id); /**< Called during module unload or system shutdown */ - - /** - * Called during module load or system startup. - * Called when all subsystems have reported startup OK and all resources where successfully initialized - */ - _mali_osk_errcode_t (*load_complete)(mali_kernel_subsystem_identifier id); - - /* per subsystem handlers */ - _mali_osk_errcode_t (*system_info_fill)(_mali_system_info* info); /**< Fill info into info struct. MUST allocate memory with kmalloc, since it's kfree'd */ - - /* per session handlers */ - /** - * Informs about a new session. - * slot can be used to track per-session per-subsystem data. - * queue can be used to send events to user space. - * _mali_osk_errcode_t error return value. - */ - _mali_osk_errcode_t (*session_begin)(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot, _mali_osk_notification_queue_t * queue); - /** - * Informs that a session is ending - * slot was the same as given during session_begin - */ - void (*session_end)(struct mali_session_data * mali_session_data, mali_kernel_subsystem_session_slot * slot); - - /* Used by subsystems to send messages to each other. This is the receiving end */ - void (*broadcast_notification)(mali_core_notification_message message, u32 data); - -#if MALI_STATE_TRACKING - /** Dump the current state of the subsystem */ - u32 (*dump_state)(char *buf, u32 size); -#endif -} mali_kernel_subsystem; - -/* functions used by the subsystems to interact with the core */ -/** - * Register a resouce handler - * @param type The resoruce type to register a handler for - * @param handler Pointer to the function handling this resource - * @return _MALI_OSK_ERR_OK on success. Otherwise, a suitable _mali_osk_errcode_t error. - */ -_mali_osk_errcode_t _mali_kernel_core_register_resource_handler(_mali_osk_resource_type_t type, mali_kernel_resource_registrator handler); - -/* function used to interact with other subsystems */ -/** - * Broadcast a message - * Sends a message to all subsystems which have registered a broadcast notification handler - * @param message The message to send - * @param data Message specific extra data - */ -void _mali_kernel_core_broadcast_subsystem_message(mali_core_notification_message message, u32 data); - -#if MALI_STATE_TRACKING -/** - * Tell all subsystems to dump their current state - */ -u32 _mali_kernel_core_dump_state(char *buf, u32 size); -#endif - - -#endif /* __MALI_KERNEL_SUBSYSTEM_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_utilization.c b/drivers/media/video/samsung/mali/common/mali_kernel_utilization.c index b43b872..a374dbf 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_utilization.c +++ b/drivers/media/video/samsung/mali/common/mali_kernel_utilization.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -27,7 +27,7 @@ static _mali_osk_timer_t *utilization_timer = NULL; static mali_bool timer_running = MALI_FALSE; -static void calculate_gpu_utilization(void *arg) +static void calculate_gpu_utilization(void* arg) { u64 time_now; u64 time_period; @@ -39,7 +39,8 @@ static void calculate_gpu_utilization(void *arg) _mali_osk_lock_wait(time_data_lock, _MALI_OSK_LOCKMODE_RW); - if (accumulated_work_time == 0 && work_start_time == 0) { + if (accumulated_work_time == 0 && work_start_time == 0) + { /* Don't reschedule timer, this will be started if new work arrives */ timer_running = MALI_FALSE; @@ -55,7 +56,8 @@ static void calculate_gpu_utilization(void *arg) time_period = time_now - period_start_time; /* If we are currently busy, update working period up to now */ - if (work_start_time != 0) { + if (work_start_time != 0) + { accumulated_work_time += (time_now - work_start_time); work_start_time = time_now; } @@ -79,10 +81,13 @@ static void calculate_gpu_utilization(void *arg) * (we could do a combination, but we just use one for simplicity, * but the end result should be good enough anyway) */ - if (period_normalized > 0x00FFFFFF) { + if (period_normalized > 0x00FFFFFF) + { /* The divisor is so big that it is safe to shift it down */ period_normalized >>= 8; - } else { + } + else + { /* * The divisor is so small that we can shift up the dividend, without loosing any data. * (dividend is always smaller than the divisor) @@ -99,22 +104,25 @@ static void calculate_gpu_utilization(void *arg) _mali_osk_timer_add(utilization_timer, _mali_osk_time_mstoticks(MALI_GPU_UTILIZATION_TIMEOUT)); + mali_gpu_utilization_handler(utilization); } - - _mali_osk_errcode_t mali_utilization_init(void) { - time_data_lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ|_MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, 0 ); + time_data_lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ | + _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_UTILIZATION); + if (NULL == time_data_lock) + { return _MALI_OSK_ERR_FAULT; - + } _mali_osk_atomic_init(&num_running_cores, 0); utilization_timer = _mali_osk_timer_init(); - if (NULL == utilization_timer) { + if (NULL == utilization_timer) + { _mali_osk_lock_term(time_data_lock); return _MALI_OSK_ERR_FAULT; } @@ -125,7 +133,8 @@ _mali_osk_errcode_t mali_utilization_init(void) void mali_utilization_suspend(void) { - if (NULL != utilization_timer) { + if (NULL != utilization_timer) + { _mali_osk_timer_del(utilization_timer); timer_running = MALI_FALSE; } @@ -133,7 +142,8 @@ void mali_utilization_suspend(void) void mali_utilization_term(void) { - if (NULL != utilization_timer) { + if (NULL != utilization_timer) + { _mali_osk_timer_del(utilization_timer); timer_running = MALI_FALSE; _mali_osk_timer_term(utilization_timer); @@ -145,11 +155,10 @@ void mali_utilization_term(void) _mali_osk_lock_term(time_data_lock); } - - void mali_utilization_core_start(u64 time_now) { - if (_mali_osk_atomic_inc_return(&num_running_cores) == 1) { + if (_mali_osk_atomic_inc_return(&num_running_cores) == 1) + { /* * We went from zero cores working, to one core working, * we now consider the entire GPU for being busy @@ -167,27 +176,26 @@ void mali_utilization_core_start(u64 time_now) } work_start_time = time_now; - - if (timer_running != MALI_TRUE) { + if (timer_running != MALI_TRUE) + { timer_running = MALI_TRUE; period_start_time = work_start_time; /* starting a new period */ _mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW); - _mali_osk_timer_del(utilization_timer); - _mali_osk_timer_add(utilization_timer, _mali_osk_time_mstoticks(MALI_GPU_UTILIZATION_TIMEOUT)); - } else { + } + else + { _mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW); } } } - - void mali_utilization_core_end(u64 time_now) { - if (_mali_osk_atomic_dec_return(&num_running_cores) == 0) { + if (_mali_osk_atomic_dec_return(&num_running_cores) == 0) + { /* * No more cores are working, so accumulate the time we was busy. */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_utilization.h b/drivers/media/video/samsung/mali/common/mali_kernel_utilization.h index c779978..1f60517 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_utilization.h +++ b/drivers/media/video/samsung/mali/common/mali_kernel_utilization.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_vsync.c b/drivers/media/video/samsung/mali/common/mali_kernel_vsync.c index dc39e01..63c9f5b 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_vsync.c +++ b/drivers/media/video/samsung/mali/common/mali_kernel_vsync.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -10,39 +10,41 @@ #include "mali_kernel_common.h" #include "mali_osk.h" -#include "mali_osk_mali.h" #include "mali_ukk.h" -/*#include "mali_timestamp.h"*/ #if MALI_TIMELINE_PROFILING_ENABLED -#include "mali_kernel_profiling.h" +#include "mali_osk_profiling.h" #endif _mali_osk_errcode_t _mali_ukk_vsync_event_report(_mali_uk_vsync_event_report_s *args) { _mali_uk_vsync_event event = (_mali_uk_vsync_event)args->event; MALI_IGNORE(event); /* event is not used for release code, and that is OK */ -/* u64 ts = _mali_timestamp_get(); - */ #if MALI_TIMELINE_PROFILING_ENABLED + /* + * Manually generate user space events in kernel space. + * This saves user space from calling kernel space twice in this case. + * We just need to remember to add pid and tid manually. + */ if ( event==_MALI_UK_VSYNC_EVENT_BEGIN_WAIT) { - _mali_profiling_add_event( MALI_PROFILING_EVENT_TYPE_SUSPEND | - MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | - MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_VSYNC, - 0, 0, 0, 0, 0); + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SUSPEND | + MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | + MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_VSYNC, + _mali_osk_get_pid(), _mali_osk_get_tid(), 0, 0, 0); } - if ( event==_MALI_UK_VSYNC_EVENT_END_WAIT) + if (event==_MALI_UK_VSYNC_EVENT_END_WAIT) { - _mali_profiling_add_event( MALI_PROFILING_EVENT_TYPE_RESUME | - MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | - MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_VSYNC, - 0, 0, 0, 0, 0); + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_RESUME | + MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | + MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_VSYNC, + _mali_osk_get_pid(), _mali_osk_get_tid(), 0, 0, 0); } #endif + MALI_DEBUG_PRINT(4, ("Received VSYNC event: %d\n", event)); MALI_SUCCESS; } diff --git a/drivers/media/video/samsung/mali/common/mali_l2_cache.c b/drivers/media/video/samsung/mali/common/mali_l2_cache.c new file mode 100644 index 0000000..aa5cc54 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_l2_cache.c @@ -0,0 +1,398 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "mali_kernel_common.h" +#include "mali_osk.h" + +#include "mali_l2_cache.h" +#include "mali_hw_core.h" +#include "mali_pm.h" + +/** + * Size of the Mali L2 cache registers in bytes + */ +#define MALI400_L2_CACHE_REGISTERS_SIZE 0x30 + +#define MALI_MAX_NUMBER_OF_L2_CACHE_CORES 3 + +/** + * Mali L2 cache register numbers + * Used in the register read/write routines. + * See the hardware documentation for more information about each register + */ +typedef enum mali_l2_cache_register { + MALI400_L2_CACHE_REGISTER_STATUS = 0x0008, + /*unused = 0x000C */ + MALI400_L2_CACHE_REGISTER_COMMAND = 0x0010, /**< Misc cache commands, e.g. clear */ + MALI400_L2_CACHE_REGISTER_CLEAR_PAGE = 0x0014, + MALI400_L2_CACHE_REGISTER_MAX_READS = 0x0018, /**< Limit of outstanding read requests */ + MALI400_L2_CACHE_REGISTER_ENABLE = 0x001C, /**< Enable misc cache features */ + MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0 = 0x0020, + MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0 = 0x0024, + MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1 = 0x0028, + MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1 = 0x002C, +} mali_l2_cache_register; + +/** + * Mali L2 cache commands + * These are the commands that can be sent to the Mali L2 cache unit + */ +typedef enum mali_l2_cache_command +{ + MALI400_L2_CACHE_COMMAND_CLEAR_ALL = 0x01, /**< Clear the entire cache */ + /* Read HW TRM carefully before adding/using other commands than the clear above */ +} mali_l2_cache_command; + +/** + * Mali L2 cache commands + * These are the commands that can be sent to the Mali L2 cache unit + */ +typedef enum mali_l2_cache_enable +{ + MALI400_L2_CACHE_ENABLE_DEFAULT = 0x0, /**< Default state of enable register */ + MALI400_L2_CACHE_ENABLE_ACCESS = 0x01, /**< Permit cacheable accesses */ + MALI400_L2_CACHE_ENABLE_READ_ALLOCATE = 0x02, /**< Permit cache read allocate */ +} mali_l2_cache_enable; + +/** + * Mali L2 cache status bits + */ +typedef enum mali_l2_cache_status +{ + MALI400_L2_CACHE_STATUS_COMMAND_BUSY = 0x01, /**< Command handler of L2 cache is busy */ + MALI400_L2_CACHE_STATUS_DATA_BUSY = 0x02, /**< L2 cache is busy handling data requests */ +} mali_l2_cache_status; + +/** + * Definition of the L2 cache core struct + * Used to track a L2 cache unit in the system. + * Contains information about the mapping of the registers + */ +struct mali_l2_cache_core +{ + struct mali_hw_core hw_core; /**< Common for all HW cores */ + u32 core_id; /**< Unique core ID */ + _mali_osk_lock_t *command_lock; /**< Serialize all L2 cache commands */ + _mali_osk_lock_t *counter_lock; /**< Synchronize L2 cache counter access */ + u32 counter_src0; /**< Performance counter 0, MALI_HW_CORE_NO_COUNTER for disabled */ + u32 counter_src1; /**< Performance counter 1, MALI_HW_CORE_NO_COUNTER for disabled */ +}; + +#define MALI400_L2_MAX_READS_DEFAULT 0x1C + +static struct mali_l2_cache_core *mali_global_l2_cache_cores[MALI_MAX_NUMBER_OF_L2_CACHE_CORES]; +static u32 mali_global_num_l2_cache_cores = 0; + +int mali_l2_max_reads = MALI400_L2_MAX_READS_DEFAULT; + +/* Local helper functions */ +static _mali_osk_errcode_t mali_l2_cache_send_command(struct mali_l2_cache_core *cache, u32 reg, u32 val); + + +struct mali_l2_cache_core *mali_l2_cache_create(_mali_osk_resource_t *resource) +{ + struct mali_l2_cache_core *cache = NULL; + + MALI_DEBUG_PRINT(2, ("Mali L2 cache: Creating Mali L2 cache: %s\n", resource->description)); + + if (mali_global_num_l2_cache_cores >= MALI_MAX_NUMBER_OF_L2_CACHE_CORES) + { + MALI_PRINT_ERROR(("Mali L2 cache: Too many L2 cache core objects created\n")); + return NULL; + } + + cache = _mali_osk_malloc(sizeof(struct mali_l2_cache_core)); + if (NULL != cache) + { + cache->core_id = mali_global_num_l2_cache_cores; + cache->counter_src0 = MALI_HW_CORE_NO_COUNTER; + cache->counter_src1 = MALI_HW_CORE_NO_COUNTER; + if (_MALI_OSK_ERR_OK == mali_hw_core_create(&cache->hw_core, resource, MALI400_L2_CACHE_REGISTERS_SIZE)) + { + cache->command_lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_SPINLOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, + 0, _MALI_OSK_LOCK_ORDER_L2_COMMAND); + if (NULL != cache->command_lock) + { + cache->counter_lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_SPINLOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, + 0, _MALI_OSK_LOCK_ORDER_L2_COUNTER); + if (NULL != cache->counter_lock) + { + if (_MALI_OSK_ERR_OK == mali_l2_cache_reset(cache)) + { + mali_global_l2_cache_cores[mali_global_num_l2_cache_cores] = cache; + mali_global_num_l2_cache_cores++; + + return cache; + } + else + { + MALI_PRINT_ERROR(("Mali L2 cache: Failed to reset L2 cache core %s\n", cache->hw_core.description)); + } + + _mali_osk_lock_term(cache->counter_lock); + } + else + { + MALI_PRINT_ERROR(("Mali L2 cache: Failed to create counter lock for L2 cache core %s\n", cache->hw_core.description)); + } + + _mali_osk_lock_term(cache->command_lock); + } + else + { + MALI_PRINT_ERROR(("Mali L2 cache: Failed to create command lock for L2 cache core %s\n", cache->hw_core.description)); + } + + mali_hw_core_delete(&cache->hw_core); + } + + _mali_osk_free(cache); + } + else + { + MALI_PRINT_ERROR(("Mali L2 cache: Failed to allocate memory for L2 cache core\n")); + } + + return NULL; +} + +void mali_l2_cache_delete(struct mali_l2_cache_core *cache) +{ + u32 i; + + /* reset to defaults */ + mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_MAX_READS, (u32)MALI400_L2_MAX_READS_DEFAULT); + mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_ENABLE, (u32)MALI400_L2_CACHE_ENABLE_DEFAULT); + + _mali_osk_lock_term(cache->counter_lock); + _mali_osk_lock_term(cache->command_lock); + mali_hw_core_delete(&cache->hw_core); + + for (i = 0; i < mali_global_num_l2_cache_cores; i++) + { + if (mali_global_l2_cache_cores[i] == cache) + { + mali_global_l2_cache_cores[i] = NULL; + mali_global_num_l2_cache_cores--; + } + } + + _mali_osk_free(cache); +} + +u32 mali_l2_cache_get_id(struct mali_l2_cache_core *cache) +{ + return cache->core_id; +} + +mali_bool mali_l2_cache_core_set_counter_src0(struct mali_l2_cache_core *cache, u32 counter) +{ + u32 value = 0; /* disabled src */ + + MALI_DEBUG_ASSERT_POINTER(cache); + MALI_DEBUG_ASSERT(counter < (1 << 7)); /* the possible values are 0-127 */ + + _mali_osk_lock_wait(cache->counter_lock, _MALI_OSK_LOCKMODE_RW); + + cache->counter_src0 = counter; + + if (counter != MALI_HW_CORE_NO_COUNTER) + { + value = counter; + } + + mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0, value); + + _mali_osk_lock_signal(cache->counter_lock, _MALI_OSK_LOCKMODE_RW); + return MALI_TRUE; +} + +mali_bool mali_l2_cache_core_set_counter_src1(struct mali_l2_cache_core *cache, u32 counter) +{ + u32 value = 0; /* disabled src */ + + MALI_DEBUG_ASSERT_POINTER(cache); + MALI_DEBUG_ASSERT(counter < (1 << 7)); /* the possible values are 0-127 */ + + _mali_osk_lock_wait(cache->counter_lock, _MALI_OSK_LOCKMODE_RW); + + cache->counter_src1 = counter; + + if (counter != MALI_HW_CORE_NO_COUNTER) + { + value = counter; + } + + mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1, value); + + _mali_osk_lock_signal(cache->counter_lock, _MALI_OSK_LOCKMODE_RW); + return MALI_TRUE; +} + +u32 mali_l2_cache_core_get_counter_src0(struct mali_l2_cache_core *cache) +{ + return cache->counter_src0; +} + +u32 mali_l2_cache_core_get_counter_src1(struct mali_l2_cache_core *cache) +{ + return cache->counter_src1; +} + +void mali_l2_cache_core_get_counter_values(struct mali_l2_cache_core *cache, u32 *src0, u32 *value0, u32 *src1, u32 *value1) +{ + MALI_DEBUG_ASSERT(NULL != src0); + MALI_DEBUG_ASSERT(NULL != value0); + MALI_DEBUG_ASSERT(NULL != src1); + MALI_DEBUG_ASSERT(NULL != value1); + + /* Caller must hold the PM lock and know that we are powered on */ + + _mali_osk_lock_wait(cache->counter_lock, _MALI_OSK_LOCKMODE_RW); + + *src0 = cache->counter_src0; + *src1 = cache->counter_src1; + + if (cache->counter_src0 != MALI_HW_CORE_NO_COUNTER) + { + *value0 = mali_hw_core_register_read(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0); + } + + if (cache->counter_src0 != MALI_HW_CORE_NO_COUNTER) + { + *value1 = mali_hw_core_register_read(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1); + } + + _mali_osk_lock_signal(cache->counter_lock, _MALI_OSK_LOCKMODE_RW); +} + +struct mali_l2_cache_core *mali_l2_cache_core_get_glob_l2_core(u32 index) +{ + if (MALI_MAX_NUMBER_OF_L2_CACHE_CORES > index) + { + return mali_global_l2_cache_cores[index]; + } + + return NULL; +} + +u32 mali_l2_cache_core_get_glob_num_l2_cores(void) +{ + return mali_global_num_l2_cache_cores; +} + +u32 mali_l2_cache_core_get_max_num_l2_cores(void) +{ + return MALI_MAX_NUMBER_OF_L2_CACHE_CORES; +} + +_mali_osk_errcode_t mali_l2_cache_reset(struct mali_l2_cache_core *cache) +{ + /* Invalidate cache (just to keep it in a known state at startup) */ + mali_l2_cache_invalidate_all(cache); + + /* Enable cache */ + mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_ENABLE, (u32)MALI400_L2_CACHE_ENABLE_ACCESS | (u32)MALI400_L2_CACHE_ENABLE_READ_ALLOCATE); + mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_MAX_READS, (u32)mali_l2_max_reads); + + /* Restart any performance counters (if enabled) */ + _mali_osk_lock_wait(cache->counter_lock, _MALI_OSK_LOCKMODE_RW); + + if (cache->counter_src0 != MALI_HW_CORE_NO_COUNTER) + { + mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0, cache->counter_src0); + } + + if (cache->counter_src1 != MALI_HW_CORE_NO_COUNTER) + { + mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1, cache->counter_src1); + } + + _mali_osk_lock_signal(cache->counter_lock, _MALI_OSK_LOCKMODE_RW); + + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t mali_l2_cache_invalidate_all(struct mali_l2_cache_core *cache) +{ + return mali_l2_cache_send_command(cache, MALI400_L2_CACHE_REGISTER_COMMAND, MALI400_L2_CACHE_COMMAND_CLEAR_ALL); +} + +_mali_osk_errcode_t mali_l2_cache_invalidate_pages(struct mali_l2_cache_core *cache, u32 *pages, u32 num_pages) +{ + u32 i; + _mali_osk_errcode_t ret1, ret = _MALI_OSK_ERR_OK; + + for (i = 0; i < num_pages; i++) + { + ret1 = mali_l2_cache_send_command(cache, MALI400_L2_CACHE_REGISTER_CLEAR_PAGE, pages[i]); + if (_MALI_OSK_ERR_OK != ret1) + { + ret = ret1; + } + } + + return ret; +} + +mali_bool mali_l2_cache_lock_power_state(struct mali_l2_cache_core *cache) +{ + /* + * Take PM lock and check power state. + * Returns MALI_TRUE if module is powered on. + * Power state will not change until mali_l2_cache_unlock_power_state() is called. + */ + mali_pm_lock(); + return mali_pm_is_powered_on(); +} + +void mali_l2_cache_unlock_power_state(struct mali_l2_cache_core *cache) +{ + /* Release PM lock */ + mali_pm_unlock(); +} + +/* -------- local helper functions below -------- */ + + +static _mali_osk_errcode_t mali_l2_cache_send_command(struct mali_l2_cache_core *cache, u32 reg, u32 val) +{ + int i = 0; + const int loop_count = 100000; + + /* + * Grab lock in order to send commands to the L2 cache in a serialized fashion. + * The L2 cache will ignore commands if it is busy. + */ + _mali_osk_lock_wait(cache->command_lock, _MALI_OSK_LOCKMODE_RW); + + /* First, wait for L2 cache command handler to go idle */ + + for (i = 0; i < loop_count; i++) + { + if (!(mali_hw_core_register_read(&cache->hw_core, MALI400_L2_CACHE_REGISTER_STATUS) & (u32)MALI400_L2_CACHE_STATUS_COMMAND_BUSY)) + { + break; + } + } + + if (i == loop_count) + { + _mali_osk_lock_signal(cache->command_lock, _MALI_OSK_LOCKMODE_RW); + MALI_DEBUG_PRINT(1, ( "Mali L2 cache: aborting wait for command interface to go idle\n")); + MALI_ERROR( _MALI_OSK_ERR_FAULT ); + } + + /* then issue the command */ + mali_hw_core_register_write(&cache->hw_core, reg, val); + + _mali_osk_lock_signal(cache->command_lock, _MALI_OSK_LOCKMODE_RW); + + MALI_SUCCESS; +} diff --git a/drivers/media/video/samsung/mali/common/mali_l2_cache.h b/drivers/media/video/samsung/mali/common/mali_l2_cache.h new file mode 100644 index 0000000..5a8e4da --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_l2_cache.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MALI_KERNEL_L2_CACHE_H__ +#define __MALI_KERNEL_L2_CACHE_H__ + +#include "mali_osk.h" + +struct mali_l2_cache_core; + +_mali_osk_errcode_t mali_l2_cache_initialize(void); +void mali_l2_cache_terminate(void); + +struct mali_l2_cache_core *mali_l2_cache_create(_mali_osk_resource_t * resource); +void mali_l2_cache_delete(struct mali_l2_cache_core *cache); + +u32 mali_l2_cache_get_id(struct mali_l2_cache_core *cache); + +mali_bool mali_l2_cache_core_set_counter_src0(struct mali_l2_cache_core *cache, u32 counter); +mali_bool mali_l2_cache_core_set_counter_src1(struct mali_l2_cache_core *cache, u32 counter); +u32 mali_l2_cache_core_get_counter_src0(struct mali_l2_cache_core *cache); +u32 mali_l2_cache_core_get_counter_src1(struct mali_l2_cache_core *cache); +void mali_l2_cache_core_get_counter_values(struct mali_l2_cache_core *cache, u32 *src0, u32 *value0, u32 *src1, u32 *value1); +struct mali_l2_cache_core *mali_l2_cache_core_get_glob_l2_core(u32 index); +u32 mali_l2_cache_core_get_glob_num_l2_cores(void); +u32 mali_l2_cache_core_get_max_num_l2_cores(void); + +_mali_osk_errcode_t mali_l2_cache_reset(struct mali_l2_cache_core *cache); + +_mali_osk_errcode_t mali_l2_cache_invalidate_all(struct mali_l2_cache_core *cache); +_mali_osk_errcode_t mali_l2_cache_invalidate_pages(struct mali_l2_cache_core *cache, u32 *pages, u32 num_pages); + +mali_bool mali_l2_cache_lock_power_state(struct mali_l2_cache_core *cache); +void mali_l2_cache_unlock_power_state(struct mali_l2_cache_core *cache); + +#endif /* __MALI_KERNEL_L2_CACHE_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_mem_validation.c b/drivers/media/video/samsung/mali/common/mali_mem_validation.c new file mode 100644 index 0000000..ea9c428 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_mem_validation.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mali_mem_validation.h" +#include "mali_osk.h" +#include "mali_kernel_common.h" + +#define MALI_INVALID_MEM_ADDR 0xFFFFFFFF + +typedef struct +{ + u32 phys_base; /**< Mali physical base of the memory, page aligned */ + u32 size; /**< size in bytes of the memory, multiple of page size */ +} _mali_mem_validation_t; + +static _mali_mem_validation_t mali_mem_validator = { MALI_INVALID_MEM_ADDR, MALI_INVALID_MEM_ADDR }; + +_mali_osk_errcode_t mali_mem_validation_add_range(const _mali_osk_resource_t *resource) +{ + /* Check that no other MEM_VALIDATION resources exist */ + if (MALI_INVALID_MEM_ADDR != mali_mem_validator.phys_base) + { + MALI_PRINT_ERROR(("Failed to add MEM_VALIDATION resource %s; another range is already specified\n", resource->description)); + return _MALI_OSK_ERR_FAULT; + } + + /* Check restrictions on page alignment */ + if ((0 != (resource->base & (~_MALI_OSK_CPU_PAGE_MASK))) || + (0 != (resource->size & (~_MALI_OSK_CPU_PAGE_MASK)))) + { + MALI_PRINT_ERROR(("Failed to add MEM_VALIDATION resource %s; incorrect alignment\n", resource->description)); + return _MALI_OSK_ERR_FAULT; + } + + mali_mem_validator.phys_base = resource->base; + mali_mem_validator.size = resource->size; + MALI_DEBUG_PRINT(2, ("Memory Validator '%s' installed for Mali physical address base=0x%08X, size=0x%08X\n", + resource->description, mali_mem_validator.phys_base, mali_mem_validator.size)); + + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t mali_mem_validation_check(u32 phys_addr, u32 size) +{ + if (phys_addr < (phys_addr + size)) /* Don't allow overflow (or zero size) */ + { + if ((0 == ( phys_addr & (~_MALI_OSK_CPU_PAGE_MASK))) && + (0 == ( size & (~_MALI_OSK_CPU_PAGE_MASK)))) + { + if ((phys_addr >= mali_mem_validator.phys_base) && + ((phys_addr + (size - 1)) >= mali_mem_validator.phys_base) && + (phys_addr <= (mali_mem_validator.phys_base + (mali_mem_validator.size - 1))) && + ((phys_addr + (size - 1)) <= (mali_mem_validator.phys_base + (mali_mem_validator.size - 1))) ) + { + MALI_DEBUG_PRINT(3, ("Accepted range 0x%08X + size 0x%08X (= 0x%08X)\n", phys_addr, size, (phys_addr + size - 1))); + return _MALI_OSK_ERR_OK; + } + } + } + + MALI_PRINT_ERROR(("MALI PHYSICAL RANGE VALIDATION ERROR: The range supplied was: phys_base=0x%08X, size=0x%08X\n", phys_addr, size)); + + return _MALI_OSK_ERR_FAULT; +} diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_session_manager.h b/drivers/media/video/samsung/mali/common/mali_mem_validation.h index 8cc41d7..2043b44 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_session_manager.h +++ b/drivers/media/video/samsung/mali/common/mali_mem_validation.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -8,12 +8,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __MALI_KERNEL_SESSION_MANAGER_H__ -#define __MALI_KERNEL_SESSION_MANAGER_H__ +#ifndef __MALI_MEM_VALIDATION_H__ +#define __MALI_MEM_VALIDATION_H__ -/* Incomplete struct to pass around pointers to it */ -struct mali_session_data; +#include "mali_osk.h" -void * mali_kernel_session_manager_slot_get(struct mali_session_data * session, int id); +_mali_osk_errcode_t mali_mem_validation_add_range(const _mali_osk_resource_t * resource); +_mali_osk_errcode_t mali_mem_validation_check(u32 phys_addr, u32 size); -#endif /* __MALI_KERNEL_SESSION_MANAGER_H__ */ +#endif /* __MALI_MEM_VALIDATION_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_memory.c b/drivers/media/video/samsung/mali/common/mali_memory.c new file mode 100644 index 0000000..7a11d1a --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_memory.c @@ -0,0 +1,1321 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mali_kernel_common.h" +#include "mali_kernel_descriptor_mapping.h" +#include "mali_mem_validation.h" +#include "mali_memory.h" +#include "mali_mmu_page_directory.h" +#include "mali_kernel_memory_engine.h" +#include "mali_block_allocator.h" +#include "mali_kernel_mem_os.h" +#include "mali_session.h" +#include "mali_l2_cache.h" +#include "mali_cluster.h" +#include "mali_group.h" +#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 +#include "ump_kernel_interface.h" +#endif + +/* kernel side OS functions and user-kernel interface */ +#include "mali_osk.h" +#include "mali_osk_mali.h" +#include "mali_ukk.h" +#include "mali_osk_list.h" +#include "mali_osk_bitops.h" + +/** + * Per-session memory descriptor mapping table sizes + */ +#define MALI_MEM_DESCRIPTORS_INIT 64 +#define MALI_MEM_DESCRIPTORS_MAX 65536 + +typedef struct dedicated_memory_info +{ + u32 base; + u32 size; + struct dedicated_memory_info * next; +} dedicated_memory_info; + +/* types used for external_memory and ump_memory physical memory allocators, which are using the mali_allocation_engine */ +#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 +typedef struct ump_mem_allocation +{ + mali_allocation_engine * engine; + mali_memory_allocation * descriptor; + u32 initial_offset; + u32 size_allocated; + ump_dd_handle ump_mem; +} ump_mem_allocation ; +#endif + +typedef struct external_mem_allocation +{ + mali_allocation_engine * engine; + mali_memory_allocation * descriptor; + u32 initial_offset; + u32 size; +} external_mem_allocation; + +/** + * @brief Internal function for unmapping memory + * + * Worker function for unmapping memory from a user-process. We assume that the + * session/descriptor's lock was obtained before entry. For example, the + * wrapper _mali_ukk_mem_munmap() will lock the descriptor, then call this + * function to do the actual unmapping. mali_memory_core_session_end() could + * also call this directly (depending on compilation options), having locked + * the descriptor. + * + * This function will fail if it is unable to put the MMU in stall mode (which + * might be the case if a page fault is also being processed). + * + * @param args see _mali_uk_mem_munmap_s in "mali_utgard_uk_types.h" + * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. + */ +static _mali_osk_errcode_t _mali_ukk_mem_munmap_internal( _mali_uk_mem_munmap_s *args ); + +#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 +static void ump_memory_release(void * ctx, void * handle); +static mali_physical_memory_allocation_result ump_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info); +#endif /* MALI_USE_UNIFIED_MEMORY_PROVIDER != 0*/ + + +static void external_memory_release(void * ctx, void * handle); +static mali_physical_memory_allocation_result external_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info); + + +/* nop functions */ + +/* mali address manager needs to allocate page tables on allocate, write to page table(s) on map, write to page table(s) and release page tables on release */ +static _mali_osk_errcode_t mali_address_manager_allocate(mali_memory_allocation * descriptor); /* validates the range, allocates memory for the page tables if needed */ +static _mali_osk_errcode_t mali_address_manager_map(mali_memory_allocation * descriptor, u32 offset, u32 *phys_addr, u32 size); +static void mali_address_manager_release(mali_memory_allocation * descriptor); + +/* MMU variables */ + +typedef struct mali_mmu_page_table_allocation +{ + _mali_osk_list_t list; + u32 * usage_map; + u32 usage_count; + u32 num_pages; + mali_page_table_block pages; +} mali_mmu_page_table_allocation; + +typedef struct mali_mmu_page_table_allocations +{ + _mali_osk_lock_t *lock; + _mali_osk_list_t partial; + _mali_osk_list_t full; + /* we never hold on to a empty allocation */ +} mali_mmu_page_table_allocations; + +static mali_kernel_mem_address_manager mali_address_manager = +{ + mali_address_manager_allocate, /* allocate */ + mali_address_manager_release, /* release */ + mali_address_manager_map, /* map_physical */ + NULL /* unmap_physical not present*/ +}; + +/* the mmu page table cache */ +static struct mali_mmu_page_table_allocations page_table_cache; + + +static mali_kernel_mem_address_manager process_address_manager = +{ + _mali_osk_mem_mapregion_init, /* allocate */ + _mali_osk_mem_mapregion_term, /* release */ + _mali_osk_mem_mapregion_map, /* map_physical */ + _mali_osk_mem_mapregion_unmap /* unmap_physical */ +}; + +static _mali_osk_errcode_t mali_mmu_page_table_cache_create(void); +static void mali_mmu_page_table_cache_destroy(void); + +static mali_allocation_engine memory_engine = NULL; +static mali_physical_memory_allocator * physical_memory_allocators = NULL; + +static dedicated_memory_info * mem_region_registrations = NULL; + +/* called during module init */ +_mali_osk_errcode_t mali_memory_initialize(void) +{ + _mali_osk_errcode_t err; + + MALI_DEBUG_PRINT(2, ("Memory system initializing\n")); + + err = mali_mmu_page_table_cache_create(); + if(_MALI_OSK_ERR_OK != err) + { + MALI_ERROR(err); + } + + memory_engine = mali_allocation_engine_create(&mali_address_manager, &process_address_manager); + MALI_CHECK_NON_NULL( memory_engine, _MALI_OSK_ERR_FAULT); + + MALI_SUCCESS; +} + +/* called if/when our module is unloaded */ +void mali_memory_terminate(void) +{ + MALI_DEBUG_PRINT(2, ("Memory system terminating\n")); + + mali_mmu_page_table_cache_destroy(); + + while ( NULL != mem_region_registrations) + { + dedicated_memory_info * m; + m = mem_region_registrations; + mem_region_registrations = m->next; + _mali_osk_mem_unreqregion(m->base, m->size); + _mali_osk_free(m); + } + + while ( NULL != physical_memory_allocators) + { + mali_physical_memory_allocator * m; + m = physical_memory_allocators; + physical_memory_allocators = m->next; + m->destroy(m); + } + + if (NULL != memory_engine) + { + mali_allocation_engine_destroy(memory_engine); + memory_engine = NULL; + } +} + +_mali_osk_errcode_t mali_memory_session_begin(struct mali_session_data * session_data) +{ + MALI_DEBUG_PRINT(5, ("Memory session begin\n")); + + /* create descriptor mapping table */ + session_data->descriptor_mapping = mali_descriptor_mapping_create(MALI_MEM_DESCRIPTORS_INIT, MALI_MEM_DESCRIPTORS_MAX); + + if (NULL == session_data->descriptor_mapping) + { + MALI_ERROR(_MALI_OSK_ERR_NOMEM); + } + + session_data->memory_lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_ONELOCK + | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_MEM_SESSION); + if (NULL == session_data->memory_lock) + { + mali_descriptor_mapping_destroy(session_data->descriptor_mapping); + _mali_osk_free(session_data); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + /* Init the session's memory allocation list */ + _MALI_OSK_INIT_LIST_HEAD( &session_data->memory_head ); + + MALI_DEBUG_PRINT(5, ("MMU session begin: success\n")); + MALI_SUCCESS; +} + +static void descriptor_table_cleanup_callback(int descriptor_id, void* map_target) +{ + mali_memory_allocation * descriptor; + + descriptor = (mali_memory_allocation*)map_target; + + MALI_DEBUG_PRINT(3, ("Cleanup of descriptor %d mapping to 0x%x in descriptor table\n", descriptor_id, map_target)); + MALI_DEBUG_ASSERT(descriptor); + + mali_allocation_engine_release_memory(memory_engine, descriptor); + _mali_osk_free(descriptor); +} + +void mali_memory_session_end(struct mali_session_data *session_data) +{ + MALI_DEBUG_PRINT(3, ("MMU session end\n")); + + if (NULL == session_data) + { + MALI_DEBUG_PRINT(1, ("No session data found during session end\n")); + return; + } + +#ifndef MALI_UKK_HAS_IMPLICIT_MMAP_CLEANUP +#if _MALI_OSK_SPECIFIC_INDIRECT_MMAP +#error Indirect MMAP specified, but UKK does not have implicit MMAP cleanup. Current implementation does not handle this. +#else + { + _mali_osk_errcode_t err; + err = _MALI_OSK_ERR_BUSY; + while (err == _MALI_OSK_ERR_BUSY) + { + /* Lock the session so we can modify the memory list */ + _mali_osk_lock_wait( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW ); + err = _MALI_OSK_ERR_OK; + + /* Free all memory engine allocations */ + if (0 == _mali_osk_list_empty(&session_data->memory_head)) + { + mali_memory_allocation *descriptor; + mali_memory_allocation *temp; + _mali_uk_mem_munmap_s unmap_args; + + MALI_DEBUG_PRINT(1, ("Memory found on session usage list during session termination\n")); + + unmap_args.ctx = session_data; + + /* use the 'safe' list iterator, since freeing removes the active block from the list we're iterating */ + _MALI_OSK_LIST_FOREACHENTRY(descriptor, temp, &session_data->memory_head, mali_memory_allocation, list) + { + MALI_DEBUG_PRINT(4, ("Freeing block with mali address 0x%x size %d mapped in user space at 0x%x\n", + descriptor->mali_address, descriptor->size, descriptor->size, descriptor->mapping) + ); + /* ASSERT that the descriptor's lock references the correct thing */ + MALI_DEBUG_ASSERT( descriptor->lock == session_data->memory_lock ); + /* Therefore, we have already locked the descriptor */ + + unmap_args.size = descriptor->size; + unmap_args.mapping = descriptor->mapping; + unmap_args.cookie = (u32)descriptor; + + /* + * This removes the descriptor from the list, and frees the descriptor + * + * Does not handle the _MALI_OSK_SPECIFIC_INDIRECT_MMAP case, since + * the only OS we are aware of that requires indirect MMAP also has + * implicit mmap cleanup. + */ + err = _mali_ukk_mem_munmap_internal( &unmap_args ); + + if (err == _MALI_OSK_ERR_BUSY) + { + _mali_osk_lock_signal( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW ); + /* + * Reason for this; + * We where unable to stall the MMU, probably because we are in page fault handling. + * Sleep for a while with the session lock released, then try again. + * Abnormal termination of programs with running Mali jobs is a normal reason for this. + */ + _mali_osk_time_ubusydelay(10); + break; /* Will jump back into: "while (err == _MALI_OSK_ERR_BUSY)" */ + } + } + } + } + /* Assert that we really did free everything */ + MALI_DEBUG_ASSERT( _mali_osk_list_empty(&session_data->memory_head) ); + } +#endif /* _MALI_OSK_SPECIFIC_INDIRECT_MMAP */ +#else + /* Lock the session so we can modify the memory list */ + _mali_osk_lock_wait( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW ); +#endif /* MALI_UKK_HAS_IMPLICIT_MMAP_CLEANUP */ + + if (NULL != session_data->descriptor_mapping) + { + mali_descriptor_mapping_call_for_each(session_data->descriptor_mapping, descriptor_table_cleanup_callback); + mali_descriptor_mapping_destroy(session_data->descriptor_mapping); + session_data->descriptor_mapping = NULL; + } + + _mali_osk_lock_signal( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW ); + + /** + * @note Could the VMA close handler mean that we use the session data after it was freed? + * In which case, would need to refcount the session data, and free on VMA close + */ + + /* Free the lock */ + _mali_osk_lock_term( session_data->memory_lock ); + + return; +} + +_mali_osk_errcode_t mali_memory_core_resource_os_memory(_mali_osk_resource_t * resource) +{ + mali_physical_memory_allocator * allocator; + mali_physical_memory_allocator ** next_allocator_list; + + u32 alloc_order = resource->alloc_order; + + allocator = mali_os_allocator_create(resource->size, resource->cpu_usage_adjust, resource->description); + if (NULL == allocator) + { + MALI_DEBUG_PRINT(1, ("Failed to create OS memory allocator\n")); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + allocator->alloc_order = alloc_order; + + /* link in the allocator: insertion into ordered list + * resources of the same alloc_order will be Last-in-first */ + next_allocator_list = &physical_memory_allocators; + + while (NULL != *next_allocator_list && + (*next_allocator_list)->alloc_order < alloc_order ) + { + next_allocator_list = &((*next_allocator_list)->next); + } + + allocator->next = (*next_allocator_list); + (*next_allocator_list) = allocator; + + MALI_SUCCESS; +} + +_mali_osk_errcode_t mali_memory_core_resource_dedicated_memory(_mali_osk_resource_t * resource) +{ + mali_physical_memory_allocator * allocator; + mali_physical_memory_allocator ** next_allocator_list; + dedicated_memory_info * cleanup_data; + + u32 alloc_order = resource->alloc_order; + + /* do the low level linux operation first */ + + /* Request ownership of the memory */ + if (_MALI_OSK_ERR_OK != _mali_osk_mem_reqregion(resource->base, resource->size, resource->description)) + { + MALI_DEBUG_PRINT(1, ("Failed to request memory region %s (0x%08X - 0x%08X)\n", resource->description, resource->base, resource->base + resource->size - 1)); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + /* create generic block allocator object to handle it */ + allocator = mali_block_allocator_create(resource->base, resource->cpu_usage_adjust, resource->size, resource->description ); + + if (NULL == allocator) + { + MALI_DEBUG_PRINT(1, ("Memory bank registration failed\n")); + _mali_osk_mem_unreqregion(resource->base, resource->size); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + /* save low level cleanup info */ + allocator->alloc_order = alloc_order; + + cleanup_data = _mali_osk_malloc(sizeof(dedicated_memory_info)); + + if (NULL == cleanup_data) + { + _mali_osk_mem_unreqregion(resource->base, resource->size); + allocator->destroy(allocator); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + cleanup_data->base = resource->base; + cleanup_data->size = resource->size; + + cleanup_data->next = mem_region_registrations; + mem_region_registrations = cleanup_data; + + /* link in the allocator: insertion into ordered list + * resources of the same alloc_order will be Last-in-first */ + next_allocator_list = &physical_memory_allocators; + + while ( NULL != *next_allocator_list && + (*next_allocator_list)->alloc_order < alloc_order ) + { + next_allocator_list = &((*next_allocator_list)->next); + } + + allocator->next = (*next_allocator_list); + (*next_allocator_list) = allocator; + + MALI_SUCCESS; +} + +#if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 +static mali_physical_memory_allocation_result ump_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info) +{ + ump_dd_handle ump_mem; + u32 nr_blocks; + u32 i; + ump_dd_physical_block * ump_blocks; + ump_mem_allocation *ret_allocation; + + MALI_DEBUG_ASSERT_POINTER(ctx); + MALI_DEBUG_ASSERT_POINTER(engine); + MALI_DEBUG_ASSERT_POINTER(descriptor); + MALI_DEBUG_ASSERT_POINTER(alloc_info); + + ret_allocation = _mali_osk_malloc( sizeof( ump_mem_allocation ) ); + if ( NULL==ret_allocation ) return MALI_MEM_ALLOC_INTERNAL_FAILURE; + + ump_mem = (ump_dd_handle)ctx; + + MALI_DEBUG_PRINT(4, ("In ump_memory_commit\n")); + + nr_blocks = ump_dd_phys_block_count_get(ump_mem); + + MALI_DEBUG_PRINT(4, ("Have %d blocks\n", nr_blocks)); + + if (nr_blocks == 0) + { + MALI_DEBUG_PRINT(1, ("No block count\n")); + _mali_osk_free( ret_allocation ); + return MALI_MEM_ALLOC_INTERNAL_FAILURE; + } + + ump_blocks = _mali_osk_malloc(sizeof(*ump_blocks)*nr_blocks ); + if ( NULL==ump_blocks ) + { + _mali_osk_free( ret_allocation ); + return MALI_MEM_ALLOC_INTERNAL_FAILURE; + } + + if (UMP_DD_INVALID == ump_dd_phys_blocks_get(ump_mem, ump_blocks, nr_blocks)) + { + _mali_osk_free(ump_blocks); + _mali_osk_free( ret_allocation ); + return MALI_MEM_ALLOC_INTERNAL_FAILURE; + } + + /* Store away the initial offset for unmapping purposes */ + ret_allocation->initial_offset = *offset; + + for(i=0; i<nr_blocks; ++i) + { + MALI_DEBUG_PRINT(4, ("Mapping in 0x%08x size %d\n", ump_blocks[i].addr , ump_blocks[i].size)); + if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, ump_blocks[i].addr , 0, ump_blocks[i].size )) + { + u32 size_allocated = *offset - ret_allocation->initial_offset; + MALI_DEBUG_PRINT(1, ("Mapping of external memory failed\n")); + + /* unmap all previous blocks (if any) */ + mali_allocation_engine_unmap_physical(engine, descriptor, ret_allocation->initial_offset, size_allocated, (_mali_osk_mem_mapregion_flags_t)0 ); + + _mali_osk_free(ump_blocks); + _mali_osk_free(ret_allocation); + return MALI_MEM_ALLOC_INTERNAL_FAILURE; + } + *offset += ump_blocks[i].size; + } + + if (descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE) + { + /* Map in an extra virtual guard page at the end of the VMA */ + MALI_DEBUG_PRINT(4, ("Mapping in extra guard page\n")); + if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, ump_blocks[0].addr , 0, _MALI_OSK_MALI_PAGE_SIZE )) + { + u32 size_allocated = *offset - ret_allocation->initial_offset; + MALI_DEBUG_PRINT(1, ("Mapping of external memory (guard page) failed\n")); + + /* unmap all previous blocks (if any) */ + mali_allocation_engine_unmap_physical(engine, descriptor, ret_allocation->initial_offset, size_allocated, (_mali_osk_mem_mapregion_flags_t)0 ); + + _mali_osk_free(ump_blocks); + _mali_osk_free(ret_allocation); + return MALI_MEM_ALLOC_INTERNAL_FAILURE; + } + *offset += _MALI_OSK_MALI_PAGE_SIZE; + } + + _mali_osk_free( ump_blocks ); + + ret_allocation->engine = engine; + ret_allocation->descriptor = descriptor; + ret_allocation->ump_mem = ump_mem; + ret_allocation->size_allocated = *offset - ret_allocation->initial_offset; + + alloc_info->ctx = NULL; + alloc_info->handle = ret_allocation; + alloc_info->next = NULL; + alloc_info->release = ump_memory_release; + + return MALI_MEM_ALLOC_FINISHED; +} + +static void ump_memory_release(void * ctx, void * handle) +{ + ump_dd_handle ump_mem; + ump_mem_allocation *allocation; + + allocation = (ump_mem_allocation *)handle; + + MALI_DEBUG_ASSERT_POINTER( allocation ); + + ump_mem = allocation->ump_mem; + + MALI_DEBUG_ASSERT(UMP_DD_HANDLE_INVALID!=ump_mem); + + /* At present, this is a no-op. But, it allows the mali_address_manager to + * do unmapping of a subrange in future. */ + mali_allocation_engine_unmap_physical( allocation->engine, + allocation->descriptor, + allocation->initial_offset, + allocation->size_allocated, + (_mali_osk_mem_mapregion_flags_t)0 + ); + _mali_osk_free( allocation ); + + + ump_dd_reference_release(ump_mem) ; + return; +} + +_mali_osk_errcode_t _mali_ukk_attach_ump_mem( _mali_uk_attach_ump_mem_s *args ) +{ + ump_dd_handle ump_mem; + mali_physical_memory_allocator external_memory_allocator; + struct mali_session_data *session_data; + mali_memory_allocation * descriptor; + int md; + + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + + session_data = (struct mali_session_data *)args->ctx; + MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); + + /* check arguments */ + /* NULL might be a valid Mali address */ + if ( ! args->size) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); + + /* size must be a multiple of the system page size */ + if ( args->size % _MALI_OSK_MALI_PAGE_SIZE ) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); + + MALI_DEBUG_PRINT(3, + ("Requested to map ump memory with secure id %d into virtual memory 0x%08X, size 0x%08X\n", + args->secure_id, args->mali_address, args->size)); + + ump_mem = ump_dd_handle_create_from_secure_id( (int)args->secure_id ) ; + + if ( UMP_DD_HANDLE_INVALID==ump_mem ) MALI_ERROR(_MALI_OSK_ERR_FAULT); + + descriptor = _mali_osk_calloc(1, sizeof(mali_memory_allocation)); + if (NULL == descriptor) + { + ump_dd_reference_release(ump_mem); + MALI_ERROR(_MALI_OSK_ERR_NOMEM); + } + + descriptor->size = args->size; + descriptor->mapping = NULL; + descriptor->mali_address = args->mali_address; + descriptor->mali_addr_mapping_info = (void*)session_data; + descriptor->process_addr_mapping_info = NULL; /* do not map to process address space */ + descriptor->lock = session_data->memory_lock; + if (args->flags & _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE) + { + descriptor->flags = MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE; + } + _mali_osk_list_init( &descriptor->list ); + + if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session_data->descriptor_mapping, descriptor, &md)) + { + ump_dd_reference_release(ump_mem); + _mali_osk_free(descriptor); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + external_memory_allocator.allocate = ump_memory_commit; + external_memory_allocator.allocate_page_table_block = NULL; + external_memory_allocator.ctx = ump_mem; + external_memory_allocator.name = "UMP Memory"; + external_memory_allocator.next = NULL; + + _mali_osk_lock_wait(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW); + + if (_MALI_OSK_ERR_OK != mali_allocation_engine_allocate_memory(memory_engine, descriptor, &external_memory_allocator, NULL)) + { + _mali_osk_lock_signal(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW); + mali_descriptor_mapping_free(session_data->descriptor_mapping, md); + ump_dd_reference_release(ump_mem); + _mali_osk_free(descriptor); + MALI_ERROR(_MALI_OSK_ERR_NOMEM); + } + + _mali_osk_lock_signal(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW); + + args->cookie = md; + + MALI_DEBUG_PRINT(5,("Returning from UMP attach\n")); + + /* All OK */ + MALI_SUCCESS; +} + + +_mali_osk_errcode_t _mali_ukk_release_ump_mem( _mali_uk_release_ump_mem_s *args ) +{ + mali_memory_allocation * descriptor; + struct mali_session_data *session_data; + + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + + session_data = (struct mali_session_data *)args->ctx; + MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); + + if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_get(session_data->descriptor_mapping, args->cookie, (void**)&descriptor)) + { + MALI_DEBUG_PRINT(1, ("Invalid memory descriptor %d used to release ump memory\n", args->cookie)); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + descriptor = mali_descriptor_mapping_free(session_data->descriptor_mapping, args->cookie); + + if (NULL != descriptor) + { + _mali_osk_lock_wait( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW ); + + mali_allocation_engine_release_memory(memory_engine, descriptor); + + _mali_osk_lock_signal( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW ); + + _mali_osk_free(descriptor); + } + + MALI_SUCCESS; + +} +#endif /* MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 */ + + +static mali_physical_memory_allocation_result external_memory_commit(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info) +{ + u32 * data; + external_mem_allocation * ret_allocation; + + MALI_DEBUG_ASSERT_POINTER(ctx); + MALI_DEBUG_ASSERT_POINTER(engine); + MALI_DEBUG_ASSERT_POINTER(descriptor); + MALI_DEBUG_ASSERT_POINTER(alloc_info); + + ret_allocation = _mali_osk_malloc( sizeof(external_mem_allocation) ); + + if ( NULL == ret_allocation ) + { + return MALI_MEM_ALLOC_INTERNAL_FAILURE; + } + + data = (u32*)ctx; + + ret_allocation->engine = engine; + ret_allocation->descriptor = descriptor; + ret_allocation->initial_offset = *offset; + + alloc_info->ctx = NULL; + alloc_info->handle = ret_allocation; + alloc_info->next = NULL; + alloc_info->release = external_memory_release; + + MALI_DEBUG_PRINT(5, ("External map: mapping phys 0x%08X at mali virtual address 0x%08X staring at offset 0x%08X length 0x%08X\n", data[0], descriptor->mali_address, *offset, data[1])); + + if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, data[0], 0, data[1])) + { + MALI_DEBUG_PRINT(1, ("Mapping of external memory failed\n")); + _mali_osk_free(ret_allocation); + return MALI_MEM_ALLOC_INTERNAL_FAILURE; + } + *offset += data[1]; + + if (descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE) + { + /* Map in an extra virtual guard page at the end of the VMA */ + MALI_DEBUG_PRINT(4, ("Mapping in extra guard page\n")); + if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, data[0], 0, _MALI_OSK_MALI_PAGE_SIZE)) + { + u32 size_allocated = *offset - ret_allocation->initial_offset; + MALI_DEBUG_PRINT(1, ("Mapping of external memory (guard page) failed\n")); + + /* unmap what we previously mapped */ + mali_allocation_engine_unmap_physical(engine, descriptor, ret_allocation->initial_offset, size_allocated, (_mali_osk_mem_mapregion_flags_t)0 ); + _mali_osk_free(ret_allocation); + return MALI_MEM_ALLOC_INTERNAL_FAILURE; + } + *offset += _MALI_OSK_MALI_PAGE_SIZE; + } + + ret_allocation->size = *offset - ret_allocation->initial_offset; + + return MALI_MEM_ALLOC_FINISHED; +} + +static void external_memory_release(void * ctx, void * handle) +{ + external_mem_allocation * allocation; + + allocation = (external_mem_allocation *) handle; + MALI_DEBUG_ASSERT_POINTER( allocation ); + + /* At present, this is a no-op. But, it allows the mali_address_manager to + * do unmapping of a subrange in future. */ + + mali_allocation_engine_unmap_physical( allocation->engine, + allocation->descriptor, + allocation->initial_offset, + allocation->size, + (_mali_osk_mem_mapregion_flags_t)0 + ); + + _mali_osk_free( allocation ); + + return; +} + +_mali_osk_errcode_t _mali_ukk_map_external_mem( _mali_uk_map_external_mem_s *args ) +{ + mali_physical_memory_allocator external_memory_allocator; + struct mali_session_data *session_data; + u32 info[2]; + mali_memory_allocation * descriptor; + int md; + + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + + session_data = (struct mali_session_data *)args->ctx; + MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); + + external_memory_allocator.allocate = external_memory_commit; + external_memory_allocator.allocate_page_table_block = NULL; + external_memory_allocator.ctx = &info[0]; + external_memory_allocator.name = "External Memory"; + external_memory_allocator.next = NULL; + + /* check arguments */ + /* NULL might be a valid Mali address */ + if ( ! args->size) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); + + /* size must be a multiple of the system page size */ + if ( args->size % _MALI_OSK_MALI_PAGE_SIZE ) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); + + MALI_DEBUG_PRINT(3, + ("Requested to map physical memory 0x%x-0x%x into virtual memory 0x%x\n", + (void*)args->phys_addr, + (void*)(args->phys_addr + args->size -1), + (void*)args->mali_address) + ); + + /* Validate the mali physical range */ + if (_MALI_OSK_ERR_OK != mali_mem_validation_check(args->phys_addr, args->size)) + { + return _MALI_OSK_ERR_FAULT; + } + + info[0] = args->phys_addr; + info[1] = args->size; + + descriptor = _mali_osk_calloc(1, sizeof(mali_memory_allocation)); + if (NULL == descriptor) MALI_ERROR(_MALI_OSK_ERR_NOMEM); + + descriptor->size = args->size; + descriptor->mapping = NULL; + descriptor->mali_address = args->mali_address; + descriptor->mali_addr_mapping_info = (void*)session_data; + descriptor->process_addr_mapping_info = NULL; /* do not map to process address space */ + descriptor->lock = session_data->memory_lock; + if (args->flags & _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE) + { + descriptor->flags = MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE; + } + _mali_osk_list_init( &descriptor->list ); + + _mali_osk_lock_wait(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW); + + if (_MALI_OSK_ERR_OK != mali_allocation_engine_allocate_memory(memory_engine, descriptor, &external_memory_allocator, NULL)) + { + _mali_osk_lock_signal(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW); + _mali_osk_free(descriptor); + MALI_ERROR(_MALI_OSK_ERR_NOMEM); + } + + _mali_osk_lock_signal(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW); + + if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session_data->descriptor_mapping, descriptor, &md)) + { + mali_allocation_engine_release_memory(memory_engine, descriptor); + _mali_osk_free(descriptor); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + args->cookie = md; + + MALI_DEBUG_PRINT(5,("Returning from range_map_external_memory\n")); + + /* All OK */ + MALI_SUCCESS; +} + + +_mali_osk_errcode_t _mali_ukk_unmap_external_mem( _mali_uk_unmap_external_mem_s *args ) +{ + mali_memory_allocation * descriptor; + void* old_value; + struct mali_session_data *session_data; + + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + + session_data = (struct mali_session_data *)args->ctx; + MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_INVALID_ARGS); + + if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_get(session_data->descriptor_mapping, args->cookie, (void**)&descriptor)) + { + MALI_DEBUG_PRINT(1, ("Invalid memory descriptor %d used to unmap external memory\n", args->cookie)); + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } + + old_value = mali_descriptor_mapping_free(session_data->descriptor_mapping, args->cookie); + + if (NULL != old_value) + { + _mali_osk_lock_wait( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW ); + + mali_allocation_engine_release_memory(memory_engine, descriptor); + + _mali_osk_lock_signal( session_data->memory_lock, _MALI_OSK_LOCKMODE_RW ); + + _mali_osk_free(descriptor); + } + + MALI_SUCCESS; +} + +_mali_osk_errcode_t _mali_ukk_init_mem( _mali_uk_init_mem_s *args ) +{ + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + + args->memory_size = 2 * 1024 * 1024 * 1024UL; /* 2GB address space */ + args->mali_address_base = 1 * 1024 * 1024 * 1024UL; /* staring at 1GB, causing this layout: (0-1GB unused)(1GB-3G usage by Mali)(3G-4G unused) */ + MALI_SUCCESS; +} + +_mali_osk_errcode_t _mali_ukk_term_mem( _mali_uk_term_mem_s *args ) +{ + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + MALI_SUCCESS; +} + +static _mali_osk_errcode_t mali_address_manager_allocate(mali_memory_allocation * descriptor) +{ + struct mali_session_data *session_data; + u32 actual_size; + + MALI_DEBUG_ASSERT_POINTER(descriptor); + + session_data = (struct mali_session_data *)descriptor->mali_addr_mapping_info; + + actual_size = descriptor->size; + + if (descriptor->flags & MALI_MEMORY_ALLOCATION_FLAG_MAP_GUARD_PAGE) + { + actual_size += _MALI_OSK_MALI_PAGE_SIZE; + } + + return mali_mmu_pagedir_map(session_data->page_directory, descriptor->mali_address, actual_size); +} + +static void mali_address_manager_release(mali_memory_allocation * descriptor) +{ + const u32 illegal_mali_address = 0xffffffff; + struct mali_session_data *session_data; + MALI_DEBUG_ASSERT_POINTER(descriptor); + + /* It is allowed to call this function several times on the same descriptor. + When memory is released we set the illegal_mali_address so we can early out here. */ + if ( illegal_mali_address == descriptor->mali_address) return; + + session_data = (struct mali_session_data *)descriptor->mali_addr_mapping_info; + mali_mmu_pagedir_unmap(session_data->page_directory, descriptor->mali_address, descriptor->size); + + descriptor->mali_address = illegal_mali_address ; +} + +static _mali_osk_errcode_t mali_address_manager_map(mali_memory_allocation * descriptor, u32 offset, u32 *phys_addr, u32 size) +{ + struct mali_session_data *session_data; + u32 mali_address; + + MALI_DEBUG_ASSERT_POINTER(descriptor); + MALI_DEBUG_ASSERT_POINTER(phys_addr); + + session_data = (struct mali_session_data *)descriptor->mali_addr_mapping_info; + MALI_DEBUG_ASSERT_POINTER(session_data); + + mali_address = descriptor->mali_address + offset; + + MALI_DEBUG_PRINT(7, ("Mali map: mapping 0x%08X to Mali address 0x%08X length 0x%08X\n", *phys_addr, mali_address, size)); + + mali_mmu_pagedir_update(session_data->page_directory, mali_address, *phys_addr, size); + + MALI_SUCCESS; +} + +/* This handler registered to mali_mmap for MMU builds */ +_mali_osk_errcode_t _mali_ukk_mem_mmap( _mali_uk_mem_mmap_s *args ) +{ + struct mali_session_data *session_data; + mali_memory_allocation * descriptor; + + /* validate input */ + if (NULL == args) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: args was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); } + + /* Unpack arguments */ + session_data = (struct mali_session_data *)args->ctx; + + /* validate input */ + if (NULL == session_data) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: session data was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_FAULT); } + + descriptor = (mali_memory_allocation*) _mali_osk_calloc( 1, sizeof(mali_memory_allocation) ); + if (NULL == descriptor) { MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: descriptor was NULL\n")); MALI_ERROR(_MALI_OSK_ERR_NOMEM); } + + descriptor->size = args->size; + descriptor->mali_address = args->phys_addr; + descriptor->mali_addr_mapping_info = (void*)session_data; + + descriptor->process_addr_mapping_info = args->ukk_private; /* save to be used during physical manager callback */ + descriptor->flags = MALI_MEMORY_ALLOCATION_FLAG_MAP_INTO_USERSPACE; + descriptor->lock = session_data->memory_lock; + _mali_osk_list_init( &descriptor->list ); + + _mali_osk_lock_wait(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW); + + if (0 == mali_allocation_engine_allocate_memory(memory_engine, descriptor, physical_memory_allocators, &session_data->memory_head)) + { + /* We do not FLUSH nor TLB_ZAP on MMAP, since we do both of those on job start*/ + _mali_osk_lock_signal(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW); + + args->mapping = descriptor->mapping; + args->cookie = (u32)descriptor; + + MALI_DEBUG_PRINT(7, ("MMAP OK\n")); + MALI_SUCCESS; + } + else + { + _mali_osk_lock_signal(session_data->memory_lock, _MALI_OSK_LOCKMODE_RW); + /* OOM, but not a fatal error */ + MALI_DEBUG_PRINT(4, ("Memory allocation failure, OOM\n")); + _mali_osk_free(descriptor); + /* Linux will free the CPU address allocation, userspace client the Mali address allocation */ + MALI_ERROR(_MALI_OSK_ERR_FAULT); + } +} + +static _mali_osk_errcode_t _mali_ukk_mem_munmap_internal( _mali_uk_mem_munmap_s *args ) +{ + struct mali_session_data *session_data; + mali_memory_allocation * descriptor; + + u32 num_groups = mali_group_get_glob_num_groups(); + struct mali_group *group; + u32 i; + + descriptor = (mali_memory_allocation *)args->cookie; + MALI_DEBUG_ASSERT_POINTER(descriptor); + + /** @note args->context unused; we use the memory_session from the cookie */ + /* args->mapping and args->size are also discarded. They are only necessary + for certain do_munmap implementations. However, they could be used to check the + descriptor at this point. */ + + session_data = (struct mali_session_data *)descriptor->mali_addr_mapping_info; + MALI_DEBUG_ASSERT_POINTER(session_data); + + /* Unmapping the memory from the mali virtual address space. + It is allowed to call this function severeal times, which might happen if zapping below fails. */ + mali_allocation_engine_release_pt1_mali_pagetables_unmap(memory_engine, descriptor); + +#ifdef MALI_UNMAP_FLUSH_ALL_MALI_L2 + { + u32 number_of_clusters = mali_cluster_get_glob_num_clusters(); + for (i = 0; i < number_of_clusters; i++) + { + struct mali_cluster *cluster; + cluster = mali_cluster_get_global_cluster(i); + if( mali_cluster_power_is_enabled_get(cluster) ) + { + mali_cluster_l2_cache_invalidate_all_force(cluster); + } + } + } +#endif + + for (i = 0; i < num_groups; i++) + { + group = mali_group_get_glob_group(i); + mali_group_lock(group); + mali_group_remove_session_if_unused(group, session_data); + if (mali_group_get_session(group) == session_data) + { + /* The Zap also does the stall and disable_stall */ + mali_bool zap_success = mali_mmu_zap_tlb(mali_group_get_mmu(group)); + if (MALI_TRUE != zap_success) + { + MALI_DEBUG_PRINT(2, ("Mali memory unmap failed. Doing pagefault handling.\n")); + mali_group_bottom_half(group, GROUP_EVENT_MMU_PAGE_FAULT); + /* The bottom half will also do the unlock */ + continue; + } + } + mali_group_unlock(group); + } + + /* Removes the descriptor from the session's memory list, releases physical memory, releases descriptor */ + mali_allocation_engine_release_pt2_physical_memory_free(memory_engine, descriptor); + + _mali_osk_free(descriptor); + + return _MALI_OSK_ERR_OK; +} + +/* Handler for unmapping memory for MMU builds */ +_mali_osk_errcode_t _mali_ukk_mem_munmap( _mali_uk_mem_munmap_s *args ) +{ + mali_memory_allocation * descriptor; + _mali_osk_lock_t *descriptor_lock; + _mali_osk_errcode_t err; + + descriptor = (mali_memory_allocation *)args->cookie; + MALI_DEBUG_ASSERT_POINTER(descriptor); + + /** @note args->context unused; we use the memory_session from the cookie */ + /* args->mapping and args->size are also discarded. They are only necessary + for certain do_munmap implementations. However, they could be used to check the + descriptor at this point. */ + + MALI_DEBUG_ASSERT_POINTER((struct mali_session_data *)descriptor->mali_addr_mapping_info); + + descriptor_lock = descriptor->lock; /* should point to the session data lock... */ + + err = _MALI_OSK_ERR_BUSY; + while (err == _MALI_OSK_ERR_BUSY) + { + if (descriptor_lock) + { + _mali_osk_lock_wait( descriptor_lock, _MALI_OSK_LOCKMODE_RW ); + } + + err = _mali_ukk_mem_munmap_internal( args ); + + if (descriptor_lock) + { + _mali_osk_lock_signal( descriptor_lock, _MALI_OSK_LOCKMODE_RW ); + } + + if (err == _MALI_OSK_ERR_BUSY) + { + /* + * Reason for this; + * We where unable to stall the MMU, probably because we are in page fault handling. + * Sleep for a while with the session lock released, then try again. + * Abnormal termination of programs with running Mali jobs is a normal reason for this. + */ + _mali_osk_time_ubusydelay(10); + } + } + + return err; +} + +u32 _mali_ukk_report_memory_usage(void) +{ + return mali_allocation_engine_memory_usage(physical_memory_allocators); +} + +_mali_osk_errcode_t mali_mmu_get_table_page(u32 *table_page, mali_io_address *mapping) +{ + _mali_osk_lock_wait(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); + + if (0 == _mali_osk_list_empty(&page_table_cache.partial)) + { + mali_mmu_page_table_allocation * alloc = _MALI_OSK_LIST_ENTRY(page_table_cache.partial.next, mali_mmu_page_table_allocation, list); + int page_number = _mali_osk_find_first_zero_bit(alloc->usage_map, alloc->num_pages); + MALI_DEBUG_PRINT(6, ("Partial page table allocation found, using page offset %d\n", page_number)); + _mali_osk_set_nonatomic_bit(page_number, alloc->usage_map); + alloc->usage_count++; + if (alloc->num_pages == alloc->usage_count) + { + /* full, move alloc to full list*/ + _mali_osk_list_move(&alloc->list, &page_table_cache.full); + } + _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); + + *table_page = (MALI_MMU_PAGE_SIZE * page_number) + alloc->pages.phys_base; + *mapping = (mali_io_address)((MALI_MMU_PAGE_SIZE * page_number) + (u32)alloc->pages.mapping); + MALI_DEBUG_PRINT(4, ("Page table allocated for VA=0x%08X, MaliPA=0x%08X\n", *mapping, *table_page )); + MALI_SUCCESS; + } + else + { + mali_mmu_page_table_allocation * alloc; + /* no free pages, allocate a new one */ + + alloc = (mali_mmu_page_table_allocation *)_mali_osk_calloc(1, sizeof(mali_mmu_page_table_allocation)); + if (NULL == alloc) + { + _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); + *table_page = MALI_INVALID_PAGE; + MALI_ERROR(_MALI_OSK_ERR_NOMEM); + } + + _MALI_OSK_INIT_LIST_HEAD(&alloc->list); + + if (_MALI_OSK_ERR_OK != mali_allocation_engine_allocate_page_tables(memory_engine, &alloc->pages, physical_memory_allocators)) + { + MALI_DEBUG_PRINT(1, ("No more memory for page tables\n")); + _mali_osk_free(alloc); + _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); + *table_page = MALI_INVALID_PAGE; + *mapping = NULL; + MALI_ERROR(_MALI_OSK_ERR_NOMEM); + } + + /* create the usage map */ + alloc->num_pages = alloc->pages.size / MALI_MMU_PAGE_SIZE; + alloc->usage_count = 1; + MALI_DEBUG_PRINT(3, ("New page table cache expansion, %d pages in new cache allocation\n", alloc->num_pages)); + alloc->usage_map = _mali_osk_calloc(1, ((alloc->num_pages + BITS_PER_LONG - 1) & ~(BITS_PER_LONG-1) / BITS_PER_LONG) * sizeof(unsigned long)); + if (NULL == alloc->usage_map) + { + MALI_DEBUG_PRINT(1, ("Failed to allocate memory to describe MMU page table cache usage\n")); + alloc->pages.release(&alloc->pages); + _mali_osk_free(alloc); + _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); + *table_page = MALI_INVALID_PAGE; + *mapping = NULL; + MALI_ERROR(_MALI_OSK_ERR_NOMEM); + } + + _mali_osk_set_nonatomic_bit(0, alloc->usage_map); + + if (alloc->num_pages > 1) + { + _mali_osk_list_add(&alloc->list, &page_table_cache.partial); + } + else + { + _mali_osk_list_add(&alloc->list, &page_table_cache.full); + } + + _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); + *table_page = alloc->pages.phys_base; /* return the first page */ + *mapping = alloc->pages.mapping; /* Mapping for first page */ + MALI_DEBUG_PRINT(4, ("Page table allocated: VA=0x%08X, MaliPA=0x%08X\n", *mapping, *table_page )); + MALI_SUCCESS; + } +} + +void mali_mmu_release_table_page(u32 pa) +{ + mali_mmu_page_table_allocation * alloc, * temp_alloc; + + MALI_DEBUG_PRINT_IF(1, pa & 4095, ("Bad page address 0x%x given to mali_mmu_release_table_page\n", (void*)pa)); + + MALI_DEBUG_PRINT(4, ("Releasing table page 0x%08X to the cache\n", pa)); + + _mali_osk_lock_wait(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); + + /* find the entry this address belongs to */ + /* first check the partial list */ + _MALI_OSK_LIST_FOREACHENTRY(alloc, temp_alloc, &page_table_cache.partial, mali_mmu_page_table_allocation, list) + { + u32 start = alloc->pages.phys_base; + u32 last = start + (alloc->num_pages - 1) * MALI_MMU_PAGE_SIZE; + if (pa >= start && pa <= last) + { + MALI_DEBUG_ASSERT(0 != _mali_osk_test_bit((pa - start)/MALI_MMU_PAGE_SIZE, alloc->usage_map)); + _mali_osk_clear_nonatomic_bit((pa - start)/MALI_MMU_PAGE_SIZE, alloc->usage_map); + alloc->usage_count--; + + _mali_osk_memset((void*)( ((u32)alloc->pages.mapping) + (pa - start) ), 0, MALI_MMU_PAGE_SIZE); + + if (0 == alloc->usage_count) + { + /* empty, release whole page alloc */ + _mali_osk_list_del(&alloc->list); + alloc->pages.release(&alloc->pages); + _mali_osk_free(alloc->usage_map); + _mali_osk_free(alloc); + } + _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); + MALI_DEBUG_PRINT(4, ("(partial list)Released table page 0x%08X to the cache\n", pa)); + return; + } + } + + /* the check the full list */ + _MALI_OSK_LIST_FOREACHENTRY(alloc, temp_alloc, &page_table_cache.full, mali_mmu_page_table_allocation, list) + { + u32 start = alloc->pages.phys_base; + u32 last = start + (alloc->num_pages - 1) * MALI_MMU_PAGE_SIZE; + if (pa >= start && pa <= last) + { + _mali_osk_clear_nonatomic_bit((pa - start)/MALI_MMU_PAGE_SIZE, alloc->usage_map); + alloc->usage_count--; + + _mali_osk_memset((void*)( ((u32)alloc->pages.mapping) + (pa - start) ), 0, MALI_MMU_PAGE_SIZE); + + + if (0 == alloc->usage_count) + { + /* empty, release whole page alloc */ + _mali_osk_list_del(&alloc->list); + alloc->pages.release(&alloc->pages); + _mali_osk_free(alloc->usage_map); + _mali_osk_free(alloc); + } + else + { + /* transfer to partial list */ + _mali_osk_list_move(&alloc->list, &page_table_cache.partial); + } + + _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); + MALI_DEBUG_PRINT(4, ("(full list)Released table page 0x%08X to the cache\n", pa)); + return; + } + } + + MALI_DEBUG_PRINT(1, ("pa 0x%x not found in the page table cache\n", (void*)pa)); + + _mali_osk_lock_signal(page_table_cache.lock, _MALI_OSK_LOCKMODE_RW); +} + +static _mali_osk_errcode_t mali_mmu_page_table_cache_create(void) +{ + page_table_cache.lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_ONELOCK + | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_MEM_PT_CACHE); + MALI_CHECK_NON_NULL( page_table_cache.lock, _MALI_OSK_ERR_FAULT ); + _MALI_OSK_INIT_LIST_HEAD(&page_table_cache.partial); + _MALI_OSK_INIT_LIST_HEAD(&page_table_cache.full); + MALI_SUCCESS; +} + +static void mali_mmu_page_table_cache_destroy(void) +{ + mali_mmu_page_table_allocation * alloc, *temp; + + _MALI_OSK_LIST_FOREACHENTRY(alloc, temp, &page_table_cache.partial, mali_mmu_page_table_allocation, list) + { + MALI_DEBUG_PRINT_IF(1, 0 != alloc->usage_count, ("Destroying page table cache while pages are tagged as in use. %d allocations still marked as in use.\n", alloc->usage_count)); + _mali_osk_list_del(&alloc->list); + alloc->pages.release(&alloc->pages); + _mali_osk_free(alloc->usage_map); + _mali_osk_free(alloc); + } + + MALI_DEBUG_PRINT_IF(1, 0 == _mali_osk_list_empty(&page_table_cache.full), ("Page table cache full list contains one or more elements \n")); + + _MALI_OSK_LIST_FOREACHENTRY(alloc, temp, &page_table_cache.full, mali_mmu_page_table_allocation, list) + { + MALI_DEBUG_PRINT(1, ("Destroy alloc 0x%08X with usage count %d\n", (u32)alloc, alloc->usage_count)); + _mali_osk_list_del(&alloc->list); + alloc->pages.release(&alloc->pages); + _mali_osk_free(alloc->usage_map); + _mali_osk_free(alloc); + } + + _mali_osk_lock_term(page_table_cache.lock); +} diff --git a/drivers/media/video/samsung/mali/common/mali_memory.h b/drivers/media/video/samsung/mali/common/mali_memory.h new file mode 100644 index 0000000..53a994c --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_memory.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MALI_MEMORY_H__ +#define __MALI_MEMORY_H__ + +#include "mali_osk.h" +#include "mali_session.h" + +struct mali_cluster; +struct mali_group; + +/** @brief Initialize Mali memory subsystem + * + * Allocate and initialize internal data structures. Must be called before + * allocating Mali memory. + * + * @return On success _MALI_OSK_ERR_OK, othervise some error code describing the error. + */ +_mali_osk_errcode_t mali_memory_initialize(void); + +/** @brief Terminate Mali memory system + * + * Clean up and release internal data structures. + */ +void mali_memory_terminate(void); + +/** @brief Start new Mali memory session + * + * Allocate and prepare session specific memory allocation data data. The + * session page directory, lock, and descriptor map is set up. + * + * @param mali_session_data pointer to the session data structure + */ +_mali_osk_errcode_t mali_memory_session_begin(struct mali_session_data *mali_session_data); + +/** @brief Close a Mali memory session + * + * Release session specific memory allocation related data. + * + * @param mali_session_data pointer to the session data structure + */ +void mali_memory_session_end(struct mali_session_data *mali_session_data); + +/** @brief Allocate a page table page + * + * Allocate a page for use as a page directory or page table. The page is + * mapped into kernel space. + * + * @return _MALI_OSK_ERR_OK on success, othervise an error code + * @param table_page GPU pointer to the allocated page + * @param mapping CPU pointer to the mapping of the allocated page + */ +_mali_osk_errcode_t mali_mmu_get_table_page(u32 *table_page, mali_io_address *mapping); + +/** @brief Release a page table page + * + * Release a page table page allocated through \a mali_mmu_get_table_page + * + * @param pa the GPU address of the page to release + */ +void mali_mmu_release_table_page(u32 pa); + + +/** @brief Parse resource and prepare the OS memory allocator + */ +_mali_osk_errcode_t mali_memory_core_resource_os_memory(_mali_osk_resource_t * resource); + +/** @brief Parse resource and prepare the dedicated memory allocator + */ +_mali_osk_errcode_t mali_memory_core_resource_dedicated_memory(_mali_osk_resource_t * resource); + +#endif /* __MALI_MEMORY_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_mmu.c b/drivers/media/video/samsung/mali/common/mali_mmu.c new file mode 100644 index 0000000..2f2fa4d --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_mmu.c @@ -0,0 +1,619 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mali_kernel_common.h" +#include "mali_osk.h" +#include "mali_osk_bitops.h" +#include "mali_osk_list.h" +#include "mali_ukk.h" + +#include "mali_mmu.h" +#include "mali_hw_core.h" +#include "mali_group.h" +#include "mali_mmu_page_directory.h" + +/** + * Size of the MMU registers in bytes + */ +#define MALI_MMU_REGISTERS_SIZE 0x24 + +/** + * MMU register numbers + * Used in the register read/write routines. + * See the hardware documentation for more information about each register + */ +typedef enum mali_mmu_register { + MALI_MMU_REGISTER_DTE_ADDR = 0x0000, /**< Current Page Directory Pointer */ + MALI_MMU_REGISTER_STATUS = 0x0004, /**< Status of the MMU */ + MALI_MMU_REGISTER_COMMAND = 0x0008, /**< Command register, used to control the MMU */ + MALI_MMU_REGISTER_PAGE_FAULT_ADDR = 0x000C, /**< Logical address of the last page fault */ + MALI_MMU_REGISTER_ZAP_ONE_LINE = 0x010, /**< Used to invalidate the mapping of a single page from the MMU */ + MALI_MMU_REGISTER_INT_RAWSTAT = 0x0014, /**< Raw interrupt status, all interrupts visible */ + MALI_MMU_REGISTER_INT_CLEAR = 0x0018, /**< Indicate to the MMU that the interrupt has been received */ + MALI_MMU_REGISTER_INT_MASK = 0x001C, /**< Enable/disable types of interrupts */ + MALI_MMU_REGISTER_INT_STATUS = 0x0020 /**< Interrupt status based on the mask */ +} mali_mmu_register; + +/** + * MMU interrupt register bits + * Each cause of the interrupt is reported + * through the (raw) interrupt status registers. + * Multiple interrupts can be pending, so multiple bits + * can be set at once. + */ +typedef enum mali_mmu_interrupt +{ + MALI_MMU_INTERRUPT_PAGE_FAULT = 0x01, /**< A page fault occured */ + MALI_MMU_INTERRUPT_READ_BUS_ERROR = 0x02 /**< A bus read error occured */ +} mali_mmu_interrupt; + +/** + * MMU commands + * These are the commands that can be sent + * to the MMU unit. + */ +typedef enum mali_mmu_command +{ + MALI_MMU_COMMAND_ENABLE_PAGING = 0x00, /**< Enable paging (memory translation) */ + MALI_MMU_COMMAND_DISABLE_PAGING = 0x01, /**< Disable paging (memory translation) */ + MALI_MMU_COMMAND_ENABLE_STALL = 0x02, /**< Enable stall on page fault */ + MALI_MMU_COMMAND_DISABLE_STALL = 0x03, /**< Disable stall on page fault */ + MALI_MMU_COMMAND_ZAP_CACHE = 0x04, /**< Zap the entire page table cache */ + MALI_MMU_COMMAND_PAGE_FAULT_DONE = 0x05, /**< Page fault processed */ + MALI_MMU_COMMAND_HARD_RESET = 0x06 /**< Reset the MMU back to power-on settings */ +} mali_mmu_command; + +typedef enum mali_mmu_status_bits +{ + MALI_MMU_STATUS_BIT_PAGING_ENABLED = 1 << 0, + MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE = 1 << 1, + MALI_MMU_STATUS_BIT_STALL_ACTIVE = 1 << 2, + MALI_MMU_STATUS_BIT_IDLE = 1 << 3, + MALI_MMU_STATUS_BIT_REPLAY_BUFFER_EMPTY = 1 << 4, + MALI_MMU_STATUS_BIT_PAGE_FAULT_IS_WRITE = 1 << 5, +} mali_mmu_status_bits; + +/** + * Definition of the MMU struct + * Used to track a MMU unit in the system. + * Contains information about the mapping of the registers + */ +struct mali_mmu_core +{ + struct mali_hw_core hw_core; /**< Common for all HW cores */ + struct mali_group *group; /**< Parent core group */ + _mali_osk_irq_t *irq; /**< IRQ handler */ +}; + +/** + * The MMU interrupt handler + * Upper half of the MMU interrupt processing. + * Called by the kernel when the MMU has triggered an interrupt. + * The interrupt function supports IRQ sharing. So it'll probe the MMU in question + * @param irq The irq number (not used) + * @param dev_id Points to the MMU object being handled + * @param regs Registers of interrupted process (not used) + * @return Standard Linux interrupt result. + * Subset used by the driver is IRQ_HANDLED processed + * IRQ_NONE Not processed + */ +static _mali_osk_errcode_t mali_mmu_upper_half(void * data); + +/** + * The MMU reset hander + * Bottom half of the MMU interrupt processing for page faults and bus errors + * @param work The item to operate on, NULL in our case + */ +static void mali_mmu_bottom_half(void *data); + +static void mali_mmu_probe_trigger(void *data); +static _mali_osk_errcode_t mali_mmu_probe_ack(void *data); + +MALI_STATIC_INLINE _mali_osk_errcode_t mali_mmu_raw_reset(struct mali_mmu_core *mmu); + +/* page fault queue flush helper pages + * note that the mapping pointers are currently unused outside of the initialization functions */ +static u32 mali_page_fault_flush_page_directory = MALI_INVALID_PAGE; +static u32 mali_page_fault_flush_page_table = MALI_INVALID_PAGE; +static u32 mali_page_fault_flush_data_page = MALI_INVALID_PAGE; + +/* an empty page directory (no address valid) which is active on any MMU not currently marked as in use */ +static u32 mali_empty_page_directory = MALI_INVALID_PAGE; + +_mali_osk_errcode_t mali_mmu_initialize(void) +{ + /* allocate the helper pages */ + mali_empty_page_directory = mali_allocate_empty_page(); + if(0 == mali_empty_page_directory) + { + mali_empty_page_directory = MALI_INVALID_PAGE; + return _MALI_OSK_ERR_NOMEM; + } + + if (_MALI_OSK_ERR_OK != mali_create_fault_flush_pages(&mali_page_fault_flush_page_directory, + &mali_page_fault_flush_page_table, &mali_page_fault_flush_data_page)) + { + mali_free_empty_page(mali_empty_page_directory); + return _MALI_OSK_ERR_FAULT; + } + + return _MALI_OSK_ERR_OK; +} + +void mali_mmu_terminate(void) +{ + MALI_DEBUG_PRINT(3, ("Mali MMU: terminating\n")); + + /* Free global helper pages */ + mali_free_empty_page(mali_empty_page_directory); + + /* Free the page fault flush pages */ + mali_destroy_fault_flush_pages(&mali_page_fault_flush_page_directory, + &mali_page_fault_flush_page_table, &mali_page_fault_flush_data_page); +} + +struct mali_mmu_core *mali_mmu_create(_mali_osk_resource_t *resource) +{ + struct mali_mmu_core* mmu = NULL; + + MALI_DEBUG_ASSERT_POINTER(resource); + + MALI_DEBUG_PRINT(2, ("Mali MMU: Creating Mali MMU: %s\n", resource->description)); + + mmu = _mali_osk_calloc(1,sizeof(struct mali_mmu_core)); + if (NULL != mmu) + { + if (_MALI_OSK_ERR_OK == mali_hw_core_create(&mmu->hw_core, resource, MALI_MMU_REGISTERS_SIZE)) + { + if (_MALI_OSK_ERR_OK == mali_mmu_reset(mmu)) + { + /* Setup IRQ handlers (which will do IRQ probing if needed) */ + mmu->irq = _mali_osk_irq_init(resource->irq, + mali_mmu_upper_half, + mali_mmu_bottom_half, + mali_mmu_probe_trigger, + mali_mmu_probe_ack, + mmu, + "mali_mmu_irq_handlers"); + if (NULL != mmu->irq) + { + return mmu; + } + else + { + MALI_PRINT_ERROR(("Failed to setup interrupt handlers for MMU %s\n", mmu->hw_core.description)); + } + } + mali_hw_core_delete(&mmu->hw_core); + } + + _mali_osk_free(mmu); + } + else + { + MALI_PRINT_ERROR(("Failed to allocate memory for MMU\n")); + } + + return NULL; +} + +void mali_mmu_delete(struct mali_mmu_core *mmu) +{ + _mali_osk_irq_term(mmu->irq); + mali_hw_core_delete(&mmu->hw_core); + _mali_osk_free(mmu); +} + +void mali_mmu_set_group(struct mali_mmu_core *mmu, struct mali_group *group) +{ + mmu->group = group; +} + +static void mali_mmu_enable_paging(struct mali_mmu_core *mmu) +{ + const int max_loop_count = 100; + const int delay_in_usecs = 1; + int i; + + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ENABLE_PAGING); + + for (i = 0; i < max_loop_count; ++i) + { + if (mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS) & MALI_MMU_STATUS_BIT_PAGING_ENABLED) + { + break; + } + _mali_osk_time_ubusydelay(delay_in_usecs); + } + if (max_loop_count == i) + { + MALI_PRINT_ERROR(("Enable paging request failed, MMU status is 0x%08X\n", mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS))); + } +} + +mali_bool mali_mmu_enable_stall(struct mali_mmu_core *mmu) +{ + const int max_loop_count = 100; + const int delay_in_usecs = 999; + int i; + u32 mmu_status; + + /* There are no group when it is called from mali_mmu_create */ + if ( mmu->group ) MALI_ASSERT_GROUP_LOCKED(mmu->group); + + mmu_status = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS); + + if ( 0 == (mmu_status & MALI_MMU_STATUS_BIT_PAGING_ENABLED) ) + { + MALI_DEBUG_PRINT(4, ("MMU stall is implicit when Paging is not enebled.\n")); + return MALI_TRUE; + } + + if ( mmu_status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE ) + { + MALI_DEBUG_PRINT(3, ("Aborting MMU stall request since it is in pagefault state.\n")); + return MALI_FALSE; + } + + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ENABLE_STALL); + + for (i = 0; i < max_loop_count; ++i) + { + mmu_status = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS); + if ( mmu_status & (MALI_MMU_STATUS_BIT_STALL_ACTIVE|MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE)) + { + break; + } + if ( 0 == (mmu_status & ( MALI_MMU_STATUS_BIT_PAGING_ENABLED ))) + { + break; + } + _mali_osk_time_ubusydelay(delay_in_usecs); + } + if (max_loop_count == i) + { + MALI_PRINT_ERROR(("Enable stall request failed, MMU status is 0x%08X\n", mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS))); + return MALI_FALSE; + } + + if ( mmu_status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE ) + { + MALI_DEBUG_PRINT(3, ("Aborting MMU stall request since it has a pagefault.\n")); + return MALI_FALSE; + } + + return MALI_TRUE; +} + +void mali_mmu_disable_stall(struct mali_mmu_core *mmu) +{ + const int max_loop_count = 100; + const int delay_in_usecs = 1; + int i; + u32 mmu_status; + /* There are no group when it is called from mali_mmu_create */ + if ( mmu->group ) MALI_ASSERT_GROUP_LOCKED(mmu->group); + + mmu_status = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS); + + if ( 0 == (mmu_status & MALI_MMU_STATUS_BIT_PAGING_ENABLED )) + { + MALI_DEBUG_PRINT(3, ("MMU disable skipped since it was not enabled.\n")); + return; + } + if (mmu_status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE) + { + MALI_DEBUG_PRINT(2, ("Aborting MMU disable stall request since it is in pagefault state.\n")); + return; + } + + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_DISABLE_STALL); + + for (i = 0; i < max_loop_count; ++i) + { + u32 status = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS); + if ( 0 == (status & MALI_MMU_STATUS_BIT_STALL_ACTIVE) ) + { + break; + } + if ( status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE ) + { + break; + } + if ( 0 == (mmu_status & MALI_MMU_STATUS_BIT_PAGING_ENABLED )) + { + break; + } + _mali_osk_time_ubusydelay(delay_in_usecs); + } + if (max_loop_count == i) MALI_DEBUG_PRINT(1,("Disable stall request failed, MMU status is 0x%08X\n", mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS))); +} + +void mali_mmu_page_fault_done(struct mali_mmu_core *mmu) +{ + MALI_ASSERT_GROUP_LOCKED(mmu->group); + MALI_DEBUG_PRINT(4, ("Mali MMU: %s: Leaving page fault mode\n", mmu->hw_core.description)); + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_PAGE_FAULT_DONE); +} + +MALI_STATIC_INLINE _mali_osk_errcode_t mali_mmu_raw_reset(struct mali_mmu_core *mmu) +{ + const int max_loop_count = 100; + const int delay_in_usecs = 1; + int i; + /* The _if_ is neccessary when called from mali_mmu_create and NULL==group */ + if (mmu->group)MALI_ASSERT_GROUP_LOCKED(mmu->group); + + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_DTE_ADDR, 0xCAFEBABE); + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_HARD_RESET); + + for (i = 0; i < max_loop_count; ++i) + { + if (mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_DTE_ADDR) == 0) + { + break; + } + _mali_osk_time_ubusydelay(delay_in_usecs); + } + if (max_loop_count == i) + { + MALI_PRINT_ERROR(("Reset request failed, MMU status is 0x%08X\n", mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS))); + return _MALI_OSK_ERR_FAULT; + } + + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t mali_mmu_reset(struct mali_mmu_core *mmu) +{ + _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; + mali_bool stall_success; + MALI_DEBUG_ASSERT_POINTER(mmu); + /* The _if_ is neccessary when called from mali_mmu_create and NULL==group */ + if (mmu->group) + { + MALI_ASSERT_GROUP_LOCKED(mmu->group); + } + + stall_success = mali_mmu_enable_stall(mmu); + + /* The stall can not fail in current hw-state */ + MALI_DEBUG_ASSERT(stall_success); + + MALI_DEBUG_PRINT(3, ("Mali MMU: mali_kernel_mmu_reset: %s\n", mmu->hw_core.description)); + + if (_MALI_OSK_ERR_OK == mali_mmu_raw_reset(mmu)) + { + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_MASK, MALI_MMU_INTERRUPT_PAGE_FAULT | MALI_MMU_INTERRUPT_READ_BUS_ERROR); + /* no session is active, so just activate the empty page directory */ + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_DTE_ADDR, mali_empty_page_directory); + mali_mmu_enable_paging(mmu); + err = _MALI_OSK_ERR_OK; + } + mali_mmu_disable_stall(mmu); + + return err; +} + + +/* ------------- interrupt handling below ------------------ */ + +static _mali_osk_errcode_t mali_mmu_upper_half(void * data) +{ + struct mali_mmu_core *mmu = (struct mali_mmu_core *)data; + u32 int_stat; + + MALI_DEBUG_ASSERT_POINTER(mmu); + + /* Check if it was our device which caused the interrupt (we could be sharing the IRQ line) */ + int_stat = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_INT_STATUS); + if (0 != int_stat) + { + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_MASK, 0); + mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS); + + if (int_stat & MALI_MMU_INTERRUPT_PAGE_FAULT) + { + _mali_osk_irq_schedulework(mmu->irq); + } + + if (int_stat & MALI_MMU_INTERRUPT_READ_BUS_ERROR) + { + /* clear interrupt flag */ + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_CLEAR, MALI_MMU_INTERRUPT_READ_BUS_ERROR); + /* reenable it */ + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_MASK, + mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_INT_MASK) | MALI_MMU_INTERRUPT_READ_BUS_ERROR); + MALI_PRINT_ERROR(("Mali MMU: Read bus error\n")); + } + return _MALI_OSK_ERR_OK; + } + + return _MALI_OSK_ERR_FAULT; +} + +static void mali_mmu_bottom_half(void * data) +{ + struct mali_mmu_core *mmu = (struct mali_mmu_core*)data; + u32 raw, status, fault_address; + + MALI_DEBUG_ASSERT_POINTER(mmu); + + MALI_DEBUG_PRINT(3, ("Mali MMU: Page fault bottom half: Locking subsystems\n")); + + mali_group_lock(mmu->group); /* Unlocked in mali_group_bottom_half */ + + if ( MALI_FALSE == mali_group_power_is_on(mmu->group) ) + { + MALI_PRINT_ERROR(("Interrupt bottom half of %s when core is OFF.",mmu->hw_core.description)); + mali_group_unlock(mmu->group); + return; + } + + raw = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_INT_RAWSTAT); + status = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS); + + if ( (0==(raw & MALI_MMU_INTERRUPT_PAGE_FAULT)) && (0==(status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE)) ) + { + MALI_DEBUG_PRINT(2, ("Mali MMU: Page fault bottom half: No Irq found.\n")); + mali_group_unlock(mmu->group); + /* MALI_DEBUG_ASSERT(0); */ + return; + } + + /* An actual page fault has occurred. */ + + fault_address = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_PAGE_FAULT_ADDR); + + MALI_DEBUG_PRINT(2,("Mali MMU: Page fault detected at 0x%x from bus id %d of type %s on %s\n", + (void*)fault_address, + (status >> 6) & 0x1F, + (status & 32) ? "write" : "read", + mmu->hw_core.description)); + + mali_group_bottom_half(mmu->group, GROUP_EVENT_MMU_PAGE_FAULT); /* Unlocks the group lock */ +} + +mali_bool mali_mmu_zap_tlb(struct mali_mmu_core *mmu) +{ + mali_bool stall_success; + MALI_ASSERT_GROUP_LOCKED(mmu->group); + + stall_success = mali_mmu_enable_stall(mmu); + + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE); + + if (MALI_FALSE == stall_success) + { + /* False means that it is in Pagefault state. Not possible to disable_stall then */ + return MALI_FALSE; + } + + mali_mmu_disable_stall(mmu); + return MALI_TRUE; +} + +void mali_mmu_zap_tlb_without_stall(struct mali_mmu_core *mmu) +{ + MALI_ASSERT_GROUP_LOCKED(mmu->group); + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE); +} + + +void mali_mmu_invalidate_page(struct mali_mmu_core *mmu, u32 mali_address) +{ + MALI_ASSERT_GROUP_LOCKED(mmu->group); + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_ZAP_ONE_LINE, MALI_MMU_PDE_ENTRY(mali_address)); +} + +static void mali_mmu_activate_address_space(struct mali_mmu_core *mmu, u32 page_directory) +{ + MALI_ASSERT_GROUP_LOCKED(mmu->group); + /* The MMU must be in stalled or page fault mode, for this writing to work */ + MALI_DEBUG_ASSERT( 0 != ( mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS) + & (MALI_MMU_STATUS_BIT_STALL_ACTIVE|MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE) ) ); + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_DTE_ADDR, page_directory); + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE); + +} + +mali_bool mali_mmu_activate_page_directory(struct mali_mmu_core *mmu, struct mali_page_directory *pagedir) +{ + mali_bool stall_success; + MALI_DEBUG_ASSERT_POINTER(mmu); + MALI_ASSERT_GROUP_LOCKED(mmu->group); + + MALI_DEBUG_PRINT(5, ("Asked to activate page directory 0x%x on MMU %s\n", pagedir, mmu->hw_core.description)); + stall_success = mali_mmu_enable_stall(mmu); + + if ( MALI_FALSE==stall_success ) return MALI_FALSE; + mali_mmu_activate_address_space(mmu, pagedir->page_directory); + mali_mmu_disable_stall(mmu); + return MALI_TRUE; +} + +void mali_mmu_activate_empty_page_directory(struct mali_mmu_core* mmu) +{ + mali_bool stall_success; + MALI_DEBUG_ASSERT_POINTER(mmu); + MALI_ASSERT_GROUP_LOCKED(mmu->group); + MALI_DEBUG_PRINT(3, ("Activating the empty page directory on MMU %s\n", mmu->hw_core.description)); + + stall_success = mali_mmu_enable_stall(mmu); + /* This function can only be called when the core is idle, so it could not fail. */ + MALI_DEBUG_ASSERT( stall_success ); + mali_mmu_activate_address_space(mmu, mali_empty_page_directory); + mali_mmu_disable_stall(mmu); +} + +void mali_mmu_activate_fault_flush_page_directory(struct mali_mmu_core* mmu) +{ + mali_bool stall_success; + MALI_DEBUG_ASSERT_POINTER(mmu); + MALI_ASSERT_GROUP_LOCKED(mmu->group); + + MALI_DEBUG_PRINT(3, ("Activating the page fault flush page directory on MMU %s\n", mmu->hw_core.description)); + stall_success = mali_mmu_enable_stall(mmu); + /* This function is expect to fail the stalling, since it might be in PageFault mode when it is called */ + mali_mmu_activate_address_space(mmu, mali_page_fault_flush_page_directory); + if ( MALI_TRUE==stall_success ) mali_mmu_disable_stall(mmu); +} + +/* Is called when we want the mmu to give an interrupt */ +static void mali_mmu_probe_trigger(void *data) +{ + struct mali_mmu_core *mmu = (struct mali_mmu_core *)data; + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_RAWSTAT, MALI_MMU_INTERRUPT_PAGE_FAULT|MALI_MMU_INTERRUPT_READ_BUS_ERROR); +} + +/* Is called when the irq probe wants the mmu to acknowledge an interrupt from the hw */ +static _mali_osk_errcode_t mali_mmu_probe_ack(void *data) +{ + struct mali_mmu_core *mmu = (struct mali_mmu_core *)data; + u32 int_stat; + + int_stat = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_INT_STATUS); + + MALI_DEBUG_PRINT(2, ("mali_mmu_probe_irq_acknowledge: intstat 0x%x\n", int_stat)); + if (int_stat & MALI_MMU_INTERRUPT_PAGE_FAULT) + { + MALI_DEBUG_PRINT(2, ("Probe: Page fault detect: PASSED\n")); + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_CLEAR, MALI_MMU_INTERRUPT_PAGE_FAULT); + } + else + { + MALI_DEBUG_PRINT(1, ("Probe: Page fault detect: FAILED\n")); + } + + if (int_stat & MALI_MMU_INTERRUPT_READ_BUS_ERROR) + { + MALI_DEBUG_PRINT(2, ("Probe: Bus read error detect: PASSED\n")); + mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_CLEAR, MALI_MMU_INTERRUPT_READ_BUS_ERROR); + } + else + { + MALI_DEBUG_PRINT(1, ("Probe: Bus read error detect: FAILED\n")); + } + + if ( (int_stat & (MALI_MMU_INTERRUPT_PAGE_FAULT|MALI_MMU_INTERRUPT_READ_BUS_ERROR)) == + (MALI_MMU_INTERRUPT_PAGE_FAULT|MALI_MMU_INTERRUPT_READ_BUS_ERROR)) + { + return _MALI_OSK_ERR_OK; + } + + return _MALI_OSK_ERR_FAULT; +} + +#if 0 +void mali_mmu_print_state(struct mali_mmu_core *mmu) +{ + MALI_DEBUG_PRINT(2, ("MMU: State of %s is 0x%08x\n", mmu->hw_core.description, mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS))); +} +#endif diff --git a/drivers/media/video/samsung/mali/common/mali_mmu.h b/drivers/media/video/samsung/mali/common/mali_mmu.h new file mode 100644 index 0000000..c7274b8 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_mmu.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MALI_MMU_H__ +#define __MALI_MMU_H__ + +#include "mali_osk.h" +#include "mali_mmu_page_directory.h" + +/* Forward declaration from mali_group.h */ +struct mali_group; + +struct mali_mmu_core; + +_mali_osk_errcode_t mali_mmu_initialize(void); + +void mali_mmu_terminate(void); + +struct mali_mmu_core *mali_mmu_create(_mali_osk_resource_t *resource); +void mali_mmu_set_group(struct mali_mmu_core *mmu, struct mali_group *group); +void mali_mmu_delete(struct mali_mmu_core *mmu); + +_mali_osk_errcode_t mali_mmu_reset(struct mali_mmu_core *mmu); +mali_bool mali_mmu_zap_tlb(struct mali_mmu_core *mmu); +void mali_mmu_zap_tlb_without_stall(struct mali_mmu_core *mmu); +void mali_mmu_invalidate_page(struct mali_mmu_core *mmu, u32 mali_address); + +mali_bool mali_mmu_activate_page_directory(struct mali_mmu_core* mmu, struct mali_page_directory *pagedir); +void mali_mmu_activate_empty_page_directory(struct mali_mmu_core* mmu); +void mali_mmu_activate_fault_flush_page_directory(struct mali_mmu_core* mmu); + +/** + * Issues the enable stall command to the MMU and waits for HW to complete the request + * @param mmu The MMU to enable paging for + * @return MALI_TRUE if HW stall was successfully engaged, otherwise MALI_FALSE (req timed out) + */ +mali_bool mali_mmu_enable_stall(struct mali_mmu_core *mmu); + +/** + * Issues the disable stall command to the MMU and waits for HW to complete the request + * @param mmu The MMU to enable paging for + */ +void mali_mmu_disable_stall(struct mali_mmu_core *mmu); + +void mali_mmu_page_fault_done(struct mali_mmu_core *mmu); + + +#endif /* __MALI_MMU_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_mmu_page_directory.c b/drivers/media/video/samsung/mali/common/mali_mmu_page_directory.c new file mode 100644 index 0000000..43a4cf4 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_mmu_page_directory.c @@ -0,0 +1,459 @@ +/* + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mali_kernel_common.h" +#include "mali_kernel_core.h" +#include "mali_osk.h" +#include "mali_uk_types.h" +#include "mali_mmu_page_directory.h" +#include "mali_memory.h" + +#include "mali_cluster.h" +#include "mali_group.h" + +static _mali_osk_errcode_t fill_page(mali_io_address mapping, u32 data); + +u32 mali_allocate_empty_page(void) +{ + _mali_osk_errcode_t err; + mali_io_address mapping; + u32 address; + + if(_MALI_OSK_ERR_OK != mali_mmu_get_table_page(&address, &mapping)) + { + /* Allocation failed */ + return 0; + } + + MALI_DEBUG_ASSERT_POINTER( mapping ); + + err = fill_page(mapping, 0); + if (_MALI_OSK_ERR_OK != err) + { + mali_mmu_release_table_page(address); + } + return address; +} + +void mali_free_empty_page(u32 address) +{ + if (MALI_INVALID_PAGE != address) + { + mali_mmu_release_table_page(address); + } +} + +_mali_osk_errcode_t mali_create_fault_flush_pages(u32 *page_directory, u32 *page_table, u32 *data_page) +{ + _mali_osk_errcode_t err; + mali_io_address page_directory_mapping; + mali_io_address page_table_mapping; + mali_io_address data_page_mapping; + + err = mali_mmu_get_table_page(data_page, &data_page_mapping); + if (_MALI_OSK_ERR_OK == err) + { + err = mali_mmu_get_table_page(page_table, &page_table_mapping); + if (_MALI_OSK_ERR_OK == err) + { + err = mali_mmu_get_table_page(page_directory, &page_directory_mapping); + if (_MALI_OSK_ERR_OK == err) + { + fill_page(data_page_mapping, 0); + fill_page(page_table_mapping, *data_page | MALI_MMU_FLAGS_WRITE_PERMISSION | MALI_MMU_FLAGS_READ_PERMISSION | MALI_MMU_FLAGS_PRESENT); + fill_page(page_directory_mapping, *page_table | MALI_MMU_FLAGS_PRESENT); + MALI_SUCCESS; + } + mali_mmu_release_table_page(*page_table); + *page_table = MALI_INVALID_PAGE; + } + mali_mmu_release_table_page(*data_page); + *data_page = MALI_INVALID_PAGE; + } + return err; +} + +void mali_destroy_fault_flush_pages(u32 *page_directory, u32 *page_table, u32 *data_page) +{ + if (MALI_INVALID_PAGE != *page_directory) + { + mali_mmu_release_table_page(*page_directory); + *page_directory = MALI_INVALID_PAGE; + } + + if (MALI_INVALID_PAGE != *page_table) + { + mali_mmu_release_table_page(*page_table); + *page_table = MALI_INVALID_PAGE; + } + + if (MALI_INVALID_PAGE != *data_page) + { + mali_mmu_release_table_page(*data_page); + *data_page = MALI_INVALID_PAGE; + } +} + +static _mali_osk_errcode_t fill_page(mali_io_address mapping, u32 data) +{ + int i; + MALI_DEBUG_ASSERT_POINTER( mapping ); + + for(i = 0; i < MALI_MMU_PAGE_SIZE/4; i++) + { + _mali_osk_mem_iowrite32_relaxed( mapping, i * sizeof(u32), data); + } + _mali_osk_mem_barrier(); + MALI_SUCCESS; +} + +_mali_osk_errcode_t mali_mmu_pagedir_map(struct mali_page_directory *pagedir, u32 mali_address, u32 size) +{ + const int first_pde = MALI_MMU_PDE_ENTRY(mali_address); + const int last_pde = MALI_MMU_PDE_ENTRY(mali_address + size - 1); + _mali_osk_errcode_t err; + mali_io_address pde_mapping; + u32 pde_phys; + int i; + + for(i = first_pde; i <= last_pde; i++) + { + if(0 == (_mali_osk_mem_ioread32(pagedir->page_directory_mapped, i*sizeof(u32)) & MALI_MMU_FLAGS_PRESENT)) + { + /* Page table not present */ + MALI_DEBUG_ASSERT(0 == pagedir->page_entries_usage_count[i]); + MALI_DEBUG_ASSERT(NULL == pagedir->page_entries_mapped[i]); + + err = mali_mmu_get_table_page(&pde_phys, &pde_mapping); + if(_MALI_OSK_ERR_OK != err) + { + MALI_PRINT_ERROR(("Failed to allocate page table page.\n")); + return err; + } + pagedir->page_entries_mapped[i] = pde_mapping; + + /* Update PDE, mark as present */ + _mali_osk_mem_iowrite32_relaxed(pagedir->page_directory_mapped, i*sizeof(u32), + pde_phys | MALI_MMU_FLAGS_PRESENT); + + MALI_DEBUG_ASSERT(0 == pagedir->page_entries_usage_count[i]); + pagedir->page_entries_usage_count[i] = 1; + } + else + { + pagedir->page_entries_usage_count[i]++; + } + } + _mali_osk_write_mem_barrier(); + + MALI_SUCCESS; +} + +MALI_STATIC_INLINE void mali_mmu_zero_pte(mali_io_address page_table, u32 mali_address, u32 size) +{ + int i; + const int first_pte = MALI_MMU_PTE_ENTRY(mali_address); + const int last_pte = MALI_MMU_PTE_ENTRY(mali_address + size - 1); + + for (i = first_pte; i <= last_pte; i++) + { + _mali_osk_mem_iowrite32_relaxed(page_table, i * sizeof(u32), 0); + } +} + +_mali_osk_errcode_t mali_mmu_pagedir_unmap(struct mali_page_directory *pagedir, u32 mali_address, u32 size) +{ + const int first_pde = MALI_MMU_PDE_ENTRY(mali_address); + const int last_pde = MALI_MMU_PDE_ENTRY(mali_address + size - 1); + u32 left = size; + int i; +#ifndef MALI_UNMAP_FLUSH_ALL_MALI_L2 + mali_bool pd_changed = MALI_FALSE; + u32 pages_to_invalidate[3]; /* hard-coded to 3: max two pages from the PT level plus max one page from PD level */ + u32 num_pages_inv = 0; +#endif + + /* For all page directory entries in range. */ + for (i = first_pde; i <= last_pde; i++) + { + u32 size_in_pde, offset; + + MALI_DEBUG_ASSERT_POINTER(pagedir->page_entries_mapped[i]); + MALI_DEBUG_ASSERT(0 != pagedir->page_entries_usage_count[i]); + + /* Offset into page table, 0 if mali_address is 4MiB aligned */ + offset = (mali_address & (MALI_MMU_VIRTUAL_PAGE_SIZE - 1)); + if (left < MALI_MMU_VIRTUAL_PAGE_SIZE - offset) + { + size_in_pde = left; + } + else + { + size_in_pde = MALI_MMU_VIRTUAL_PAGE_SIZE - offset; + } + + pagedir->page_entries_usage_count[i]--; + + /* If entire page table is unused, free it */ + if (0 == pagedir->page_entries_usage_count[i]) + { + u32 page_address; + MALI_DEBUG_PRINT(4, ("Releasing page table as this is the last reference\n")); + /* last reference removed, no need to zero out each PTE */ + + page_address = MALI_MMU_ENTRY_ADDRESS(_mali_osk_mem_ioread32(pagedir->page_directory_mapped, i*sizeof(u32))); + pagedir->page_entries_mapped[i] = NULL; + _mali_osk_mem_iowrite32_relaxed(pagedir->page_directory_mapped, i*sizeof(u32), 0); + + mali_mmu_release_table_page(page_address); +#ifndef MALI_UNMAP_FLUSH_ALL_MALI_L2 + pd_changed = MALI_TRUE; +#endif + } + else + { +#ifndef MALI_UNMAP_FLUSH_ALL_MALI_L2 + pages_to_invalidate[num_pages_inv] = mali_page_directory_get_phys_address(pagedir, i); + num_pages_inv++; + MALI_DEBUG_ASSERT(num_pages_inv<3); +#endif + + /* If part of the page table is still in use, zero the relevant PTEs */ + mali_mmu_zero_pte(pagedir->page_entries_mapped[i], mali_address, size_in_pde); + } + + left -= size_in_pde; + mali_address += size_in_pde; + } + _mali_osk_write_mem_barrier(); + +#ifndef MALI_UNMAP_FLUSH_ALL_MALI_L2 + /* L2 pages invalidation */ + if (MALI_TRUE == pd_changed) + { + pages_to_invalidate[num_pages_inv] = pagedir->page_directory; + num_pages_inv++; + MALI_DEBUG_ASSERT(num_pages_inv<3); + } + + if (_MALI_PRODUCT_ID_MALI200 != mali_kernel_core_get_product_id()) + { + mali_cluster_invalidate_pages(pages_to_invalidate, num_pages_inv); + } +#endif + + MALI_SUCCESS; +} + +struct mali_page_directory *mali_mmu_pagedir_alloc(void) +{ + struct mali_page_directory *pagedir; + + pagedir = _mali_osk_calloc(1, sizeof(struct mali_page_directory)); + if(NULL == pagedir) + { + return NULL; + } + + if(_MALI_OSK_ERR_OK != mali_mmu_get_table_page(&pagedir->page_directory, &pagedir->page_directory_mapped)) + { + _mali_osk_free(pagedir); + return NULL; + } + + /* Zero page directory */ + fill_page(pagedir->page_directory_mapped, 0); + + return pagedir; +} + +void mali_mmu_pagedir_free(struct mali_page_directory *pagedir) +{ + const int num_page_table_entries = sizeof(pagedir->page_entries_mapped) / sizeof(pagedir->page_entries_mapped[0]); + int i; + + /* Free referenced page tables and zero PDEs. */ + for (i = 0; i < num_page_table_entries; i++) + { + if (pagedir->page_directory_mapped && (_mali_osk_mem_ioread32(pagedir->page_directory_mapped, sizeof(u32)*i) & MALI_MMU_FLAGS_PRESENT)) + { + mali_mmu_release_table_page( _mali_osk_mem_ioread32(pagedir->page_directory_mapped, i*sizeof(u32)) & ~MALI_MMU_FLAGS_MASK); + _mali_osk_mem_iowrite32_relaxed(pagedir->page_directory_mapped, i * sizeof(u32), 0); + } + } + _mali_osk_write_mem_barrier(); + + /* Free the page directory page. */ + mali_mmu_release_table_page(pagedir->page_directory); + + _mali_osk_free(pagedir); +} + + +void mali_mmu_pagedir_update(struct mali_page_directory *pagedir, u32 mali_address, u32 phys_address, u32 size) +{ + u32 end_address = mali_address + size; + + /* Map physical pages into MMU page tables */ + for ( ; mali_address < end_address; mali_address += MALI_MMU_PAGE_SIZE, phys_address += MALI_MMU_PAGE_SIZE) + { + MALI_DEBUG_ASSERT_POINTER(pagedir->page_entries_mapped[MALI_MMU_PDE_ENTRY(mali_address)]); + _mali_osk_mem_iowrite32_relaxed(pagedir->page_entries_mapped[MALI_MMU_PDE_ENTRY(mali_address)], + MALI_MMU_PTE_ENTRY(mali_address) * sizeof(u32), + phys_address | MALI_MMU_FLAGS_WRITE_PERMISSION | MALI_MMU_FLAGS_READ_PERMISSION | MALI_MMU_FLAGS_PRESENT); + } + _mali_osk_write_mem_barrier(); +} + +u32 mali_page_directory_get_phys_address(struct mali_page_directory *pagedir, u32 index) +{ + return (_mali_osk_mem_ioread32(pagedir->page_directory_mapped, index*sizeof(u32)) & ~MALI_MMU_FLAGS_MASK); +} + +/* For instrumented */ +struct dump_info +{ + u32 buffer_left; + u32 register_writes_size; + u32 page_table_dump_size; + u32 *buffer; +}; + +static _mali_osk_errcode_t writereg(u32 where, u32 what, const char *comment, struct dump_info *info) +{ + if (NULL != info) + { + info->register_writes_size += sizeof(u32)*2; /* two 32-bit words */ + + if (NULL != info->buffer) + { + /* check that we have enough space */ + if (info->buffer_left < sizeof(u32)*2) MALI_ERROR(_MALI_OSK_ERR_NOMEM); + + *info->buffer = where; + info->buffer++; + + *info->buffer = what; + info->buffer++; + + info->buffer_left -= sizeof(u32)*2; + } + } + + MALI_SUCCESS; +} + +static _mali_osk_errcode_t dump_page(mali_io_address page, u32 phys_addr, struct dump_info * info) +{ + if (NULL != info) + { + /* 4096 for the page and 4 bytes for the address */ + const u32 page_size_in_elements = MALI_MMU_PAGE_SIZE / 4; + const u32 page_size_in_bytes = MALI_MMU_PAGE_SIZE; + const u32 dump_size_in_bytes = MALI_MMU_PAGE_SIZE + 4; + + info->page_table_dump_size += dump_size_in_bytes; + + if (NULL != info->buffer) + { + if (info->buffer_left < dump_size_in_bytes) MALI_ERROR(_MALI_OSK_ERR_NOMEM); + + *info->buffer = phys_addr; + info->buffer++; + + _mali_osk_memcpy(info->buffer, page, page_size_in_bytes); + info->buffer += page_size_in_elements; + + info->buffer_left -= dump_size_in_bytes; + } + } + + MALI_SUCCESS; +} + +static _mali_osk_errcode_t dump_mmu_page_table(struct mali_page_directory *pagedir, struct dump_info * info) +{ + MALI_DEBUG_ASSERT_POINTER(pagedir); + MALI_DEBUG_ASSERT_POINTER(info); + + if (NULL != pagedir->page_directory_mapped) + { + int i; + + MALI_CHECK_NO_ERROR( + dump_page(pagedir->page_directory_mapped, pagedir->page_directory, info) + ); + + for (i = 0; i < 1024; i++) + { + if (NULL != pagedir->page_entries_mapped[i]) + { + MALI_CHECK_NO_ERROR( + dump_page(pagedir->page_entries_mapped[i], + _mali_osk_mem_ioread32(pagedir->page_directory_mapped, + i * sizeof(u32)) & ~MALI_MMU_FLAGS_MASK, info) + ); + } + } + } + + MALI_SUCCESS; +} + +static _mali_osk_errcode_t dump_mmu_registers(struct mali_page_directory *pagedir, struct dump_info * info) +{ + MALI_CHECK_NO_ERROR(writereg(0x00000000, pagedir->page_directory, + "set the page directory address", info)); + MALI_CHECK_NO_ERROR(writereg(0x00000008, 4, "zap???", info)); + MALI_CHECK_NO_ERROR(writereg(0x00000008, 0, "enable paging", info)); + MALI_SUCCESS; +} + +_mali_osk_errcode_t _mali_ukk_query_mmu_page_table_dump_size( _mali_uk_query_mmu_page_table_dump_size_s *args ) +{ + struct dump_info info = { 0, 0, 0, NULL }; + struct mali_session_data * session_data; + + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + + session_data = (struct mali_session_data *)(args->ctx); + + MALI_CHECK_NO_ERROR(dump_mmu_registers(session_data->page_directory, &info)); + MALI_CHECK_NO_ERROR(dump_mmu_page_table(session_data->page_directory, &info)); + args->size = info.register_writes_size + info.page_table_dump_size; + MALI_SUCCESS; +} + +_mali_osk_errcode_t _mali_ukk_dump_mmu_page_table( _mali_uk_dump_mmu_page_table_s * args ) +{ + struct dump_info info = { 0, 0, 0, NULL }; + struct mali_session_data * session_data; + + MALI_DEBUG_ASSERT_POINTER(args); + MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); + MALI_CHECK_NON_NULL(args->buffer, _MALI_OSK_ERR_INVALID_ARGS); + + session_data = (struct mali_session_data *)(args->ctx); + + info.buffer_left = args->size; + info.buffer = args->buffer; + + args->register_writes = info.buffer; + MALI_CHECK_NO_ERROR(dump_mmu_registers(session_data->page_directory, &info)); + + args->page_table_dump = info.buffer; + MALI_CHECK_NO_ERROR(dump_mmu_page_table(session_data->page_directory, &info)); + + args->register_writes_size = info.register_writes_size; + args->page_table_dump_size = info.page_table_dump_size; + + MALI_SUCCESS; +} diff --git a/drivers/media/video/samsung/mali/common/mali_mmu_page_directory.h b/drivers/media/video/samsung/mali/common/mali_mmu_page_directory.h new file mode 100644 index 0000000..8aababe --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_mmu_page_directory.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MALI_MMU_PAGE_DIRECTORY_H__ +#define __MALI_MMU_PAGE_DIRECTORY_H__ + +#include "mali_osk.h" + +/** + * Size of an MMU page in bytes + */ +#define MALI_MMU_PAGE_SIZE 0x1000 + +/* + * Size of the address space referenced by a page table page + */ +#define MALI_MMU_VIRTUAL_PAGE_SIZE 0x400000 /* 4 MiB */ + +/** + * Page directory index from address + * Calculates the page directory index from the given address + */ +#define MALI_MMU_PDE_ENTRY(address) (((address)>>22) & 0x03FF) + +/** + * Page table index from address + * Calculates the page table index from the given address + */ +#define MALI_MMU_PTE_ENTRY(address) (((address)>>12) & 0x03FF) + +/** + * Extract the memory address from an PDE/PTE entry + */ +#define MALI_MMU_ENTRY_ADDRESS(value) ((value) & 0xFFFFFC00) + +#define MALI_INVALID_PAGE ((u32)(~0)) + +/** + * + */ +typedef enum mali_mmu_entry_flags +{ + MALI_MMU_FLAGS_PRESENT = 0x01, + MALI_MMU_FLAGS_READ_PERMISSION = 0x02, + MALI_MMU_FLAGS_WRITE_PERMISSION = 0x04, + MALI_MMU_FLAGS_MASK = 0x07 +} mali_mmu_entry_flags; + + +struct mali_page_directory +{ + u32 page_directory; /**< Physical address of the memory session's page directory */ + mali_io_address page_directory_mapped; /**< Pointer to the mapped version of the page directory into the kernel's address space */ + + mali_io_address page_entries_mapped[1024]; /**< Pointers to the page tables which exists in the page directory mapped into the kernel's address space */ + u32 page_entries_usage_count[1024]; /**< Tracks usage count of the page table pages, so they can be releases on the last reference */ +}; + +/* Map Mali virtual address space (i.e. ensure page tables exist for the virtual range) */ +_mali_osk_errcode_t mali_mmu_pagedir_map(struct mali_page_directory *pagedir, u32 mali_address, u32 size); +_mali_osk_errcode_t mali_mmu_pagedir_unmap(struct mali_page_directory *pagedir, u32 mali_address, u32 size); + +/* Back virtual address space with actual pages. Assumes input is contiguous and 4k aligned. */ +void mali_mmu_pagedir_update(struct mali_page_directory *pagedir, u32 mali_address, u32 phys_address, u32 size); + +u32 mali_page_directory_get_phys_address(struct mali_page_directory *pagedir, u32 index); + +u32 mali_allocate_empty_page(void); +void mali_free_empty_page(u32 address); +_mali_osk_errcode_t mali_create_fault_flush_pages(u32 *page_directory, u32 *page_table, u32 *data_page); +void mali_destroy_fault_flush_pages(u32 *page_directory, u32 *page_table, u32 *data_page); + +struct mali_page_directory *mali_mmu_pagedir_alloc(void); +void mali_mmu_pagedir_free(struct mali_page_directory *pagedir); + +#endif /* __MALI_MMU_PAGE_DIRECTORY_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_osk.h b/drivers/media/video/samsung/mali/common/mali_osk.h index 72d851d..e32d15d 100644 --- a/drivers/media/video/samsung/mali/common/mali_osk.h +++ b/drivers/media/video/samsung/mali/common/mali_osk.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -165,9 +165,6 @@ typedef void (*_mali_osk_irq_bhandler_t)( void * arg ); * This is public for allocation on stack. On systems that support it, this is just a single 32-bit value. * On others, it could be encapsulating an object stored elsewhere. * - * Even though the structure has space for a u32, the counters will only - * represent signed 24-bit integers. - * * Regardless of implementation, the \ref _mali_osk_atomic functions \b must be used * for all accesses to the variable's value, even if atomicity is not required. * Do not access u.val or u.obj directly. @@ -186,6 +183,40 @@ typedef struct /** @defgroup _mali_osk_lock OSK Mutual Exclusion Locks * @{ */ + +/** @brief OSK Mutual Exclusion Lock ordered list + * + * This lists the various types of locks in the system and is used to check + * that locks are taken in the correct order. + * + * Holding more than one lock of the same order at the same time is not + * allowed. + * + */ +typedef enum +{ + _MALI_OSK_LOCK_ORDER_LAST = 0, + + _MALI_OSK_LOCK_ORDER_PM_EXECUTE, + _MALI_OSK_LOCK_ORDER_UTILIZATION, + _MALI_OSK_LOCK_ORDER_L2_COUNTER, + _MALI_OSK_LOCK_ORDER_PROFILING, + _MALI_OSK_LOCK_ORDER_L2_COMMAND, + _MALI_OSK_LOCK_ORDER_PM_CORE_STATE, + _MALI_OSK_LOCK_ORDER_GROUP, + _MALI_OSK_LOCK_ORDER_SCHEDULER, + + _MALI_OSK_LOCK_ORDER_DESCRIPTOR_MAP, + _MALI_OSK_LOCK_ORDER_MEM_PT_CACHE, + _MALI_OSK_LOCK_ORDER_MEM_INFO, + _MALI_OSK_LOCK_ORDER_MEM_SESSION, + + _MALI_OSK_LOCK_ORDER_SESSIONS, + + _MALI_OSK_LOCK_ORDER_FIRST +} _mali_osk_lock_order_t; + + /** @brief OSK Mutual Exclusion Lock flags type * * Flags are supplied at the point where the Lock is initialized. Each flag can @@ -271,6 +302,17 @@ typedef enum /** @brief Private type for Mutual Exclusion lock objects */ typedef struct _mali_osk_lock_t_struct _mali_osk_lock_t; + +#ifdef DEBUG +/** @brief Macro for asserting that the current thread holds a given lock + */ +#define MALI_DEBUG_ASSERT_LOCK_HELD(l) MALI_DEBUG_ASSERT(_mali_osk_lock_get_owner(l) == _mali_osk_get_tid()); + +/** @brief returns a lock's owner (thread id) if debugging is enabled + */ +u32 _mali_osk_lock_get_owner( _mali_osk_lock_t *lock ); +#endif + /** @} */ /* end group _mali_osk_lock */ /** @defgroup _mali_osk_low_level_memory OSK Low-level Memory Operations @@ -368,7 +410,6 @@ typedef struct _mali_osk_notification_queue_t_struct _mali_osk_notification_queu /** @brief Public notification data object type */ typedef struct _mali_osk_notification_t_struct { - u32 magic_code; u32 notification_type; /**< The notification type */ u32 result_buffer_size; /**< Size of the result buffer to copy to user space */ void * result_buffer; /**< Buffer containing any type specific data */ @@ -527,20 +568,35 @@ typedef struct _mali_osk_list_s typedef enum _mali_osk_resource_type { RESOURCE_TYPE_FIRST =0, /**< Duplicate resource marker for the first resource*/ + MEMORY =0, /**< Physically contiguous memory block, not managed by the OS */ OS_MEMORY =1, /**< Memory managed by and shared with the OS */ - MALI200 =3, /**< Mali200 Programmable Fragment Shader */ - MALIGP2 =4, /**< MaliGP2 Programmable Vertex Shader */ - MMU =5, /**< Mali MMU (Memory Management Unit) */ - FPGA_FRAMEWORK =6, /**< Mali registers specific to FPGA implementations */ - MALI400L2 =7, /**< Mali400 L2 Cache */ - MALI300L2 =7, /**< Mali300 L2 Cache */ - MALI400GP =8, /**< Mali400 Programmable Vertex Shader Core */ - MALI300GP =8, /**< Mali300 Programmable Vertex Shader Core */ - MALI400PP =9, /**< Mali400 Programmable Fragment Shader Core */ - MALI300PP =9, /**< Mali300 Programmable Fragment Shader Core */ - MEM_VALIDATION =10, /**< External Memory Validator */ - PMU =11, /**< Power Manangement Unit */ + + MALI_PP =2, /**< Mali Pixel Processor core */ + MALI450PP =2, /**< Compatibility option */ + MALI400PP =2, /**< Compatibility option */ + MALI300PP =2, /**< Compatibility option */ + MALI200 =2, /**< Compatibility option */ + + MALI_GP =3, /**< Mali Geometry Processor core */ + MALI450GP =3, /**< Compatibility option */ + MALI400GP =3, /**< Compatibility option */ + MALI300GP =3, /**< Compatibility option */ + MALIGP2 =3, /**< Compatibility option */ + + MMU =4, /**< Mali MMU (Memory Management Unit) */ + + FPGA_FRAMEWORK =5, /**< Mali registers specific to FPGA implementations */ + + MALI_L2 =6, /**< Mali Level 2 cache core */ + MALI450L2 =6, /**< Compatibility option */ + MALI400L2 =6, /**< Compatibility option */ + MALI300L2 =6, /**< Compatibility option */ + + MEM_VALIDATION =7, /**< External Memory Validator */ + + PMU =8, /**< Power Manangement Unit */ + RESOURCE_TYPE_COUNT /**< The total number of known resources */ } _mali_osk_resource_type_t; @@ -726,11 +782,6 @@ void _mali_osk_atomic_dec( _mali_osk_atomic_t *atom ); /** @brief Decrement an atomic counter, return new value * - * Although the value returned is a u32, only numbers with signed 24-bit - * precision (sign extended to u32) are returned. - * - * @note It is an error to decrement the counter beyond -(1<<23) - * * @param atom pointer to an atomic counter * @return The new value, after decrement */ u32 _mali_osk_atomic_dec_return( _mali_osk_atomic_t *atom ); @@ -744,19 +795,11 @@ void _mali_osk_atomic_inc( _mali_osk_atomic_t *atom ); /** @brief Increment an atomic counter, return new value * - * Although the value returned is a u32, only numbers with signed 24-bit - * precision (sign extended to u32) are returned. - * - * @note It is an error to increment the counter beyond (1<<23)-1 - * * @param atom pointer to an atomic counter */ u32 _mali_osk_atomic_inc_return( _mali_osk_atomic_t *atom ); /** @brief Initialize an atomic counter * - * The counters have storage for signed 24-bit integers. Initializing to signed - * values requiring more than 24-bits storage will fail. - * * @note the parameter required is a u32, and so signed integers should be * cast to u32. * @@ -769,9 +812,6 @@ _mali_osk_errcode_t _mali_osk_atomic_init( _mali_osk_atomic_t *atom, u32 val ); /** @brief Read a value from an atomic counter * - * Although the value returned is a u32, only numbers with signed 24-bit - * precision (sign extended to u32) are returned. - * * This can only be safely used to determine the value of the counter when it * is guaranteed that other threads will not be modifying the counter. This * makes its usefulness limited. @@ -1624,6 +1664,41 @@ u64 _mali_osk_time_get_ns( void ); u32 _mali_osk_clz( u32 val ); /** @} */ /* end group _mali_osk_math */ +/** @defgroup _mali_osk_wait_queue OSK Wait Queue functionality + * @{ */ +/** @brief Private type for wait queue objects */ +typedef struct _mali_osk_wait_queue_t_struct _mali_osk_wait_queue_t; + +/** @brief Initialize an empty Wait Queue */ +_mali_osk_wait_queue_t* _mali_osk_wait_queue_init( void ); + +/** @brief Sleep if condition is false + * + * @param queue the queue to use + * @param condition function pointer to a boolean function + * + * Put thread to sleep if the given \a codition function returns false. When + * being asked to wake up again, the condition will be re-checked and the + * thread only woken up if the condition is now true. + */ +void _mali_osk_wait_queue_wait_event( _mali_osk_wait_queue_t *queue, mali_bool (*condition)(void) ); + +/** @brief Wake up all threads in wait queue if their respective conditions are + * true + * + * @param queue the queue whose threads should be woken up + * + * Wake up all threads in wait queue \a queue whose condition is now true. + */ +void _mali_osk_wait_queue_wake_up( _mali_osk_wait_queue_t *queue ); + +/** @brief terminate a wait queue + * + * @param queue the queue to terminate. + */ +void _mali_osk_wait_queue_term( _mali_osk_wait_queue_t *queue ); +/** @} */ /* end group _mali_osk_wait_queue */ + /** @addtogroup _mali_osk_miscellaneous * @{ */ @@ -1647,6 +1722,7 @@ void _mali_osk_dbgmsg( const char *fmt, ... ); * @param size the total number of bytes allowed to write to \a buf * @param fmt a _mali_osu_vsnprintf() style format string * @param ... a variable-number of parameters suitable for \a fmt + * @return The number of bytes written to \a buf */ u32 _mali_osk_snprintf( char *buf, u32 size, const char *fmt, ... ); @@ -1685,13 +1761,19 @@ u32 _mali_osk_get_pid(void); */ u32 _mali_osk_get_tid(void); -void _mali_osk_profiling_add_event(u32 event_id, u32 data0); -void _mali_osk_profiling_add_counter(u32 event_id, u32 data0); -int _mali_osk_counter_event(u32 counter, u32 event); -extern u32 counter_table[]; +/** @brief Enable OS controlled runtime power management + */ +void _mali_osk_pm_dev_enable(void); -/** @} */ /* end group _mali_osk_miscellaneous */ +/** @brief Tells the OS that device is now idle + */ +_mali_osk_errcode_t _mali_osk_pm_dev_idle(void); +/** @brief Tells the OS that the device is about to become active + */ +_mali_osk_errcode_t _mali_osk_pm_dev_activate(void); + +/** @} */ /* end group _mali_osk_miscellaneous */ /** @} */ /* end group osuapi */ diff --git a/drivers/media/video/samsung/mali/common/mali_osk_list.h b/drivers/media/video/samsung/mali/common/mali_osk_list.h index 3a562bb..a8d15f2 100644 --- a/drivers/media/video/samsung/mali/common/mali_osk_list.h +++ b/drivers/media/video/samsung/mali/common/mali_osk_list.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2011 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. diff --git a/drivers/media/video/samsung/mali/common/mali_osk_mali.h b/drivers/media/video/samsung/mali/common/mali_osk_mali.h index 0b1d13a..427fcc8 100644 --- a/drivers/media/video/samsung/mali/common/mali_osk_mali.h +++ b/drivers/media/video/samsung/mali/common/mali_osk_mali.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -26,36 +26,6 @@ extern "C" /** @addtogroup _mali_osk_miscellaneous * @{ */ -/** @brief Initialize the OSK layer - * - * This function is used to setup any initialization of OSK functionality, if - * required. - * - * This must be the first function called from the common code, specifically, - * from the common code entry-point, mali_kernel_constructor. - * - * The OS-integration into the OS's kernel must handle calling of - * mali_kernel_constructor when the device driver is loaded. - * - * @return _MALI_OSK_ERR_OK on success, or a suitable _mali_osk_errcode_t on - * failure. - */ -_mali_osk_errcode_t _mali_osk_init( void ); - -/** @brief Terminate the OSK layer - * - * This function is used to terminate any resources initialized by - * _mali_osk_init. - * - * This must be the last function called from the common code, specifically, - * from the common code closedown function, mali_kernel_destructor, and the - * error path in mali_kernel_constructor. - * - * The OS-integration into the OS's kernel must handle calling of - * mali_kernel_destructor when the device driver is terminated. - */ -void _mali_osk_term( void ); - /** @brief Read the Mali Resource configuration * * Populates a _mali_arch_resource_t array from configuration settings, which diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_profiling.h b/drivers/media/video/samsung/mali/common/mali_osk_profiling.h index eb1e6c2..fd9a8fb 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_profiling.h +++ b/drivers/media/video/samsung/mali/common/mali_osk_profiling.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -8,31 +8,34 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __MALI_KERNEL_PROFILING_H__ -#define __MALI_KERNEL_PROFILING_H__ +#ifndef __MALI_OSK_PROFILING_H__ +#define __MALI_OSK_PROFILING_H__ #if MALI_TIMELINE_PROFILING_ENABLED -#include "cinstr/mali_cinstr_profiling_events_m200.h" +#if defined (CONFIG_TRACEPOINTS) && !MALI_INTERNAL_TIMELINE_PROFILING_ENABLED +#include "mali_linux_trace.h" +#endif /* CONFIG_TRACEPOINTS && !MALI_INTERNAL_TIMELINE_PROFILING_ENABLED */ + +#include "mali_profiling_events.h" #define MALI_PROFILING_MAX_BUFFER_ENTRIES 1048576 +#define MALI_PROFILING_NO_HW_COUNTER = ((u32)-1) + +/** @defgroup _mali_osk_profiling External profiling connectivity + * @{ */ + /** * Initialize the profiling module. * @return _MALI_OSK_ERR_OK on success, otherwise failure. */ -_mali_osk_errcode_t _mali_profiling_init(mali_bool auto_start); +_mali_osk_errcode_t _mali_osk_profiling_init(mali_bool auto_start); /* * Terminate the profiling module. */ -void _mali_profiling_term(void); - -/** Add a counter event - * @param event_id - Magic counter id - * @param data0 - Value of counter - */ -void _mali_profiling_add_counter(u32 event_id, u32 data0); +void _mali_osk_profiling_term(void); /** * Start recording profiling data @@ -43,7 +46,7 @@ void _mali_profiling_add_counter(u32 event_id, u32 data0); * @param limit The desired maximum number of events to record on input, the actual maximum on output. * @return _MALI_OSK_ERR_OK on success, otherwise failure. */ -_mali_osk_errcode_t _mali_profiling_start(u32 * limit); +_mali_osk_errcode_t _mali_osk_profiling_start(u32 * limit); /** * Add an profiling event @@ -56,7 +59,35 @@ _mali_osk_errcode_t _mali_profiling_start(u32 * limit); * @param data4 Fifth data parameter, depending on event_id specified. * @return _MALI_OSK_ERR_OK on success, otherwise failure. */ -_mali_osk_errcode_t _mali_profiling_add_event(u32 event_id, u32 data0, u32 data1, u32 data2, u32 data3, u32 data4); +#if defined (CONFIG_TRACEPOINTS) && !MALI_INTERNAL_TIMELINE_PROFILING_ENABLED +/* Call Linux tracepoint directly */ +#define _mali_osk_profiling_add_event(event_id, data0, data1, data2, data3, data4) trace_mali_timeline_event((event_id), (data0), (data1), (data2), (data3), (data4)) +#else +/* Internal profiling is handled like a plain function call */ +void _mali_osk_profiling_add_event(u32 event_id, u32 data0, u32 data1, u32 data2, u32 data3, u32 data4); +#endif + +/** + * Report a hardware counter event. + * + * @param counter_id The ID of the counter. + * @param value The value of the counter. + */ + +#if defined (CONFIG_TRACEPOINTS) && !MALI_INTERNAL_TIMELINE_PROFILING_ENABLED +/* Call Linux tracepoint directly */ +#define _mali_osk_profiling_report_hw_counter(counter_id, value) trace_mali_hw_counter(counter_id, value) +#else +/* Internal profiling is handled like a plain function call */ +void _mali_osk_profiling_report_hw_counter(u32 counter_id, u32 value); +#endif + +/** + * Report SW counters + * + * @param counters array of counter values + */ +void _mali_osk_profiling_report_sw_counters(u32 *counters); /** * Stop recording profiling data @@ -64,14 +95,14 @@ _mali_osk_errcode_t _mali_profiling_add_event(u32 event_id, u32 data0, u32 data1 * @param count Returns the number of recorded events. * @return _MALI_OSK_ERR_OK on success, otherwise failure. */ -_mali_osk_errcode_t _mali_profiling_stop(u32 * count); +_mali_osk_errcode_t _mali_osk_profiling_stop(u32 * count); /** * Retrieves the number of events that can be retrieved * * @return The number of recorded events that can be retrieved. */ -u32 _mali_profiling_get_count(void); +u32 _mali_osk_profiling_get_count(void); /** * Retrieve an event @@ -81,7 +112,8 @@ u32 _mali_profiling_get_count(void); * @param event_id The event ID for the retrieved event will be stored here. * @param data The 5 data values for the retrieved event will be stored here. * @return _MALI_OSK_ERR_OK on success, otherwise failure. - */_mali_osk_errcode_t _mali_profiling_get_event(u32 index, u64* timestamp, u32* event_id, u32 data[5]); + */ +_mali_osk_errcode_t _mali_osk_profiling_get_event(u32 index, u64* timestamp, u32* event_id, u32 data[5]); /** * Clear the recorded buffer. @@ -90,38 +122,26 @@ u32 _mali_profiling_get_count(void); * * @return _MALI_OSK_ERR_OK on success, otherwise failure. */ -_mali_osk_errcode_t _mali_profiling_clear(void); +_mali_osk_errcode_t _mali_osk_profiling_clear(void); /** * Checks if a recording of profiling data is in progress * * @return MALI_TRUE if recording of profiling data is in progress, MALI_FALSE if not */ -mali_bool _mali_profiling_is_recording(void); +mali_bool _mali_osk_profiling_is_recording(void); /** * Checks if profiling data is available for retrival * * @return MALI_TRUE if profiling data is avaiable, MALI_FALSE if not */ -mali_bool _mali_profiling_have_recording(void); +mali_bool _mali_osk_profiling_have_recording(void); -/** - * Enable or disable profiling events as default for new sessions (applications) - * - * @param enable MALI_TRUE if profiling events should be turned on, otherwise MALI_FALSE - */ -void _mali_profiling_set_default_enable_state(mali_bool enable); - -/** - * Get current default enable state for new sessions (applications) - * - * @return MALI_TRUE if profiling events should be turned on, otherwise MALI_FALSE - */ -mali_bool _mali_profiling_get_default_enable_state(void); +/** @} */ /* end group _mali_osk_profiling */ #endif /* MALI_TIMELINE_PROFILING_ENABLED */ -#endif /* __MALI_KERNEL_PROFILING_H__ */ +#endif /* __MALI_OSK_PROFILING_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_pm.c b/drivers/media/video/samsung/mali/common/mali_pm.c new file mode 100644 index 0000000..1ef3807 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pm.c @@ -0,0 +1,547 @@ +/* + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mali_pm.h" +#include "mali_kernel_common.h" +#include "mali_osk.h" +#include "mali_gp_scheduler.h" +#include "mali_pp_scheduler.h" +#include "mali_platform.h" +#include "mali_kernel_utilization.h" +#include "mali_kernel_core.h" +#include "mali_group.h" + +#define MALI_PM_LIGHT_SLEEP_TIMEOUT 1000 + +enum mali_pm_scheme +{ + MALI_PM_SCHEME_DYNAMIC, + MALI_PM_SCHEME_OS_SUSPENDED, + MALI_PM_SCHEME_ALWAYS_ON +}; + +enum mali_pm_level +{ + MALI_PM_LEVEL_1_ON, + MALI_PM_LEVEL_2_STANDBY, + MALI_PM_LEVEL_3_LIGHT_SLEEP, + MALI_PM_LEVEL_4_DEEP_SLEEP +}; +static _mali_osk_lock_t *mali_pm_lock_set_next_state; +static _mali_osk_lock_t *mali_pm_lock_set_core_states; +static _mali_osk_lock_t *mali_pm_lock_execute_state_change; +static _mali_osk_irq_t *wq_irq; + +static _mali_osk_timer_t *idle_timer = NULL; +static mali_bool idle_timer_running = MALI_FALSE; +static u32 mali_pm_event_number = 0; + +static u32 num_active_gps = 0; +static u32 num_active_pps = 0; + +static enum mali_pm_scheme current_scheme = MALI_PM_SCHEME_DYNAMIC; +static enum mali_pm_level current_level = MALI_PM_LEVEL_1_ON; +static enum mali_pm_level next_level_dynamic = MALI_PM_LEVEL_2_STANDBY; /* Should be the state we go to when we go out of MALI_PM_SCHEME_ALWAYS_ON during init */ + + + +static _mali_osk_errcode_t mali_pm_upper_half(void *data); +static void mali_pm_bottom_half(void *data); +static void mali_pm_powerup(void); +static void mali_pm_powerdown(mali_power_mode power_mode); + +static void timeout_light_sleep(void* arg); +#if 0 +/* Deep sleep timout not supported */ +static void timeout_deep_sleep(void* arg); +#endif +static u32 mali_pm_event_number_get(void); +static void mali_pm_event(enum mali_pm_event pm_event, mali_bool schedule_work, u32 timer_time ); + +_mali_osk_errcode_t mali_pm_initialize(void) +{ + mali_pm_lock_execute_state_change = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_ORDERED |_MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_PM_EXECUTE); + + if (NULL != mali_pm_lock_execute_state_change ) + { + mali_pm_lock_set_next_state = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ONELOCK| _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ |_MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_LAST); + + if (NULL != mali_pm_lock_set_next_state) + { + mali_pm_lock_set_core_states = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_PM_CORE_STATE); + + if (NULL != mali_pm_lock_set_core_states) + { + idle_timer = _mali_osk_timer_init(); + if (NULL != idle_timer) + { + wq_irq = _mali_osk_irq_init(_MALI_OSK_IRQ_NUMBER_PMM, + mali_pm_upper_half, + mali_pm_bottom_half, + NULL, + NULL, + (void *)NULL, + "Mali PM deferred work"); + if (NULL != wq_irq) + { + if (_MALI_OSK_ERR_OK == mali_platform_init()) + { +#if MALI_PMM_RUNTIME_JOB_CONTROL_ON + _mali_osk_pm_dev_enable(); + mali_pm_powerup(); +#endif + return _MALI_OSK_ERR_OK; + } + + _mali_osk_irq_term(wq_irq); + } + + _mali_osk_timer_del(idle_timer); + _mali_osk_timer_term(idle_timer); + } + _mali_osk_lock_term(mali_pm_lock_set_core_states); + } + _mali_osk_lock_term(mali_pm_lock_set_next_state); + } + _mali_osk_lock_term(mali_pm_lock_execute_state_change); + } + + return _MALI_OSK_ERR_FAULT; +} + +void mali_pm_terminate(void) +{ + mali_platform_deinit(); + _mali_osk_irq_term(wq_irq); + _mali_osk_timer_del(idle_timer); + _mali_osk_timer_term(idle_timer); + _mali_osk_lock_term(mali_pm_lock_execute_state_change); + _mali_osk_lock_term(mali_pm_lock_set_next_state); + _mali_osk_lock_term(mali_pm_lock_set_core_states); +} + + +inline void mali_pm_lock(void) +{ + _mali_osk_lock_wait(mali_pm_lock_set_next_state, _MALI_OSK_LOCKMODE_RW); +} + +inline void mali_pm_unlock(void) +{ + _mali_osk_lock_signal(mali_pm_lock_set_next_state, _MALI_OSK_LOCKMODE_RW); +} + +inline void mali_pm_execute_state_change_lock(void) +{ + _mali_osk_lock_wait(mali_pm_lock_execute_state_change,_MALI_OSK_LOCKMODE_RW); +} + +inline void mali_pm_execute_state_change_unlock(void) +{ + _mali_osk_lock_signal(mali_pm_lock_execute_state_change, _MALI_OSK_LOCKMODE_RW); +} + +static void mali_pm_powerup(void) +{ + MALI_DEBUG_PRINT(3, ("Mali PM: Setting GPU power mode to MALI_POWER_MODE_ON\n")); + mali_platform_power_mode_change(MALI_POWER_MODE_ON); + +#if MALI_PMM_RUNTIME_JOB_CONTROL_ON + + /* Aquire our reference */ + MALI_DEBUG_PRINT(4, ("Mali PM: Getting device PM reference (=> requesting MALI_POWER_MODE_ON)\n")); + _mali_osk_pm_dev_activate(); +#endif + + mali_group_power_on(); +} + +static void mali_pm_powerdown(mali_power_mode power_mode) +{ + if ( (MALI_PM_LEVEL_1_ON == current_level) || (MALI_PM_LEVEL_2_STANDBY == current_level) ) + { + mali_group_power_off(); + } + mali_platform_power_mode_change(power_mode); + +#if MALI_PMM_RUNTIME_JOB_CONTROL_ON + _mali_osk_pm_dev_idle(); +#endif +} + +mali_bool mali_pm_is_powered_on(void) +{ + mali_bool is_on = MALI_TRUE; + + if( ! (MALI_PM_SCHEME_ALWAYS_ON == current_scheme || MALI_PM_SCHEME_DYNAMIC == current_scheme) ) + { + is_on = MALI_FALSE; + } + else if ( ! (MALI_PM_LEVEL_1_ON == current_level || MALI_PM_LEVEL_2_STANDBY == current_level)) + { + is_on = MALI_FALSE; + } + else if ( ! (MALI_PM_LEVEL_1_ON == next_level_dynamic || MALI_PM_LEVEL_2_STANDBY == next_level_dynamic)) + { + is_on = MALI_FALSE; + } + + return is_on; +} + +MALI_DEBUG_CODE( +static const char *state_as_string(enum mali_pm_level level) +{ + switch(level) + { + case MALI_PM_LEVEL_1_ON: + return "MALI_PM_LEVEL_1_ON"; + case MALI_PM_LEVEL_2_STANDBY: + return "MALI_PM_LEVEL_2_STANDBY"; + case MALI_PM_LEVEL_3_LIGHT_SLEEP: + return "MALI_PM_LEVEL_3_LIGHT_SLEEP"; + case MALI_PM_LEVEL_4_DEEP_SLEEP: + return "MALI_PM_LEVEL_4_DEEP_SLEEP"; + default: + return "UNKNOWN LEVEL"; + } +}); + +/* This could be used from another thread (work queue), if we need that */ +static void mali_pm_process_next(void) +{ + enum mali_pm_level pm_level_to_set; + + _mali_osk_lock_wait(mali_pm_lock_execute_state_change, _MALI_OSK_LOCKMODE_RW); + + pm_level_to_set = current_level; + + if (MALI_PM_SCHEME_DYNAMIC == current_scheme) + { + pm_level_to_set = next_level_dynamic; + + MALI_DEBUG_PRINT(4, ("Mali PM: Dynamic scheme; Changing Mali GPU power state from %s to: %s\n", state_as_string(current_level), state_as_string(pm_level_to_set))); + + if (current_level == pm_level_to_set) + { + goto end_function; /* early out, no change in power level */ + } + + /* Start timers according to new state, so we get STANDBY -> LIGHT_SLEEP -> DEEP_SLEEP */ + + if (MALI_TRUE == idle_timer_running) + { + /* There is an existing timeout, so delete it */ + _mali_osk_timer_del(idle_timer); + idle_timer_running = MALI_FALSE; + } + + /* Making sure that we turn on through the platform file + Since it was turned OFF directly through the platform file. + This might lead to double turn-on, but the plaform file supports that.*/ + if ( current_level == MALI_PM_LEVEL_4_DEEP_SLEEP) + { + mali_pm_powerup(); + mali_kernel_core_wakeup(); + + } + if (MALI_PM_LEVEL_1_ON == pm_level_to_set) + { + if (MALI_PM_LEVEL_2_STANDBY != current_level) + { + /* We only need to do anything if we came from one of the sleeping states */ + mali_pm_powerup(); + + /* Wake up Mali cores since we came from a sleep state */ + mali_kernel_core_wakeup(); + } + } + else if (MALI_PM_LEVEL_2_STANDBY == pm_level_to_set) + { + /* This is just an internal state, so we don't bother to report it to the platform file */ + idle_timer_running = MALI_TRUE; + _mali_osk_timer_setcallback(idle_timer, timeout_light_sleep, (void*) mali_pm_event_number_get()); + _mali_osk_timer_add(idle_timer, _mali_osk_time_mstoticks(MALI_PM_LIGHT_SLEEP_TIMEOUT)); + } + else if (MALI_PM_LEVEL_3_LIGHT_SLEEP == pm_level_to_set) + { + mali_pm_powerdown(MALI_POWER_MODE_LIGHT_SLEEP); + } + else if (MALI_PM_LEVEL_4_DEEP_SLEEP == pm_level_to_set) + { + MALI_DEBUG_PRINT(2, ("Mali PM: Setting GPU power mode to MALI_POWER_MODE_DEEP_SLEEP\n")); + mali_pm_powerdown(MALI_POWER_MODE_DEEP_SLEEP); + } + } + else if (MALI_PM_SCHEME_OS_SUSPENDED == current_scheme) + { + MALI_DEBUG_PRINT(4, ("Mali PM: OS scheme; Changing Mali GPU power state from %s to: %s\n", state_as_string(current_level), state_as_string(MALI_PM_LEVEL_4_DEEP_SLEEP))); + + pm_level_to_set = MALI_PM_LEVEL_4_DEEP_SLEEP; + + if (current_level == pm_level_to_set) + { + goto end_function; /* early out, no change in power level */ + } + + /* Cancel any timers */ + if (MALI_TRUE == idle_timer_running) + { + /* There is an existing timeout, so delete it */ + _mali_osk_timer_del(idle_timer); + idle_timer_running = MALI_FALSE; + } + + MALI_DEBUG_PRINT(2, ("Mali PM: Setting GPU power mode to MALI_POWER_MODE_DEEP_SLEEP\n")); + mali_pm_powerdown(MALI_POWER_MODE_DEEP_SLEEP); + next_level_dynamic = current_level; + } + else if (MALI_PM_SCHEME_ALWAYS_ON == current_scheme) + { + MALI_DEBUG_PRINT(4, ("Mali PM: Always on scheme; Changing Mali GPU power state from %s to: %s\n", state_as_string(current_level), state_as_string(MALI_PM_LEVEL_1_ON))); + + pm_level_to_set = MALI_PM_LEVEL_1_ON; + if (current_level == pm_level_to_set) + { + goto end_function; /* early out, no change in power level */ + } + + MALI_DEBUG_PRINT(2, ("Mali PM: Setting GPU power mode to MALI_POWER_MODE_ON\n")); + mali_pm_powerup(); + if (MALI_PM_LEVEL_2_STANDBY != current_level) + { + /* Wake up Mali cores since we came from a sleep state */ + mali_kernel_core_wakeup(); + } + } + else + { + MALI_PRINT_ERROR(("MALI PM: Illegal scheme")); + } + + current_level = pm_level_to_set; + +end_function: + _mali_osk_lock_signal(mali_pm_lock_execute_state_change, _MALI_OSK_LOCKMODE_RW); + +} + +void mali_pm_always_on(mali_bool enable) +{ + if (MALI_TRUE == enable) + { + /* The event is processed in current thread synchronously */ + mali_pm_event(MALI_PM_EVENT_SCHEME_ALWAYS_ON, MALI_FALSE, 0 ); + } + else + { + /* The event is processed in current thread synchronously */ + mali_pm_event(MALI_PM_EVENT_SCHEME_DYNAMIC_CONTROLL, MALI_FALSE, 0 ); + } +} + +static _mali_osk_errcode_t mali_pm_upper_half(void *data) +{ + /* not used */ + return _MALI_OSK_ERR_OK; +} + +static void mali_pm_bottom_half(void *data) +{ + mali_pm_process_next(); +} + +static u32 mali_pm_event_number_get(void) +{ + u32 retval; + + mali_pm_lock(); /* spinlock: mali_pm_lock_set_next_state */ + retval = ++mali_pm_event_number; + if (0==retval ) retval = ++mali_pm_event_number; + mali_pm_unlock(); + + return retval; +} + +static void mali_pm_event(enum mali_pm_event pm_event, mali_bool schedule_work, u32 timer_time ) +{ + mali_pm_lock(); /* spinlock: mali_pm_lock_set_next_state */ + /* Only timer events should set this variable, all other events must set it to zero. */ + if ( 0 != timer_time ) + { + MALI_DEBUG_ASSERT( (pm_event==MALI_PM_EVENT_TIMER_LIGHT_SLEEP) || (pm_event==MALI_PM_EVENT_TIMER_DEEP_SLEEP) ); + if ( mali_pm_event_number != timer_time ) + { + /* In this case there have been processed newer events since the timer event was set up. + If so we always ignore the timing event */ + mali_pm_unlock(); + return; + } + } + else + { + /* Delete possible ongoing timers + if ( (MALI_PM_LEVEL_2_STANDBY==current_level) || (MALI_PM_LEVEL_3_LIGHT_SLEEP==current_level) ) + { + _mali_osk_timer_del(idle_timer); + } + */ + } + mali_pm_event_number++; + switch (pm_event) + { + case MALI_PM_EVENT_CORES_WORKING: + next_level_dynamic = MALI_PM_LEVEL_1_ON; + MALI_DEBUG_ASSERT( MALI_PM_SCHEME_OS_SUSPENDED != current_scheme ); + break; + case MALI_PM_EVENT_CORES_IDLE: + next_level_dynamic = MALI_PM_LEVEL_2_STANDBY; + /*MALI_DEBUG_ASSERT( MALI_PM_SCHEME_OS_SUSPENDED != current_scheme );*/ + break; + case MALI_PM_EVENT_TIMER_LIGHT_SLEEP: + MALI_DEBUG_ASSERT( MALI_PM_SCHEME_ALWAYS_ON != current_scheme ); + MALI_DEBUG_ASSERT( MALI_PM_SCHEME_OS_SUSPENDED != current_scheme ); + next_level_dynamic = MALI_PM_LEVEL_3_LIGHT_SLEEP; + break; + case MALI_PM_EVENT_TIMER_DEEP_SLEEP: + MALI_DEBUG_ASSERT( MALI_PM_SCHEME_ALWAYS_ON != current_scheme ); + MALI_DEBUG_ASSERT( MALI_PM_SCHEME_OS_SUSPENDED != current_scheme ); + next_level_dynamic = MALI_PM_LEVEL_4_DEEP_SLEEP; + break; + case MALI_PM_EVENT_OS_SUSPEND: + MALI_DEBUG_ASSERT( MALI_PM_SCHEME_ALWAYS_ON != current_scheme ); + MALI_DEBUG_ASSERT( MALI_PM_SCHEME_OS_SUSPENDED != current_scheme ); + current_scheme = MALI_PM_SCHEME_OS_SUSPENDED; + next_level_dynamic = MALI_PM_LEVEL_4_DEEP_SLEEP; /* Dynamic scheme will go into level when we are resumed */ + break; + case MALI_PM_EVENT_OS_RESUME: + MALI_DEBUG_ASSERT(MALI_PM_SCHEME_OS_SUSPENDED == current_scheme ); + current_scheme = MALI_PM_SCHEME_DYNAMIC; + break; + case MALI_PM_EVENT_SCHEME_ALWAYS_ON: + MALI_DEBUG_ASSERT( MALI_PM_SCHEME_OS_SUSPENDED != current_scheme ); + current_scheme = MALI_PM_SCHEME_ALWAYS_ON; + break; + case MALI_PM_EVENT_SCHEME_DYNAMIC_CONTROLL: + MALI_DEBUG_ASSERT( MALI_PM_SCHEME_ALWAYS_ON == current_scheme || MALI_PM_SCHEME_DYNAMIC == current_scheme ); + current_scheme = MALI_PM_SCHEME_DYNAMIC; + break; + default: + MALI_DEBUG_PRINT_ERROR(("Unknown next state.")); + mali_pm_unlock(); + return; + } + mali_pm_unlock(); + + if (MALI_TRUE == schedule_work) + { + _mali_osk_irq_schedulework(wq_irq); + } + else + { + mali_pm_process_next(); + } +} + +static void timeout_light_sleep(void* arg) +{ + /* State change only if no newer power events have happend from the time in arg. + Actual work will be scheduled on worker thread. */ + mali_pm_event(MALI_PM_EVENT_TIMER_LIGHT_SLEEP, MALI_TRUE, (u32) arg); +} + +void mali_pm_core_event(enum mali_core_event core_event) +{ + mali_bool transition_working = MALI_FALSE; + mali_bool transition_idle = MALI_FALSE; + + _mali_osk_lock_wait(mali_pm_lock_set_core_states, _MALI_OSK_LOCKMODE_RW); + + switch (core_event) + { + case MALI_CORE_EVENT_GP_START: + if (num_active_pps + num_active_gps == 0) + { + transition_working = MALI_TRUE; + } + num_active_gps++; + break; + case MALI_CORE_EVENT_GP_STOP: + if (num_active_pps + num_active_gps == 1) + { + transition_idle = MALI_TRUE; + } + num_active_gps--; + break; + case MALI_CORE_EVENT_PP_START: + if (num_active_pps + num_active_gps == 0) + { + transition_working = MALI_TRUE; + } + num_active_pps++; + break; + case MALI_CORE_EVENT_PP_STOP: + if (num_active_pps + num_active_gps == 1) + { + transition_idle = MALI_TRUE; + } + num_active_pps--; + break; + } + + if (transition_working == MALI_TRUE) + { +#ifdef CONFIG_MALI400_GPU_UTILIZATION + mali_utilization_core_start(_mali_osk_time_get_ns()); +#endif + mali_pm_event(MALI_PM_EVENT_CORES_WORKING, MALI_FALSE, 0); /* process event in same thread */ + } + else if (transition_idle == MALI_TRUE) + { +#ifdef CONFIG_MALI400_GPU_UTILIZATION + mali_utilization_core_end(_mali_osk_time_get_ns()); +#endif + mali_pm_event(MALI_PM_EVENT_CORES_IDLE, MALI_FALSE, 0); /* process event in same thread */ + } + + _mali_osk_lock_signal(mali_pm_lock_set_core_states, _MALI_OSK_LOCKMODE_RW); +} + +void mali_pm_os_suspend(void) +{ + MALI_DEBUG_PRINT(2, ("Mali PM: OS suspending...\n")); + + mali_gp_scheduler_suspend(); + mali_pp_scheduler_suspend(); + mali_pm_event(MALI_PM_EVENT_OS_SUSPEND, MALI_FALSE, 0); /* process event in same thread */ + + MALI_DEBUG_PRINT(2, ("Mali PM: OS suspend completed\n")); +} + +void mali_pm_os_resume(void) +{ + MALI_DEBUG_PRINT(2, ("Mali PM: OS resuming...\n")); + + mali_pm_event(MALI_PM_EVENT_OS_RESUME, MALI_FALSE, 0); /* process event in same thread */ + mali_gp_scheduler_resume(); + mali_pp_scheduler_resume(); + + MALI_DEBUG_PRINT(2, ("Mali PM: OS resume completed\n")); +} + +void mali_pm_runtime_suspend(void) +{ + MALI_DEBUG_PRINT(2, ("Mali PM: OS runtime suspended\n")); +} + +void mali_pm_runtime_resume(void) +{ + MALI_DEBUG_PRINT(3, ("Mali PM: OS runtime resumed\n")); +} diff --git a/drivers/media/video/samsung/mali/common/mali_pm.h b/drivers/media/video/samsung/mali/common/mali_pm.h new file mode 100644 index 0000000..d4ccfde --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pm.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MALI_PM_H__ +#define __MALI_PM_H__ + +#include "mali_osk.h" + +enum mali_core_event +{ + MALI_CORE_EVENT_GP_START, + MALI_CORE_EVENT_GP_STOP, + MALI_CORE_EVENT_PP_START, + MALI_CORE_EVENT_PP_STOP +}; + +enum mali_pm_event +{ + MALI_PM_EVENT_CORES_WORKING, + MALI_PM_EVENT_CORES_IDLE, + MALI_PM_EVENT_TIMER_LIGHT_SLEEP, + MALI_PM_EVENT_TIMER_DEEP_SLEEP, + MALI_PM_EVENT_OS_SUSPEND, + MALI_PM_EVENT_OS_RESUME, + MALI_PM_EVENT_SCHEME_ALWAYS_ON, + MALI_PM_EVENT_SCHEME_DYNAMIC_CONTROLL, +}; + +_mali_osk_errcode_t mali_pm_initialize(void); +void mali_pm_terminate(void); +void mali_pm_always_on(mali_bool enable); + +void mali_pm_lock(void); +void mali_pm_unlock(void); +void mali_pm_execute_state_change_lock(void); + +void mali_pm_execute_state_change_unlock(void); + +mali_bool mali_pm_is_powered_on(void); + +void mali_pm_core_event(enum mali_core_event core_event); + +void mali_pm_os_suspend(void); +void mali_pm_os_resume(void); +void mali_pm_runtime_suspend(void); +void mali_pm_runtime_resume(void); + + +#endif /* __MALI_PM_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_pmu.c b/drivers/media/video/samsung/mali/common/mali_pmu.c new file mode 100644 index 0000000..348b5dc --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pmu.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** + * @file mali_pmu.c + * Mali driver functions for Mali 400 PMU hardware + */ +#include "mali_hw_core.h" +#include "mali_pmu.h" +#include "mali_pp.h" +#include "mali_kernel_common.h" +#include "mali_osk.h" + +static u32 mali_pmu_detect_mask(u32 number_of_pp_cores, u32 number_of_l2_caches); + +/** @brief MALI inbuilt PMU hardware info and PMU hardware has knowledge of cores power mask + */ +struct mali_pmu_core +{ + struct mali_hw_core hw_core; + u32 mali_registered_cores_power_mask; +}; + +static struct mali_pmu_core *mali_global_pmu_core = NULL; + +/** @brief Register layout for hardware PMU + */ +typedef enum { + PMU_REG_ADDR_MGMT_POWER_UP = 0x00, /*< Power up register */ + PMU_REG_ADDR_MGMT_POWER_DOWN = 0x04, /*< Power down register */ + PMU_REG_ADDR_MGMT_STATUS = 0x08, /*< Core sleep status register */ + PMU_REG_ADDR_MGMT_INT_MASK = 0x0C, /*< Interrupt mask register */ + PMU_REGISTER_ADDRESS_SPACE_SIZE = 0x10, /*< Size of register space */ +} pmu_reg_addr_mgmt_addr; + +struct mali_pmu_core *mali_pmu_create(_mali_osk_resource_t *resource, u32 number_of_pp_cores, u32 number_of_l2_caches) +{ + struct mali_pmu_core* pmu; + + MALI_DEBUG_ASSERT(NULL == mali_global_pmu_core); + MALI_DEBUG_PRINT(2, ("Mali PMU: Creating Mali PMU core\n")); + + pmu = (struct mali_pmu_core *)_mali_osk_malloc(sizeof(struct mali_pmu_core)); + if (NULL != pmu) + { + pmu->mali_registered_cores_power_mask = mali_pmu_detect_mask(number_of_pp_cores, number_of_l2_caches); + if (_MALI_OSK_ERR_OK == mali_hw_core_create(&pmu->hw_core, resource, PMU_REGISTER_ADDRESS_SPACE_SIZE)) + { + if (_MALI_OSK_ERR_OK == mali_pmu_reset(pmu)) + { + mali_global_pmu_core = pmu; + return pmu; + } + mali_hw_core_delete(&pmu->hw_core); + } + _mali_osk_free(pmu); + } + + return NULL; +} + +void mali_pmu_delete(struct mali_pmu_core *pmu) +{ + MALI_DEBUG_ASSERT_POINTER(pmu); + + mali_hw_core_delete(&pmu->hw_core); + _mali_osk_free(pmu); + pmu = NULL; +} + +_mali_osk_errcode_t mali_pmu_reset(struct mali_pmu_core *pmu) +{ + /* Don't use interrupts - just poll status */ + mali_hw_core_register_write(&pmu->hw_core, PMU_REG_ADDR_MGMT_INT_MASK, 0); + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t mali_pmu_powerdown_all(struct mali_pmu_core *pmu) +{ + u32 stat; + u32 timeout; + + MALI_DEBUG_ASSERT_POINTER(pmu); + MALI_DEBUG_ASSERT( pmu->mali_registered_cores_power_mask != 0 ); + MALI_DEBUG_PRINT( 4, ("Mali PMU: power down (0x%08X)\n", pmu->mali_registered_cores_power_mask) ); + + mali_hw_core_register_write(&pmu->hw_core, PMU_REG_ADDR_MGMT_POWER_DOWN, pmu->mali_registered_cores_power_mask); + + /* Wait for cores to be powered down (100 x 100us = 100ms) */ + timeout = 100; + do + { + /* Get status of sleeping cores */ + stat = mali_hw_core_register_read(&pmu->hw_core, PMU_REG_ADDR_MGMT_STATUS); + stat &= pmu->mali_registered_cores_power_mask; + if( stat == pmu->mali_registered_cores_power_mask ) break; /* All cores we wanted are now asleep */ + _mali_osk_time_ubusydelay(100); + timeout--; + } while( timeout > 0 ); + + if( timeout == 0 ) + { + return _MALI_OSK_ERR_TIMEOUT; + } + + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t mali_pmu_powerup_all(struct mali_pmu_core *pmu) +{ + u32 stat; + u32 timeout; + + MALI_DEBUG_ASSERT_POINTER(pmu); + MALI_DEBUG_ASSERT( pmu->mali_registered_cores_power_mask != 0 ); /* Shouldn't be zero */ + MALI_DEBUG_PRINT( 4, ("Mali PMU: power up (0x%08X)\n", pmu->mali_registered_cores_power_mask) ); + + mali_hw_core_register_write(&pmu->hw_core, PMU_REG_ADDR_MGMT_POWER_UP, pmu->mali_registered_cores_power_mask); + + /* Wait for cores to be powered up (100 x 100us = 100ms) */ + timeout = 100; + do + { + /* Get status of sleeping cores */ + stat = mali_hw_core_register_read(&pmu->hw_core,PMU_REG_ADDR_MGMT_STATUS); + stat &= pmu->mali_registered_cores_power_mask; + if( stat == 0 ) break; /* All cores we wanted are now awake */ + _mali_osk_time_ubusydelay(100); + timeout--; + } while( timeout > 0 ); + + if( timeout == 0 ) + { + return _MALI_OSK_ERR_TIMEOUT; + } + + return _MALI_OSK_ERR_OK; +} + +struct mali_pmu_core *mali_pmu_get_global_pmu_core(void) +{ + return mali_global_pmu_core; +} + +static u32 mali_pmu_detect_mask(u32 number_of_pp_cores, u32 number_of_l2_caches) +{ + u32 mask = 0; + + if (number_of_l2_caches == 1) + { + /* Mali-300 or Mali-400 */ + u32 i; + + /* GP */ + mask = 0x01; + + /* L2 cache */ + mask |= 0x01<<1; + + /* Set bit for each PP core */ + for (i = 0; i < number_of_pp_cores; i++) + { + mask |= 0x01<<(i+2); + } + } + else if (number_of_l2_caches > 1) + { + /* Mali-450 */ + + /* GP (including its L2 cache) */ + mask = 0x01; + + /* There is always at least one PP (including its L2 cache) */ + mask |= 0x01<<1; + + /* Additional PP cores in same L2 cache */ + if (number_of_pp_cores >= 2) + { + mask |= 0x01<<2; + } + + /* Additional PP cores in a third L2 cache */ + if (number_of_pp_cores >= 5) + { + mask |= 0x01<<3; + } + } + + MALI_DEBUG_PRINT(4, ("Mali PMU: Power mask is 0x%08X (%u + %u)\n", mask, number_of_pp_cores, number_of_l2_caches)); + + return mask; +} diff --git a/drivers/media/video/samsung/mali/common/mali_pmu.h b/drivers/media/video/samsung/mali/common/mali_pmu.h new file mode 100644 index 0000000..fd10c08 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pmu.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** + * @file mali_platform.h + * Platform specific Mali driver functions + */ + +#include "mali_osk.h" + +struct mali_pmu_core; + +/** @brief Initialisation of MALI PMU + * + * This is called from entry point of the driver in order to create and intialize the PMU resource + * + * @param resource it will be a pointer to a PMU resource + * @param number_of_pp_cores Number of found PP resources in configuration + * @param number_of_l2_caches Number of found L2 cache resources in configuration + * @return The created PMU object, or NULL in case of failure. + */ +struct mali_pmu_core *mali_pmu_create(_mali_osk_resource_t *resource, u32 number_of_pp_cores, u32 number_of_l2_caches); + +/** @brief It deallocates the PMU resource + * + * This is called on the exit of the driver to terminate the PMU resource + * + * @param pmu Pointer to PMU core object to delete + */ +void mali_pmu_delete(struct mali_pmu_core *pmu); + +/** @brief Reset PMU core + * + * @param pmu Pointer to PMU core object to reset + * @return _MALI_OSK_ERR_OK on success, otherwise failure. + */ +_mali_osk_errcode_t mali_pmu_reset(struct mali_pmu_core *pmu); + +/** @brief MALI GPU power down using MALI in-built PMU + * + * called to power down all cores + * + * @param pmu Pointer to PMU core object to power down + * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. + */ +_mali_osk_errcode_t mali_pmu_powerdown_all(struct mali_pmu_core *pmu); + + +/** @brief MALI GPU power up using MALI in-built PMU + * + * called to power up all cores + * + * @param pmu Pointer to PMU core object to power up + * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. + */ +_mali_osk_errcode_t mali_pmu_powerup_all(struct mali_pmu_core *pmu); + + +/** @brief Retrieves the Mali PMU core object (if any) + * + * @return The Mali PMU object, or NULL if no PMU exists. + */ +struct mali_pmu_core *mali_pmu_get_global_pmu_core(void); diff --git a/drivers/media/video/samsung/mali/common/mali_pp.c b/drivers/media/video/samsung/mali/common/mali_pp.c new file mode 100644 index 0000000..5549f82 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pp.c @@ -0,0 +1,710 @@ +/* + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mali_pp.h" +#include "mali_hw_core.h" +#include "mali_group.h" +#include "mali_osk.h" +#include "regs/mali_200_regs.h" +#include "mali_kernel_common.h" +#include "mali_kernel_core.h" +#if MALI_TIMELINE_PROFILING_ENABLED +#include "mali_osk_profiling.h" +#endif + +/* See mali_gp.c file for description on how to handle the interrupt mask. + * This is how to do it on PP: mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_USED); + */ + +#define MALI_MAX_NUMBER_OF_PP_CORES 8 + +/** + * Definition of the PP core struct + * Used to track a PP core in the system. + */ +struct mali_pp_core +{ + struct mali_hw_core hw_core; /**< Common for all HW cores */ + struct mali_group *group; /**< Parent group for this core */ + _mali_osk_irq_t *irq; /**< IRQ handler */ + u32 core_id; /**< Unique core ID */ + struct mali_pp_job *running_job; /**< Current running (super) job */ + u32 running_sub_job; /**< Current running sub job */ + _mali_osk_timer_t *timeout_timer; /**< timeout timer for this core */ + u32 timeout_job_id; /**< job id for the timed out job - relevant only if pp_core_timed_out == MALI_TRUE */ + mali_bool core_timed_out; /**< if MALI_TRUE, this pp core has timed out; if MALI_FALSE, no timeout on this pp core */ + u32 counter_src0; /**< Performance counter 0, MALI_HW_CORE_NO_COUNTER for disabled */ + u32 counter_src1; /**< Performance counter 1, MALI_HW_CORE_NO_COUNTER for disabled */ + u32 counter_src0_used; /**< The selected performance counter 0 when a job is running */ + u32 counter_src1_used; /**< The selected performance counter 1 when a job is running */ +}; + +static struct mali_pp_core* mali_global_pp_cores[MALI_MAX_NUMBER_OF_PP_CORES]; +static u32 mali_global_num_pp_cores = 0; + +/* Interrupt handlers */ +static _mali_osk_errcode_t mali_pp_upper_half(void *data); +static void mali_pp_bottom_half(void *data); +static void mali_pp_irq_probe_trigger(void *data); +static _mali_osk_errcode_t mali_pp_irq_probe_ack(void *data); +static void mali_pp_post_process_job(struct mali_pp_core *core); +static void mali_pp_timeout(void *data); + +struct mali_pp_core *mali_pp_create(const _mali_osk_resource_t *resource, struct mali_group *group) +{ + struct mali_pp_core* core = NULL; + + MALI_DEBUG_PRINT(2, ("Mali PP: Creating Mali PP core: %s\n", resource->description)); + MALI_DEBUG_PRINT(2, ("Mali PP: Base address of PP core: 0x%x\n", resource->base)); + + if (mali_global_num_pp_cores >= MALI_MAX_NUMBER_OF_PP_CORES) + { + MALI_PRINT_ERROR(("Mali PP: Too many PP core objects created\n")); + return NULL; + } + + core = _mali_osk_malloc(sizeof(struct mali_pp_core)); + if (NULL != core) + { + core->group = group; + core->core_id = mali_global_num_pp_cores; + core->running_job = NULL; + core->counter_src0 = MALI_HW_CORE_NO_COUNTER; + core->counter_src1 = MALI_HW_CORE_NO_COUNTER; + core->counter_src0_used = MALI_HW_CORE_NO_COUNTER; + core->counter_src1_used = MALI_HW_CORE_NO_COUNTER; + if (_MALI_OSK_ERR_OK == mali_hw_core_create(&core->hw_core, resource, MALI200_REG_SIZEOF_REGISTER_BANK)) + { + _mali_osk_errcode_t ret; + + mali_group_lock(group); + ret = mali_pp_reset(core); + mali_group_unlock(group); + + if (_MALI_OSK_ERR_OK == ret) + { + /* Setup IRQ handlers (which will do IRQ probing if needed) */ + core->irq = _mali_osk_irq_init(resource->irq, + mali_pp_upper_half, + mali_pp_bottom_half, + mali_pp_irq_probe_trigger, + mali_pp_irq_probe_ack, + core, + "mali_pp_irq_handlers"); + if (NULL != core->irq) + { + /* Initialise the timeout timer */ + core->timeout_timer = _mali_osk_timer_init(); + if(NULL != core->timeout_timer) + { + _mali_osk_timer_setcallback(core->timeout_timer, mali_pp_timeout, (void *)core); + + mali_global_pp_cores[mali_global_num_pp_cores] = core; + mali_global_num_pp_cores++; + + return core; + } + else + { + MALI_PRINT_ERROR(("Failed to setup timeout timer for PP core %s\n", core->hw_core.description)); + /* Release IRQ handlers */ + _mali_osk_irq_term(core->irq); + } + } + else + { + MALI_PRINT_ERROR(("Mali PP: Failed to setup interrupt handlers for PP core %s\n", core->hw_core.description)); + } + } + mali_hw_core_delete(&core->hw_core); + } + + _mali_osk_free(core); + } + else + { + MALI_PRINT_ERROR(("Mali PP: Failed to allocate memory for PP core\n")); + } + + return NULL; +} + +void mali_pp_delete(struct mali_pp_core *core) +{ + u32 i; + + MALI_DEBUG_ASSERT_POINTER(core); + + _mali_osk_timer_term(core->timeout_timer); + _mali_osk_irq_term(core->irq); + mali_hw_core_delete(&core->hw_core); + + /* Remove core from global list */ + for (i = 0; i < mali_global_num_pp_cores; i++) + { + if (mali_global_pp_cores[i] == core) + { + mali_global_pp_cores[i] = NULL; + mali_global_num_pp_cores--; + break; + } + } + + _mali_osk_free(core); +} + +void mali_pp_stop_bus(struct mali_pp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + /* Will only send the stop bus command, and not wait for it to complete */ + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_STOP_BUS); +} + +_mali_osk_errcode_t mali_pp_stop_bus_wait(struct mali_pp_core *core) +{ + int i; + const int request_loop_count = 20; + + MALI_DEBUG_ASSERT_POINTER(core); + MALI_ASSERT_GROUP_LOCKED(core->group); + + /* Send the stop bus command. */ + mali_pp_stop_bus(core); + + /* Wait for bus to be stopped */ + for (i = 0; i < request_loop_count; i++) + { + if (mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_STATUS) & MALI200_REG_VAL_STATUS_BUS_STOPPED) + break; + _mali_osk_time_ubusydelay(10); + } + + if (request_loop_count == i) + { + MALI_PRINT_ERROR(("Mali PP: Failed to stop bus on %s. Status: 0x%08x\n", core->hw_core.description, mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_STATUS))); + return _MALI_OSK_ERR_FAULT; + } + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t mali_pp_hard_reset(struct mali_pp_core *core) +{ + /* Bus must be stopped before calling this function */ + const int reset_finished_loop_count = 15; + const u32 reset_invalid_value = 0xC0FFE000; + const u32 reset_check_value = 0xC01A0000; + int i; + + MALI_DEBUG_ASSERT_POINTER(core); + MALI_DEBUG_PRINT(2, ("Mali PP: Hard reset of core %s\n", core->hw_core.description)); + MALI_ASSERT_GROUP_LOCKED(core->group); + + mali_pp_post_process_job(core); /* @@@@ is there some cases where it is unsafe to post process the job here? */ + + /* Set register to a bogus value. The register will be used to detect when reset is complete */ + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_WRITE_BOUNDARY_LOW, reset_invalid_value); + + /* Force core to reset */ + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_FORCE_RESET); + + /* Wait for reset to be complete */ + for (i = 0; i < reset_finished_loop_count; i++) + { + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_WRITE_BOUNDARY_LOW, reset_check_value); + if (reset_check_value == mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_WRITE_BOUNDARY_LOW)) + { + break; + } + _mali_osk_time_ubusydelay(10); + } + + if (i == reset_finished_loop_count) + { + MALI_PRINT_ERROR(("Mali PP: The hard reset loop didn't work, unable to recover\n")); + } + + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_WRITE_BOUNDARY_LOW, 0x00000000); /* set it back to the default */ + /* Re-enable interrupts */ + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI200_REG_VAL_IRQ_MASK_ALL); + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_USED); + + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t mali_pp_reset(struct mali_pp_core *core) +{ + int i; + const int request_loop_count = 20; + + MALI_DEBUG_ASSERT_POINTER(core); + MALI_DEBUG_PRINT(4, ("Mali PP: Reset of core %s\n", core->hw_core.description)); + MALI_ASSERT_GROUP_LOCKED(core->group); + + mali_pp_post_process_job(core); /* @@@@ is there some cases where it is unsafe to post process the job here? */ + + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, 0); /* disable the IRQs */ + +#if defined(USING_MALI200) + + /* On Mali-200, stop the bus, then do a hard reset of the core */ + + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_STOP_BUS); + + for (i = 0; i < request_loop_count; i++) + { + if (mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_STATUS) & MALI200_REG_VAL_STATUS_BUS_STOPPED) + { + break; + } + _mali_osk_time_ubusydelay(10); + } + + if (request_loop_count == i) + { + MALI_PRINT_ERROR(("Mali PP: Failed to stop bus for core %s, unable to recover\n", core->hw_core.description)); + return _MALI_OSK_ERR_FAULT ; + } + + /* the bus was stopped OK, do the hard reset */ + mali_pp_hard_reset(core); + +#elif defined(USING_MALI400) + + /* Mali-300 and Mali-400 have a safe reset command which we use */ + + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI400PP_REG_VAL_IRQ_RESET_COMPLETED); + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI400PP_REG_VAL_CTRL_MGMT_SOFT_RESET); + + for (i = 0; i < request_loop_count; i++) + { + if (mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT) & MALI400PP_REG_VAL_IRQ_RESET_COMPLETED) + { + break; + } + _mali_osk_time_ubusydelay(10); + } + + if (request_loop_count == i) + { + MALI_DEBUG_PRINT(2, ("Mali PP: Failed to reset core %s, Status: 0x%08x\n", core->hw_core.description, mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_STATUS))); + return _MALI_OSK_ERR_FAULT; + } +#else +#error "no supported mali core defined" +#endif + + /* Re-enable interrupts */ + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI200_REG_VAL_IRQ_MASK_ALL); + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_USED); + + return _MALI_OSK_ERR_OK; +} + +void mali_pp_job_start(struct mali_pp_core *core, struct mali_pp_job *job, u32 sub_job) +{ + u32 *frame_registers = mali_pp_job_get_frame_registers(job); + u32 *wb0_registers = mali_pp_job_get_wb0_registers(job); + u32 *wb1_registers = mali_pp_job_get_wb1_registers(job); + u32 *wb2_registers = mali_pp_job_get_wb2_registers(job); + core->counter_src0_used = core->counter_src0; + core->counter_src1_used = core->counter_src1; + + MALI_DEBUG_ASSERT_POINTER(core); + MALI_ASSERT_GROUP_LOCKED(core->group); + + mali_hw_core_register_write_array_relaxed(&core->hw_core, MALI200_REG_ADDR_FRAME, frame_registers, MALI200_NUM_REGS_FRAME); + if (0 != sub_job) + { + /* + * There are two frame registers which are different for each sub job. + * For the first sub job, these are correctly represented in the frame register array, + * but we need to patch these for all other sub jobs + */ + mali_hw_core_register_write_relaxed(&core->hw_core, MALI200_REG_ADDR_FRAME, mali_pp_job_get_addr_frame(job, sub_job)); + mali_hw_core_register_write_relaxed(&core->hw_core, MALI200_REG_ADDR_STACK, mali_pp_job_get_addr_stack(job, sub_job)); + } + + if (wb0_registers[0]) /* M200_WB0_REG_SOURCE_SELECT register */ + { + mali_hw_core_register_write_array_relaxed(&core->hw_core, MALI200_REG_ADDR_WB0, wb0_registers, MALI200_NUM_REGS_WBx); + } + + if (wb1_registers[0]) /* M200_WB1_REG_SOURCE_SELECT register */ + { + mali_hw_core_register_write_array_relaxed(&core->hw_core, MALI200_REG_ADDR_WB1, wb1_registers, MALI200_NUM_REGS_WBx); + } + + if (wb2_registers[0]) /* M200_WB2_REG_SOURCE_SELECT register */ + { + mali_hw_core_register_write_array_relaxed(&core->hw_core, MALI200_REG_ADDR_WB2, wb2_registers, MALI200_NUM_REGS_WBx); + } + + /* This selects which performance counters we are reading */ + if (MALI_HW_CORE_NO_COUNTER != core->counter_src0_used || MALI_HW_CORE_NO_COUNTER != core->counter_src1_used) + { + /* global_config has enabled HW counters, this will override anything specified by user space */ + if (MALI_HW_CORE_NO_COUNTER != core->counter_src0_used) + { + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_SRC, core->counter_src0_used); + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_ENABLE, MALI200_REG_VAL_PERF_CNT_ENABLE); + } + if (MALI_HW_CORE_NO_COUNTER != core->counter_src1_used) + { + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_SRC, core->counter_src1_used); + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_ENABLE, MALI200_REG_VAL_PERF_CNT_ENABLE); + } + } + else + { + /* Use HW counters from job object, if any */ + u32 perf_counter_flag = mali_pp_job_get_perf_counter_flag(job); + if (0 != perf_counter_flag) + { + if (perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE) + { + core->counter_src0_used = mali_pp_job_get_perf_counter_src0(job); + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_SRC, core->counter_src0_used); + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_ENABLE, MALI200_REG_VAL_PERF_CNT_ENABLE); + } + + if (perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE) + { + core->counter_src1_used = mali_pp_job_get_perf_counter_src1(job); + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_SRC, core->counter_src1_used); + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_ENABLE, MALI200_REG_VAL_PERF_CNT_ENABLE); + } + } + } + + MALI_DEBUG_PRINT(3, ("Mali PP: Starting job 0x%08X part %u/%u on PP core %s\n", job, sub_job + 1, mali_pp_job_get_sub_job_count(job), core->hw_core.description)); + + /* Adding barrier to make sure all rester writes are finished */ + _mali_osk_write_mem_barrier(); + + /* This is the command that starts the core. */ + mali_hw_core_register_write_relaxed(&core->hw_core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_START_RENDERING); + + /* Adding barrier to make sure previous rester writes is finished */ + _mali_osk_write_mem_barrier(); + + /* Setup the timeout timer value and save the job id for the job running on the pp core */ + _mali_osk_timer_add(core->timeout_timer, _mali_osk_time_mstoticks(mali_max_job_runtime)); + core->timeout_job_id = mali_pp_job_get_id(job); + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE | MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_id) | MALI_PROFILING_EVENT_REASON_SINGLE_HW_FLUSH, job->frame_builder_id, job->flush_id, 0, 0, 0); + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_START|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_id), job->pid, job->tid, 0, 0, 0); +#endif + + core->running_job = job; + core->running_sub_job = sub_job; +} + +u32 mali_pp_core_get_version(struct mali_pp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + return mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_VERSION); +} + +u32 mali_pp_core_get_id(struct mali_pp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + return core->core_id; +} + +mali_bool mali_pp_core_set_counter_src0(struct mali_pp_core *core, u32 counter) +{ + MALI_DEBUG_ASSERT_POINTER(core); + + core->counter_src0 = counter; + return MALI_TRUE; +} + +mali_bool mali_pp_core_set_counter_src1(struct mali_pp_core *core, u32 counter) +{ + MALI_DEBUG_ASSERT_POINTER(core); + + core->counter_src1 = counter; + return MALI_TRUE; +} + +u32 mali_pp_core_get_counter_src0(struct mali_pp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + return core->counter_src0; +} + +u32 mali_pp_core_get_counter_src1(struct mali_pp_core *core) +{ + MALI_DEBUG_ASSERT_POINTER(core); + return core->counter_src1; +} + +struct mali_pp_core* mali_pp_get_global_pp_core(u32 index) +{ + if (MALI_MAX_NUMBER_OF_PP_CORES > index) + { + return mali_global_pp_cores[index]; + } + + return NULL; +} + +u32 mali_pp_get_glob_num_pp_cores(void) +{ + return mali_global_num_pp_cores; +} + +u32 mali_pp_get_max_num_pp_cores(void) +{ + return MALI_MAX_NUMBER_OF_PP_CORES; +} + +/* ------------- interrupt handling below ------------------ */ +static _mali_osk_errcode_t mali_pp_upper_half(void *data) +{ + struct mali_pp_core *core = (struct mali_pp_core *)data; + u32 irq_readout; + + irq_readout = mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_STATUS); + if (MALI200_REG_VAL_IRQ_MASK_NONE != irq_readout) + { + /* Mask out all IRQs from this core until IRQ is handled */ + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_NONE); + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_id)|MALI_PROFILING_EVENT_REASON_SINGLE_HW_INTERRUPT, irq_readout, 0, 0, 0, 0); +#endif + + /* We do need to handle this in a bottom half */ + _mali_osk_irq_schedulework(core->irq); + return _MALI_OSK_ERR_OK; + } + + return _MALI_OSK_ERR_FAULT; +} + +static void mali_pp_bottom_half(void *data) +{ + struct mali_pp_core *core = (struct mali_pp_core *)data; + u32 irq_readout; + u32 irq_errors; + +#if MALI_TIMELINE_PROFILING_ENABLED +#if 0 /* Bottom half TLP logging is currently not supported */ + _mali_osk_profiling_add_event( MALI_PROFILING_EVENT_TYPE_START| MALI_PROFILING_EVENT_CHANNEL_SOFTWARE , _mali_osk_get_pid(), _mali_osk_get_tid(), 0, 0, 0); +#endif +#endif + + mali_group_lock(core->group); /* Group lock grabbed in core handlers, but released in common group handler */ + + if ( MALI_FALSE == mali_group_power_is_on(core->group) ) + { + MALI_PRINT_ERROR(("Interrupt bottom half of %s when core is OFF.", core->hw_core.description)); + mali_group_unlock(core->group); + return; + } + + irq_readout = mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT) & MALI200_REG_VAL_IRQ_MASK_USED; + + MALI_DEBUG_PRINT(4, ("Mali PP: Bottom half IRQ 0x%08X from core %s\n", irq_readout, core->hw_core.description)); + + if (irq_readout & MALI200_REG_VAL_IRQ_END_OF_FRAME) + { + mali_pp_post_process_job(core); + MALI_DEBUG_PRINT(3, ("Mali PP: Job completed, calling group handler\n")); + mali_group_bottom_half(core->group, GROUP_EVENT_PP_JOB_COMPLETED); /* Will release group lock */ + return; + } + + /* + * Now lets look at the possible error cases (IRQ indicating error or timeout) + * END_OF_FRAME and HANG interrupts are not considered error. + */ + irq_errors = irq_readout & ~(MALI200_REG_VAL_IRQ_END_OF_FRAME|MALI200_REG_VAL_IRQ_HANG); + if (0 != irq_errors) + { + mali_pp_post_process_job(core); + MALI_PRINT_ERROR(("Mali PP: Unknown interrupt 0x%08X from core %s, aborting job\n", + irq_readout, core->hw_core.description)); + mali_group_bottom_half(core->group, GROUP_EVENT_PP_JOB_FAILED); /* Will release group lock */ + return; + } + else if (MALI_TRUE == core->core_timed_out) /* SW timeout */ + { + if (core->timeout_job_id == mali_pp_job_get_id(core->running_job)) + { + mali_pp_post_process_job(core); + MALI_DEBUG_PRINT(2, ("Mali PP: Job %d timed out on core %s\n", + mali_pp_job_get_id(core->running_job), core->hw_core.description)); + mali_group_bottom_half(core->group, GROUP_EVENT_PP_JOB_TIMED_OUT); /* Will release group lock */ + } + else + { + mali_group_unlock(core->group); + } + core->core_timed_out = MALI_FALSE; + return; + } + else if (irq_readout & MALI200_REG_VAL_IRQ_HANG) + { + /* Just ignore hang interrupts, the job timer will detect hanging jobs anyways */ + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI200_REG_VAL_IRQ_HANG); + } + + /* + * The only way to get here is if we got a HANG interrupt, which we ignore. + * Re-enable interrupts and let core continue to run + */ + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_USED); + mali_group_unlock(core->group); + +#if MALI_TIMELINE_PROFILING_ENABLED +#if 0 /* Bottom half TLP logging is currently not supported */ + _mali_osk_profiling_add_event( MALI_PROFILING_EVENT_TYPE_STOP| MALI_PROFILING_EVENT_CHANNEL_SOFTWARE , _mali_osk_get_pid(), _mali_osk_get_tid(), 0, 0, 0); +#endif +#endif +} + +static void mali_pp_irq_probe_trigger(void *data) +{ + struct mali_pp_core *core = (struct mali_pp_core *)data; + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_USED); /* @@@@ This should not be needed */ + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT, MALI200_REG_VAL_IRQ_FORCE_HANG); + _mali_osk_mem_barrier(); +} + +static _mali_osk_errcode_t mali_pp_irq_probe_ack(void *data) +{ + struct mali_pp_core *core = (struct mali_pp_core *)data; + u32 irq_readout; + + irq_readout = mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_STATUS); + if (MALI200_REG_VAL_IRQ_FORCE_HANG & irq_readout) + { + mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI200_REG_VAL_IRQ_FORCE_HANG); + _mali_osk_mem_barrier(); + return _MALI_OSK_ERR_OK; + } + + return _MALI_OSK_ERR_FAULT; +} + + +/* ------ local helper functions below --------- */ +static void mali_pp_post_process_job(struct mali_pp_core *core) +{ + MALI_ASSERT_GROUP_LOCKED(core->group); + + if (NULL != core->running_job) + { + u32 val0 = 0; + u32 val1 = 0; +#if MALI_TIMELINE_PROFILING_ENABLED + int counter_index = COUNTER_FP0_C0 + (2 * core->core_id); +#endif + + if (MALI_HW_CORE_NO_COUNTER != core->counter_src0_used) + { + val0 = mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_VALUE); + if (mali_pp_job_get_perf_counter_flag(core->running_job) && + _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE && mali_pp_job_get_perf_counter_src0(core->running_job) == core->counter_src0_used) + { + /* We retrieved the counter that user space asked for, so return the value through the job object */ + mali_pp_job_set_perf_counter_value0(core->running_job, core->running_sub_job, val0); + } + else + { + /* User space asked for a counter, but this is not what we retrived (overridden by counter src set on core) */ + mali_pp_job_set_perf_counter_value0(core->running_job, core->running_sub_job, MALI_HW_CORE_INVALID_VALUE); + } + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_report_hw_counter(counter_index, val0); +#endif + } + + if (MALI_HW_CORE_NO_COUNTER != core->counter_src1_used) + { + val1 = mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_VALUE); + if (mali_pp_job_get_perf_counter_flag(core->running_job) && + _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE && mali_pp_job_get_perf_counter_src1(core->running_job) == core->counter_src1_used) + { + /* We retrieved the counter that user space asked for, so return the value through the job object */ + mali_pp_job_set_perf_counter_value1(core->running_job, core->running_sub_job, val1); + } + else + { + /* User space asked for a counter, but this is not what we retrived (overridden by counter src set on core) */ + mali_pp_job_set_perf_counter_value1(core->running_job, core->running_sub_job, MALI_HW_CORE_INVALID_VALUE); + } + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_report_hw_counter(counter_index + 1, val1); +#endif + } + +#if MALI_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_id), + val0, val1, core->counter_src0_used | (core->counter_src1_used << 8), 0, 0); +#endif + + /* We are no longer running a job... */ + core->running_job = NULL; + _mali_osk_timer_del(core->timeout_timer); + } +} + +/* callback function for pp core timeout */ +static void mali_pp_timeout(void *data) +{ + struct mali_pp_core * core = ((struct mali_pp_core *)data); + + MALI_DEBUG_PRINT(3, ("Mali PP: TIMEOUT callback \n")); + core->core_timed_out = MALI_TRUE; + _mali_osk_irq_schedulework(core->irq); +} + +#if 0 +static void mali_pp_print_registers(struct mali_pp_core *core) +{ + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_VERSION = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_VERSION))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_CURRENT_REND_LIST_ADDR = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_CURRENT_REND_LIST_ADDR))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_STATUS = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_STATUS))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_INT_RAWSTAT = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_INT_MASK = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_INT_STATUS = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_STATUS))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_BUS_ERROR_STATUS = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_BUS_ERROR_STATUS))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_PERF_CNT_0_ENABLE = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_ENABLE))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_PERF_CNT_0_SRC = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_SRC))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_PERF_CNT_0_VALUE = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_VALUE))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_PERF_CNT_1_ENABLE = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_ENABLE))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_PERF_CNT_1_SRC = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_SRC))); + MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_PERF_CNT_1_VALUE = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_VALUE))); +} +#endif + +#if 0 +void mali_pp_print_state(struct mali_pp_core *core) +{ + MALI_DEBUG_PRINT(2, ("Mali PP: State: 0x%08x\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_STATUS) )); +} +#endif + +#if MALI_STATE_TRACKING +u32 mali_pp_dump_state(struct mali_pp_core *core, char *buf, u32 size) +{ + int n = 0; + + n += _mali_osk_snprintf(buf + n, size - n, "\tPP #%d: %s\n", core->core_id, core->hw_core.description); + + return n; +} +#endif diff --git a/drivers/media/video/samsung/mali/common/mali_pp.h b/drivers/media/video/samsung/mali/common/mali_pp.h new file mode 100644 index 0000000..9b425a0 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pp.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MALI_PP_H__ +#define __MALI_PP_H__ + +#include "mali_osk.h" +#include "mali_pp_job.h" + +struct mali_pp_core; +struct mali_group; + +_mali_osk_errcode_t mali_pp_initialize(void); +void mali_pp_terminate(void); + +struct mali_pp_core *mali_pp_create(const _mali_osk_resource_t * resource, struct mali_group *group); +void mali_pp_delete(struct mali_pp_core *core); + +void mali_pp_stop_bus(struct mali_pp_core *core); +_mali_osk_errcode_t mali_pp_stop_bus_wait(struct mali_pp_core *core); +_mali_osk_errcode_t mali_pp_reset(struct mali_pp_core *core); +_mali_osk_errcode_t mali_pp_hard_reset(struct mali_pp_core *core); + +void mali_pp_job_start(struct mali_pp_core *core, struct mali_pp_job *job, u32 sub_job); + +u32 mali_pp_core_get_version(struct mali_pp_core *core); + +u32 mali_pp_core_get_id(struct mali_pp_core *core); + +mali_bool mali_pp_core_set_counter_src0(struct mali_pp_core *core, u32 counter); +mali_bool mali_pp_core_set_counter_src1(struct mali_pp_core *core, u32 counter); +u32 mali_pp_core_get_counter_src0(struct mali_pp_core *core); +u32 mali_pp_core_get_counter_src1(struct mali_pp_core *core); +struct mali_pp_core* mali_pp_get_global_pp_core(u32 index); +u32 mali_pp_get_glob_num_pp_cores(void); +u32 mali_pp_get_max_num_pp_cores(void); +/* Debug */ +u32 mali_pp_dump_state(struct mali_pp_core *core, char *buf, u32 size); + +#endif /* __MALI_PP_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_pp_job.c b/drivers/media/video/samsung/mali/common/mali_pp_job.c new file mode 100644 index 0000000..1efcfda --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pp_job.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mali_pp_job.h" +#include "mali_osk.h" +#include "mali_osk_list.h" +#include "mali_kernel_common.h" +#include "mali_uk_types.h" + +struct mali_pp_job *mali_pp_job_create(struct mali_session_data *session, _mali_uk_pp_start_job_s *args, u32 id) +{ + struct mali_pp_job *job; + + if (args->num_cores > _MALI_PP_MAX_SUB_JOBS) + { + MALI_PRINT_ERROR(("Mali PP job: Too many sub jobs specified in job object\n")); + return NULL; + } + + job = _mali_osk_malloc(sizeof(struct mali_pp_job)); + if (NULL != job) + { + u32 i; + _mali_osk_list_init(&job->list); + job->session = session; + job->id = id; + job->user_id = args->user_job_ptr; + _mali_osk_memcpy(job->frame_registers, args->frame_registers, sizeof(job->frame_registers)); + _mali_osk_memcpy(job->frame_registers_addr_frame, args->frame_registers_addr_frame, sizeof(job->frame_registers_addr_frame)); + _mali_osk_memcpy(job->frame_registers_addr_stack, args->frame_registers_addr_stack, sizeof(job->frame_registers_addr_stack)); + + /* Only copy write back registers for the units that are enabled */ + job->wb0_registers[0] = 0; + job->wb1_registers[0] = 0; + job->wb2_registers[0] = 0; + if (args->wb0_registers[0]) /* M200_WB0_REG_SOURCE_SELECT register */ + { + _mali_osk_memcpy(job->wb0_registers, args->wb0_registers, sizeof(job->wb0_registers)); + } + if (args->wb1_registers[0]) /* M200_WB1_REG_SOURCE_SELECT register */ + { + _mali_osk_memcpy(job->wb1_registers, args->wb1_registers, sizeof(job->wb1_registers)); + } + if (args->wb2_registers[0]) /* M200_WB2_REG_SOURCE_SELECT register */ + { + _mali_osk_memcpy(job->wb2_registers, args->wb2_registers, sizeof(job->wb2_registers)); + } + + job->perf_counter_flag = args->perf_counter_flag; + job->perf_counter_src0 = args->perf_counter_src0; + job->perf_counter_src1 = args->perf_counter_src1; + for (i = 0; i < args->num_cores; i++) + { + job->perf_counter_value0[i] = 0; + job->perf_counter_value1[i] = 0; + } + job->sub_job_count = args->num_cores; + job->sub_jobs_started = 0; + job->sub_jobs_completed = 0; + job->sub_job_errors = 0; + + job->pid = _mali_osk_get_pid(); + job->tid = _mali_osk_get_tid(); + job->frame_builder_id = args->frame_builder_id; + job->flush_id = args->flush_id; + + return job; + } + + return NULL; +} + +void mali_pp_job_delete(struct mali_pp_job *job) +{ + _mali_osk_free(job); +} + +_mali_osk_errcode_t mali_pp_job_check(struct mali_pp_job *job) +{ + if ((0 == job->frame_registers[0]) || (0 == job->frame_registers[1])) + { + return _MALI_OSK_ERR_FAULT; + } + return _MALI_OSK_ERR_OK; +} diff --git a/drivers/media/video/samsung/mali/common/mali_pp_job.h b/drivers/media/video/samsung/mali/common/mali_pp_job.h new file mode 100644 index 0000000..7fe87f8 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pp_job.h @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MALI_PP_JOB_H__ +#define __MALI_PP_JOB_H__ + +#include "mali_osk.h" +#include "mali_osk_list.h" +#include "mali_uk_types.h" +#include "mali_session.h" +#include "mali_kernel_common.h" +#include "regs/mali_200_regs.h" + +/** + * The structure represends a PP job, including all sub-jobs + * (This struct unfortunatly needs to be public because of how the _mali_osk_list_* + * mechanism works) + */ +struct mali_pp_job +{ + _mali_osk_list_t list; /**< Used to link jobs together in the scheduler queue */ + struct mali_session_data *session; /**< Session which submitted this job */ + u32 id; /**< identifier for this job in kernel space (sequencial numbering) */ + u32 user_id; /**< identifier for the job in user space */ + u32 frame_registers[_MALI_PP_MAX_FRAME_REGISTERS]; /**< core specific registers associated with this job, see ARM DDI0415A */ + u32 frame_registers_addr_frame[_MALI_PP_MAX_SUB_JOBS - 1]; /**< ADDR_FRAME registers for sub job 1-7 */ + u32 frame_registers_addr_stack[_MALI_PP_MAX_SUB_JOBS - 1]; /**< ADDR_STACK registers for sub job 1-7 */ + u32 wb0_registers[_MALI_PP_MAX_WB_REGISTERS]; /**< Write back unit 0 registers */ + u32 wb1_registers[_MALI_PP_MAX_WB_REGISTERS]; /**< Write back unit 1 registers */ + u32 wb2_registers[_MALI_PP_MAX_WB_REGISTERS]; /**< Write back unit 2 registers */ + u32 perf_counter_flag; /**< bitmask indicating which performance counters to enable, see \ref _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE and related macro definitions */ + u32 perf_counter_src0; /**< Source id for performance counter 0 (see ARM DDI0415A, Table 3-60) */ + u32 perf_counter_src1; /**< Source id for performance counter 1 (see ARM DDI0415A, Table 3-60) */ + u32 perf_counter_value0[_MALI_PP_MAX_SUB_JOBS]; /**< Value of performance counter 0 (to be returned to user space), one for each sub job */ + u32 perf_counter_value1[_MALI_PP_MAX_SUB_JOBS]; /**< Value of performance counter 1 (to be returned to user space), one for each sub job */ + u32 sub_job_count; /**< Total number of sub-jobs in this superjob */ + u32 sub_jobs_started; /**< Total number of sub-jobs started (always started in ascending order) */ + u32 sub_jobs_completed; /**< Number of completed sub-jobs in this superjob */ + u32 sub_job_errors; /**< Bitfield with errors (errors for each single sub-job is or'ed together) */ + u32 pid; /**< Process ID of submitting process */ + u32 tid; /**< Thread ID of submitting thread */ + u32 frame_builder_id; /**< id of the originating frame builder */ + u32 flush_id; /**< flush id within the originating frame builder */ +}; + +struct mali_pp_job *mali_pp_job_create(struct mali_session_data *session, _mali_uk_pp_start_job_s *args, u32 id); +void mali_pp_job_delete(struct mali_pp_job *job); + +_mali_osk_errcode_t mali_pp_job_check(struct mali_pp_job *job); + +/****************************************************** + * simple utility functions for dealing with pp jobs: + *****************************************************/ + +MALI_STATIC_INLINE u32 mali_pp_job_get_id(struct mali_pp_job *job) +{ + return (NULL == job) ? 0 : job->id; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_user_id(struct mali_pp_job *job) +{ + return job->user_id; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_frame_builder_id(struct mali_pp_job *job) +{ + return job->frame_builder_id; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_flush_id(struct mali_pp_job *job) +{ + return job->flush_id; +} + +MALI_STATIC_INLINE u32* mali_pp_job_get_frame_registers(struct mali_pp_job *job) +{ + return job->frame_registers; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_addr_frame(struct mali_pp_job *job, u32 sub_job) +{ + if (sub_job == 0) + { + return job->frame_registers[MALI200_REG_ADDR_FRAME / sizeof(u32)]; + } + else if (sub_job < _MALI_PP_MAX_SUB_JOBS) + { + return job->frame_registers_addr_frame[sub_job - 1]; + } + + return 0; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_addr_stack(struct mali_pp_job *job, u32 sub_job) +{ + if (sub_job == 0) + { + return job->frame_registers[MALI200_REG_ADDR_STACK / sizeof(u32)]; + } + else if (sub_job < _MALI_PP_MAX_SUB_JOBS) + { + return job->frame_registers_addr_stack[sub_job - 1]; + } + + return 0; +} + +MALI_STATIC_INLINE u32* mali_pp_job_get_wb0_registers(struct mali_pp_job *job) +{ + return job->wb0_registers; +} + +MALI_STATIC_INLINE u32* mali_pp_job_get_wb1_registers(struct mali_pp_job *job) +{ + return job->wb1_registers; +} + +MALI_STATIC_INLINE u32* mali_pp_job_get_wb2_registers(struct mali_pp_job *job) +{ + return job->wb2_registers; +} + +MALI_STATIC_INLINE void mali_pp_job_disable_wb0(struct mali_pp_job *job) +{ + job->wb0_registers[MALI200_REG_ADDR_WB_SOURCE_SELECT] = 0; +} + +MALI_STATIC_INLINE void mali_pp_job_disable_wb1(struct mali_pp_job *job) +{ + job->wb1_registers[MALI200_REG_ADDR_WB_SOURCE_SELECT] = 0; +} + +MALI_STATIC_INLINE void mali_pp_job_disable_wb2(struct mali_pp_job *job) +{ + job->wb2_registers[MALI200_REG_ADDR_WB_SOURCE_SELECT] = 0; +} + +MALI_STATIC_INLINE struct mali_session_data *mali_pp_job_get_session(struct mali_pp_job *job) +{ + return job->session; +} + +MALI_STATIC_INLINE mali_bool mali_pp_job_has_unstarted_sub_jobs(struct mali_pp_job *job) +{ + return (job->sub_jobs_started < job->sub_job_count) ? MALI_TRUE : MALI_FALSE; +} + +/* Function used when we are terminating a session with jobs. Return TRUE if it has a rendering job. + Makes sure that no new subjobs is started. */ +MALI_STATIC_INLINE mali_bool mali_pp_job_is_currently_rendering_and_if_so_abort_new_starts(struct mali_pp_job *job) +{ + /* All can not be started, since then it would not be in the job queue */ + MALI_DEBUG_ASSERT( job->sub_jobs_started != job->sub_job_count ); + + /* If at least one job is started */ + if ( (job->sub_jobs_started > 0) ) + { + /* If at least one job is currently being rendered, and thus assigned to a group and core */ + if (job->sub_jobs_started > job->sub_jobs_completed ) + { + u32 jobs_remaining = job->sub_job_count - job->sub_jobs_started; + job->sub_jobs_started += jobs_remaining; + job->sub_jobs_completed += jobs_remaining; + job->sub_job_errors += jobs_remaining; + /* Returning TRUE indicating that we can not delete this job which is being redered */ + return MALI_TRUE; + } + } + /* The job is not being rendered to at the moment and can then safely be deleted */ + return MALI_FALSE; +} + +MALI_STATIC_INLINE mali_bool mali_pp_job_is_complete(struct mali_pp_job *job) +{ + return (job->sub_job_count == job->sub_jobs_completed) ? MALI_TRUE : MALI_FALSE; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_first_unstarted_sub_job(struct mali_pp_job *job) +{ + return job->sub_jobs_started; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_sub_job_count(struct mali_pp_job *job) +{ + return job->sub_job_count; +} + +MALI_STATIC_INLINE void mali_pp_job_mark_sub_job_started(struct mali_pp_job *job, u32 sub_job) +{ + /* Assert that we are marking the "first unstarted sub job" as started */ + MALI_DEBUG_ASSERT(job->sub_jobs_started == sub_job); + job->sub_jobs_started++; +} + +MALI_STATIC_INLINE void mali_pp_job_mark_sub_job_completed(struct mali_pp_job *job, mali_bool success) +{ + job->sub_jobs_completed++; + if ( MALI_FALSE == success ) + { + job->sub_job_errors++; + } +} + +MALI_STATIC_INLINE mali_bool mali_pp_job_was_success(struct mali_pp_job *job) +{ + if ( 0 == job->sub_job_errors ) + { + return MALI_TRUE; + } + return MALI_FALSE; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_perf_counter_flag(struct mali_pp_job *job) +{ + return job->perf_counter_flag; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_perf_counter_src0(struct mali_pp_job *job) +{ + return job->perf_counter_src0; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_perf_counter_src1(struct mali_pp_job *job) +{ + return job->perf_counter_src1; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_perf_counter_value0(struct mali_pp_job *job, u32 sub_job) +{ + return job->perf_counter_value0[sub_job]; +} + +MALI_STATIC_INLINE u32 mali_pp_job_get_perf_counter_value1(struct mali_pp_job *job, u32 sub_job) +{ + return job->perf_counter_value1[sub_job]; +} + +MALI_STATIC_INLINE void mali_pp_job_set_perf_counter_value0(struct mali_pp_job *job, u32 sub_job, u32 value) +{ + job->perf_counter_value0[sub_job] = value; +} + +MALI_STATIC_INLINE void mali_pp_job_set_perf_counter_value1(struct mali_pp_job *job, u32 sub_job, u32 value) +{ + job->perf_counter_value1[sub_job] = value; +} + +#endif /* __MALI_PP_JOB_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_pp_scheduler.c b/drivers/media/video/samsung/mali/common/mali_pp_scheduler.c new file mode 100644 index 0000000..ce07a76 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pp_scheduler.c @@ -0,0 +1,542 @@ +/* + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mali_pp_scheduler.h" +#include "mali_kernel_common.h" +#include "mali_osk.h" +#include "mali_osk_list.h" +#include "mali_scheduler.h" +#include "mali_pp.h" +#include "mali_pp_job.h" +#include "mali_group.h" +#include "mali_cluster.h" + +/* Maximum of 8 PP cores (a group can only have maximum of 1 PP core) */ +#define MALI_MAX_NUMBER_OF_PP_GROUPS 8 + +static mali_bool mali_pp_scheduler_is_suspended(void); + +enum mali_pp_slot_state +{ + MALI_PP_SLOT_STATE_IDLE, + MALI_PP_SLOT_STATE_WORKING, +}; + +/* A render slot is an entity which jobs can be scheduled onto */ +struct mali_pp_slot +{ + struct mali_group *group; + /* + * We keep track of the state here as well as in the group object + * so we don't need to take the group lock so often (and also avoid clutter with the working lock) + */ + enum mali_pp_slot_state state; +}; + +static u32 pp_version = 0; +static _MALI_OSK_LIST_HEAD(job_queue); /* List of jobs with some unscheduled work */ +static struct mali_pp_slot slots[MALI_MAX_NUMBER_OF_PP_GROUPS]; +static u32 num_slots = 0; +static u32 num_slots_idle = 0; + +/* Variables to allow safe pausing of the scheduler */ +static _mali_osk_wait_queue_t *pp_scheduler_working_wait_queue = NULL; +static u32 pause_count = 0; + +static _mali_osk_lock_t *pp_scheduler_lock = NULL; +/* Contains tid of thread that locked the scheduler or 0, if not locked */ +MALI_DEBUG_CODE(static u32 pp_scheduler_lock_owner = 0); + +_mali_osk_errcode_t mali_pp_scheduler_initialize(void) +{ + u32 i; + + _MALI_OSK_INIT_LIST_HEAD(&job_queue); + + pp_scheduler_lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED |_MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_SCHEDULER); + if (NULL == pp_scheduler_lock) + { + return _MALI_OSK_ERR_NOMEM; + } + + pp_scheduler_working_wait_queue = _mali_osk_wait_queue_init(); + if (NULL == pp_scheduler_working_wait_queue) + { + _mali_osk_lock_term(pp_scheduler_lock); + return _MALI_OSK_ERR_NOMEM; + } + + /* Find all the available PP cores */ + for (i = 0; i < mali_cluster_get_glob_num_clusters(); i++) + { + u32 group_id = 0; + struct mali_cluster *curr_cluster = mali_cluster_get_global_cluster(i); + struct mali_group *group = mali_cluster_get_group(curr_cluster, group_id); + while (NULL != group) + { + struct mali_pp_core *pp_core = mali_group_get_pp_core(group); + if (NULL != pp_core) + { + if (0 == pp_version) + { + /* Retrieve PP version from first avaiable PP core */ + pp_version = mali_pp_core_get_version(pp_core); + } + slots[num_slots].group = group; + slots[num_slots].state = MALI_PP_SLOT_STATE_IDLE; + num_slots++; + num_slots_idle++; + } + group_id++; + group = mali_cluster_get_group(curr_cluster, group_id); + } + } + + return _MALI_OSK_ERR_OK; +} + +void mali_pp_scheduler_terminate(void) +{ + _mali_osk_wait_queue_term(pp_scheduler_working_wait_queue); + _mali_osk_lock_term(pp_scheduler_lock); +} + +MALI_STATIC_INLINE void mali_pp_scheduler_lock(void) +{ + if(_MALI_OSK_ERR_OK != _mali_osk_lock_wait(pp_scheduler_lock, _MALI_OSK_LOCKMODE_RW)) + { + /* Non-interruptable lock failed: this should never happen. */ + MALI_DEBUG_ASSERT(0); + } + MALI_DEBUG_PRINT(5, ("Mali PP scheduler: PP scheduler lock taken\n")); + MALI_DEBUG_ASSERT(0 == pp_scheduler_lock_owner); + MALI_DEBUG_CODE(pp_scheduler_lock_owner = _mali_osk_get_tid()); +} + +MALI_STATIC_INLINE void mali_pp_scheduler_unlock(void) +{ + MALI_DEBUG_PRINT(5, ("Mali PP scheduler: Releasing PP scheduler lock\n")); + MALI_DEBUG_ASSERT(_mali_osk_get_tid() == pp_scheduler_lock_owner); + MALI_DEBUG_CODE(pp_scheduler_lock_owner = 0); + _mali_osk_lock_signal(pp_scheduler_lock, _MALI_OSK_LOCKMODE_RW); +} + +#ifdef DEBUG +MALI_STATIC_INLINE void mali_pp_scheduler_assert_locked(void) +{ + MALI_DEBUG_ASSERT(_mali_osk_get_tid() == pp_scheduler_lock_owner); +} +#define MALI_ASSERT_PP_SCHEDULER_LOCKED() mali_pp_scheduler_assert_locked() +#else +#define MALI_ASSERT_PP_SCHEDULER_LOCKED() +#endif + +static void mali_pp_scheduler_schedule(void) +{ + u32 i; + struct mali_pp_job *job; +#if MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP_BETWEEN_APPS + struct mali_session_data * session; +#endif + + MALI_ASSERT_PP_SCHEDULER_LOCKED(); + + if (0 < pause_count || 0 == num_slots_idle || _mali_osk_list_empty(&job_queue)) + { + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Nothing to schedule (paused=%u, idle slots=%u)\n", + pause_count, num_slots_idle)); + return; /* Nothing to do, so early out */ + } + + +#if MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP + if ( num_slots_idle < num_slots ) + { + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Job not started, since only %d/%d cores are available\n", num_slots_idle,num_slots)); + return; + } +#endif + +#if MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP_BETWEEN_APPS + /* Finding initial session for the PP cores */ + job = _MALI_OSK_LIST_ENTRY(job_queue.next, struct mali_pp_job, list); + session = job->session; + if ( num_slots != num_slots_idle ) + { + for (i = 0; (i < num_slots) ; i++) + { + if ( slots[i].state == MALI_PP_SLOT_STATE_IDLE ) + { + continue; + } + session = mali_group_get_session(slots[i].group); + break; + } + } +#endif + + for (i = 0; (i < num_slots) && (0 < num_slots_idle); i++) + { + u32 sub_job; + + if (_mali_osk_list_empty(&job_queue)) /* move this check down to where we know we have started all sub jobs for this job??? */ + { + break; /* No more jobs to schedule, so early out */ + } + + if (MALI_PP_SLOT_STATE_IDLE != slots[i].state) + { + continue; + } + + job = _MALI_OSK_LIST_ENTRY(job_queue.next, struct mali_pp_job, list); + MALI_DEBUG_ASSERT(mali_pp_job_has_unstarted_sub_jobs(job)); /* All jobs on the job_queue should have unstarted sub jobs */ + + #if MALI_PP_SCHEDULER_KEEP_SUB_JOB_STARTS_ALIGNED + if ( (0==job->sub_jobs_started) && (num_slots_idle < num_slots) && (job->sub_job_count > num_slots_idle)) + { + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Job with %d subjobs not started, since only %d/%d cores are available\n", job->sub_job_count, num_slots_idle,num_slots)); + return; + } + #endif + + #if MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP_BETWEEN_APPS + if ( job->session != session ) + { + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Job not started since existing job is from another application\n")); + return; + } + #endif + + sub_job = mali_pp_job_get_first_unstarted_sub_job(job); + + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Starting job %u (0x%08X) part %u/%u\n", mali_pp_job_get_id(job), job, sub_job + 1, mali_pp_job_get_sub_job_count(job))); + if (_MALI_OSK_ERR_OK == mali_group_start_pp_job(slots[i].group, job, sub_job)) + { + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Job %u (0x%08X) part %u/%u started\n", mali_pp_job_get_id(job), job, sub_job + 1, mali_pp_job_get_sub_job_count(job))); + + /* Mark this sub job as started */ + mali_pp_job_mark_sub_job_started(job, sub_job); + + /* Mark slot as busy */ + slots[i].state = MALI_PP_SLOT_STATE_WORKING; + num_slots_idle--; + + if (!mali_pp_job_has_unstarted_sub_jobs(job)) + { + /* + * All sub jobs have now started for this job, remove this job from the job queue. + * The job will now only be referred to by the slots which are running it. + * The last slot to complete will make sure it is returned to user space. + */ + _mali_osk_list_del(&job->list); +#if MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP + MALI_DEBUG_PRINT(6, ("Mali PP scheduler: Skip scheduling more jobs when MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP is set.\n")); + return; +#endif + } + } + else + { + MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Failed to start PP job\n")); + return; + } + } +} + +static void mali_pp_scheduler_return_job_to_user(struct mali_pp_job *job) +{ + _mali_osk_notification_t *notobj = _mali_osk_notification_create(_MALI_NOTIFICATION_PP_FINISHED, sizeof(_mali_uk_pp_job_finished_s)); + if (NULL != notobj) + { + u32 i; + u32 sub_jobs = mali_pp_job_get_sub_job_count(job); + mali_bool success = mali_pp_job_was_success(job); + + _mali_uk_pp_job_finished_s *jobres = notobj->result_buffer; + _mali_osk_memset(jobres, 0, sizeof(_mali_uk_pp_job_finished_s)); /* @@@@ can be removed once we initialize all members in this struct */ + jobres->user_job_ptr = mali_pp_job_get_user_id(job); + if (MALI_TRUE == success) + { + jobres->status = _MALI_UK_JOB_STATUS_END_SUCCESS; + } + else + { + jobres->status = _MALI_UK_JOB_STATUS_END_UNKNOWN_ERR; + } + + for (i = 0; i < sub_jobs; i++) + { + jobres->perf_counter0[i] = mali_pp_job_get_perf_counter_value0(job, i); + jobres->perf_counter1[i] = mali_pp_job_get_perf_counter_value1(job, i); + } + + mali_session_send_notification(mali_pp_job_get_session(job), notobj); + } + else + { + MALI_PRINT_ERROR(("Mali PP scheduler: Unable to allocate notification object\n")); + } + + mali_pp_job_delete(job); +} + +void mali_pp_scheduler_do_schedule(void) +{ + mali_pp_scheduler_lock(); + + mali_pp_scheduler_schedule(); + + mali_pp_scheduler_unlock(); +} + +void mali_pp_scheduler_job_done(struct mali_group *group, struct mali_pp_job *job, u32 sub_job, mali_bool success) +{ + u32 i; + mali_bool job_is_done; + + MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Job %u (0x%08X) part %u/%u completed (%s)\n", mali_pp_job_get_id(job), job, sub_job + 1, mali_pp_job_get_sub_job_count(job), success ? "success" : "failure")); + + mali_pp_scheduler_lock(); + + /* Find slot which was running this job */ + for (i = 0; i < num_slots; i++) + { + if (slots[i].group == group) + { + MALI_DEBUG_ASSERT(MALI_PP_SLOT_STATE_WORKING == slots[i].state); + slots[i].state = MALI_PP_SLOT_STATE_IDLE; + num_slots_idle++; + mali_pp_job_mark_sub_job_completed(job, success); + } + } + + /* If paused, then this was the last job, so wake up sleeping workers */ + if (pause_count > 0) + { + /* Wake up sleeping workers. Their wake-up condition is that + * num_slots == num_slots_idle, so unless we are done working, no + * threads will actually be woken up. + */ + _mali_osk_wait_queue_wake_up(pp_scheduler_working_wait_queue); + } + else + { + mali_pp_scheduler_schedule(); + } + + job_is_done = mali_pp_job_is_complete(job); + + mali_pp_scheduler_unlock(); + + if (job_is_done) + { + /* Send notification back to user space */ + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: All parts completed for job %u (0x%08X)\n", mali_pp_job_get_id(job), job)); + mali_pp_scheduler_return_job_to_user(job); + } +} + +void mali_pp_scheduler_suspend(void) +{ + mali_pp_scheduler_lock(); + pause_count++; /* Increment the pause_count so that no more jobs will be scheduled */ + mali_pp_scheduler_unlock(); + + /*mali_pp_scheduler_working_lock();*/ + /* We have now aquired the working lock, which means that we have successfully paused the scheduler */ + /*mali_pp_scheduler_working_unlock();*/ + + /* go to sleep. When woken up again (in mali_pp_scheduler_job_done), the + * mali_pp_scheduler_suspended() function will be called. This will return true + * iff state is idle and pause_count > 0, so if the core is active this + * will not do anything. + */ + _mali_osk_wait_queue_wait_event(pp_scheduler_working_wait_queue, mali_pp_scheduler_is_suspended); +} + +void mali_pp_scheduler_resume(void) +{ + mali_pp_scheduler_lock(); + pause_count--; /* Decrement pause_count to allow scheduling again (if it reaches 0) */ + if (0 == pause_count) + { + mali_pp_scheduler_schedule(); + } + mali_pp_scheduler_unlock(); +} + +_mali_osk_errcode_t _mali_ukk_pp_start_job(_mali_uk_pp_start_job_s *args) +{ + struct mali_session_data *session; + struct mali_pp_job *job; + + MALI_DEBUG_ASSERT_POINTER(args); + MALI_DEBUG_ASSERT_POINTER(args->ctx); + + session = (struct mali_session_data*)args->ctx; + + job = mali_pp_job_create(session, args, mali_scheduler_get_new_id()); + if (NULL == job) + { + return _MALI_OSK_ERR_NOMEM; + } + + if (_MALI_OSK_ERR_OK != mali_pp_job_check(job)) + { + /* Not a valid job, return to user immediately */ + mali_pp_job_mark_sub_job_completed(job, MALI_FALSE); /* Flagging the job as failed. */ + mali_pp_scheduler_return_job_to_user(job); /* This will also delete the job object */ + return _MALI_OSK_ERR_OK; /* User is notified via a notification, so this call is ok */ + } + + mali_pp_scheduler_lock(); + + _mali_osk_list_addtail(&job->list, &job_queue); + + MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Job %u (0x%08X) with %u parts queued\n", mali_pp_job_get_id(job), job, mali_pp_job_get_sub_job_count(job))); + + mali_pp_scheduler_schedule(); + + mali_pp_scheduler_unlock(); + + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t _mali_ukk_get_pp_number_of_cores(_mali_uk_get_pp_number_of_cores_s *args) +{ + MALI_DEBUG_ASSERT_POINTER(args); + MALI_DEBUG_ASSERT_POINTER(args->ctx); + args->number_of_cores = num_slots; + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t _mali_ukk_get_pp_core_version(_mali_uk_get_pp_core_version_s *args) +{ + MALI_DEBUG_ASSERT_POINTER(args); + MALI_DEBUG_ASSERT_POINTER(args->ctx); + args->version = pp_version; + return _MALI_OSK_ERR_OK; +} + +void _mali_ukk_pp_job_disable_wb(_mali_uk_pp_disable_wb_s *args) +{ + struct mali_session_data *session; + struct mali_pp_job *job; + struct mali_pp_job *tmp; + + MALI_DEBUG_ASSERT_POINTER(args); + MALI_DEBUG_ASSERT_POINTER(args->ctx); + + session = (struct mali_session_data*)args->ctx; + + mali_pp_scheduler_lock(); + + /* Check queue for jobs that match */ + _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &job_queue, struct mali_pp_job, list) + { + if (mali_pp_job_get_session(job) == session && + mali_pp_job_get_frame_builder_id(job) == (u32)args->fb_id && + mali_pp_job_get_flush_id(job) == (u32)args->flush_id) + { + if (args->wbx & _MALI_UK_PP_JOB_WB0) + { + mali_pp_job_disable_wb0(job); + } + if (args->wbx & _MALI_UK_PP_JOB_WB1) + { + mali_pp_job_disable_wb1(job); + } + if (args->wbx & _MALI_UK_PP_JOB_WB2) + { + mali_pp_job_disable_wb2(job); + } + break; + } + } + + mali_pp_scheduler_unlock(); +} + +void mali_pp_scheduler_abort_session(struct mali_session_data *session) +{ + struct mali_pp_job *job, *tmp; + int i; + + mali_pp_scheduler_lock(); + MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Aborting all jobs from session 0x%08x\n", session)); + + /* Check queue for jobs and remove */ + _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &job_queue, struct mali_pp_job, list) + { + if (mali_pp_job_get_session(job) == session) + { + _mali_osk_list_del(&(job->list)); + + if ( mali_pp_job_is_currently_rendering_and_if_so_abort_new_starts(job) ) + { + /* The job is in the render pipeline, we can not delete it yet. */ + /* It will be deleted in the mali_group_abort_session() call below */ + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Keeping partially started PP job 0x%08x in queue\n", job)); + continue; + } + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Removing PP job 0x%08x from queue\n", job)); + mali_pp_job_delete(job); + } + } + + mali_pp_scheduler_unlock(); + + /* Abort running jobs from this session */ + for (i = 0; i < num_slots; i++) + { + struct mali_group *group = slots[i].group; + + MALI_DEBUG_PRINT(5, ("PP sched abort: Looking at group 0x%08x\n", group)); + + if (MALI_PP_SLOT_STATE_WORKING == slots[i].state) + { + MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Aborting session 0x%08x from group 0x%08x\n", session, group)); + + mali_group_abort_session(group, session); + } + } +} + +static mali_bool mali_pp_scheduler_is_suspended(void) +{ + mali_bool ret; + + mali_pp_scheduler_lock(); + ret = pause_count > 0 && num_slots == num_slots_idle; + mali_pp_scheduler_unlock(); + + return ret; +} + +#if MALI_STATE_TRACKING +u32 mali_pp_scheduler_dump_state(char *buf, u32 size) +{ + int n = 0; + int i; + + n += _mali_osk_snprintf(buf + n, size - n, "PP:\n"); + n += _mali_osk_snprintf(buf + n, size - n, "\tQueue is %s\n", _mali_osk_list_empty(&job_queue) ? "empty" : "not empty"); + n += _mali_osk_snprintf(buf + n, size - n, "\n"); + + for (i = 0; i < num_slots; i++) + { + n += mali_group_dump_state(slots[i].group, buf + n, size - n); + n += _mali_osk_snprintf(buf + n, size - n, "\t\tState: %d\n", slots[i].state); + } + + return n; +} +#endif diff --git a/drivers/media/video/samsung/mali/common/mali_pp_scheduler.h b/drivers/media/video/samsung/mali/common/mali_pp_scheduler.h new file mode 100644 index 0000000..48eb3bd --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_pp_scheduler.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MALI_PP_SCHEDULER_H__ +#define __MALI_PP_SCHEDULER_H__ + +#include "mali_osk.h" +#include "mali_cluster.h" +#include "mali_pp_job.h" + +_mali_osk_errcode_t mali_pp_scheduler_initialize(void); +void mali_pp_scheduler_terminate(void); + +void mali_pp_scheduler_do_schedule(void); +void mali_pp_scheduler_job_done(struct mali_group *group, struct mali_pp_job *job, u32 sub_job, mali_bool success); + +void mali_pp_scheduler_suspend(void); +void mali_pp_scheduler_resume(void); + +/** @brief Abort all PP jobs from session running or queued + * + * This functions aborts all PP jobs from the specified session. Queued jobs are removed from the queue and jobs + * currently running on a core will be aborted. + * + * @param session Pointer to session whose jobs should be aborted + */ +void mali_pp_scheduler_abort_session(struct mali_session_data *session); + +u32 mali_pp_scheduler_dump_state(char *buf, u32 size); + +#endif /* __MALI_PP_SCHEDULER_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_scheduler.c b/drivers/media/video/samsung/mali/common/mali_scheduler.c new file mode 100644 index 0000000..52159a0 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_scheduler.c @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mali_kernel_common.h" +#include "mali_osk.h" + +static _mali_osk_atomic_t mali_job_autonumber; + +_mali_osk_errcode_t mali_scheduler_initialize(void) +{ + if ( _MALI_OSK_ERR_OK != _mali_osk_atomic_init(&mali_job_autonumber, 0)) + { + MALI_DEBUG_PRINT(1, ("Initialization of atomic job id counter failed.\n")); + return _MALI_OSK_ERR_FAULT; + } + + return _MALI_OSK_ERR_OK; +} + +void mali_scheduler_terminate(void) +{ + _mali_osk_atomic_term(&mali_job_autonumber); +} + +u32 mali_scheduler_get_new_id(void) +{ + u32 job_id = _mali_osk_atomic_inc_return(&mali_job_autonumber); + return job_id; +} diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_mem.h b/drivers/media/video/samsung/mali/common/mali_scheduler.h index 8caafe3..74f0947 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_mem.h +++ b/drivers/media/video/samsung/mali/common/mali_scheduler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -8,10 +8,14 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __MALI_KERNEL_MEM_H__ -#define __MALI_KERNEL_MEM_H__ +#ifndef __MALI_SCHEDULER_H__ +#define __MALI_SCHEDULER_H__ -#include "mali_kernel_subsystem.h" -extern struct mali_kernel_subsystem mali_subsystem_memory; +#include "mali_osk.h" -#endif /* __MALI_KERNEL_MEM_H__ */ +_mali_osk_errcode_t mali_scheduler_initialize(void); +void mali_scheduler_terminate(void); + +u32 mali_scheduler_get_new_id(void); + +#endif /* __MALI_SCHEDULER_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_session.c b/drivers/media/video/samsung/mali/common/mali_session.c new file mode 100644 index 0000000..2394bb9 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_session.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mali_osk.h" +#include "mali_osk_list.h" +#include "mali_session.h" + +_MALI_OSK_LIST_HEAD(mali_sessions); + +_mali_osk_lock_t *mali_sessions_lock; + +_mali_osk_errcode_t mali_session_initialize(void) +{ + _MALI_OSK_INIT_LIST_HEAD(&mali_sessions); + + mali_sessions_lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_READERWRITER | _MALI_OSK_LOCKFLAG_ORDERED, 0, _MALI_OSK_LOCK_ORDER_SESSIONS); + + if (NULL == mali_sessions_lock) return _MALI_OSK_ERR_NOMEM; + + return _MALI_OSK_ERR_OK; +} + +void mali_session_terminate(void) +{ + _mali_osk_lock_term(mali_sessions_lock); +} + +void mali_session_add(struct mali_session_data *session) +{ + mali_session_lock(); + _mali_osk_list_add(&session->link, &mali_sessions); + mali_session_unlock(); +} + +void mali_session_remove(struct mali_session_data *session) +{ + mali_session_lock(); + _mali_osk_list_delinit(&session->link); + mali_session_unlock(); +} diff --git a/drivers/media/video/samsung/mali/common/mali_session.h b/drivers/media/video/samsung/mali/common/mali_session.h new file mode 100644 index 0000000..b47c340 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_session.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2010, 2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MALI_SESSION_H__ +#define __MALI_SESSION_H__ + +#include "mali_mmu_page_directory.h" +#include "mali_kernel_descriptor_mapping.h" +#include "mali_osk.h" +#include "mali_osk_list.h" + +struct mali_session_data +{ + _mali_osk_notification_queue_t * ioctl_queue; + + _mali_osk_lock_t *memory_lock; /**< Lock protecting the vm manipulation */ + mali_descriptor_mapping * descriptor_mapping; /**< Mapping between userspace descriptors and our pointers */ + _mali_osk_list_t memory_head; /**< Track all the memory allocated in this session, for freeing on abnormal termination */ + + struct mali_page_directory *page_directory; /**< MMU page directory for this session */ + + _MALI_OSK_LIST_HEAD(link); /**< Link for list of all sessions */ +}; + +_mali_osk_errcode_t mali_session_initialize(void); +void mali_session_terminate(void); + +/* List of all sessions. Actual list head in mali_kernel_core.c */ +extern _mali_osk_list_t mali_sessions; +/* Lock to protect modification and access to the mali_sessions list */ +extern _mali_osk_lock_t *mali_sessions_lock; + +MALI_STATIC_INLINE void mali_session_lock(void) +{ + _mali_osk_lock_wait(mali_sessions_lock, _MALI_OSK_LOCKMODE_RW); +} + +MALI_STATIC_INLINE void mali_session_unlock(void) +{ + _mali_osk_lock_signal(mali_sessions_lock, _MALI_OSK_LOCKMODE_RW); +} + +void mali_session_add(struct mali_session_data *session); +void mali_session_remove(struct mali_session_data *session); +#define MALI_SESSION_FOREACH(session, tmp, link) \ + _MALI_OSK_LIST_FOREACHENTRY(session, tmp, &mali_sessions, struct mali_session_data, link) + +MALI_STATIC_INLINE struct mali_page_directory *mali_session_get_page_directory(struct mali_session_data *session) +{ + return session->page_directory; +} + +MALI_STATIC_INLINE void mali_session_send_notification(struct mali_session_data *session, _mali_osk_notification_t *object) +{ + _mali_osk_notification_queue_send(session->ioctl_queue, object); +} + +#endif /* __MALI_SESSION_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_ukk.h b/drivers/media/video/samsung/mali/common/mali_ukk.h index 94efdf5..8ff2002 100644 --- a/drivers/media/video/samsung/mali/common/mali_ukk.h +++ b/drivers/media/video/samsung/mali/common/mali_ukk.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -17,7 +17,7 @@ #define __MALI_UKK_H__ #include "mali_osk.h" -#include "mali_uk_types.h" +#include "../linux/mali_uk_types.h" #ifdef __cplusplus extern "C" @@ -139,14 +139,6 @@ extern "C" * (_mali_osk_mem_mapregion_init()) functions will collaborate on the * meaning of ukk_private member. On other OSs, it may be unused by both * U/K and OSK layers - * - On OS systems (not including direct function call U/K interface - * implementations), _mali_ukk_get_big_block() may succeed, but the subsequent - * copying to user space may fail. - * - A problem scenario exists: some memory has been reserved by - * _mali_ukk_get_big_block(), but the user-mode will be unaware of it (it will - * never receive any information about this memory). In this case, the U/K - * implementation must do everything necessary to 'rollback' the \em atomic - * _mali_ukk_get_big_block() transaction. * - Therefore, on error inside the U/K interface implementation itself, * it will be as though the _mali_ukk function itself had failed, and cleaned * up after itself. @@ -233,7 +225,7 @@ _mali_osk_errcode_t _mali_ukk_close( void **context ); * allocated, and a pointer to this memory written into the system_info member * of _mali_uk_get_system_info_s. * - * @param args see _mali_uk_get_system_info_size_s in "mali_uk_types.h" + * @param args see _mali_uk_get_system_info_size_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_get_system_info_size( _mali_uk_get_system_info_size_s *args ); @@ -270,7 +262,7 @@ _mali_osk_errcode_t _mali_ukk_get_system_info_size( _mali_uk_get_system_info_siz * destination address for pointer-patching to occur. When NULL, it is unused, an no pointer-patching occurs in the * common code. * - * @param args see _mali_uk_get_system_info_s in "mali_uk_types.h" + * @param args see _mali_uk_get_system_info_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_get_system_info( _mali_uk_get_system_info_s *args ); @@ -279,24 +271,37 @@ _mali_osk_errcode_t _mali_ukk_get_system_info( _mali_uk_get_system_info_s *args * * Sleeps until notified or a timeout occurs. Returns information about the notification. * - * @param args see _mali_uk_wait_for_notification_s in "mali_uk_types.h" + * @param args see _mali_uk_wait_for_notification_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_wait_for_notification( _mali_uk_wait_for_notification_s *args ); /** @brief Post a notification to the notification queue of this application. * - * @param args see _mali_uk_post_notification_s in "mali_uk_types.h" + * @param args see _mali_uk_post_notification_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_post_notification( _mali_uk_post_notification_s *args ); /** @brief Verifies if the user and kernel side of this API are compatible. * - * @param args see _mali_uk_get_api_version_s in "mali_uk_types.h" + * @param args see _mali_uk_get_api_version_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_get_api_version( _mali_uk_get_api_version_s *args ); + +/** @brief Get the user space settings applicable for calling process. + * + * @param args see _mali_uk_get_user_settings_s in "mali_utgard_uk_types.h" + */ +_mali_osk_errcode_t _mali_ukk_get_user_settings(_mali_uk_get_user_settings_s *args); + +/** @brief Get a user space setting applicable for calling process. + * + * @param args see _mali_uk_get_user_setting_s in "mali_utgard_uk_types.h" + */ +_mali_osk_errcode_t _mali_ukk_get_user_setting(_mali_uk_get_user_setting_s *args); + /** @} */ /* end group _mali_uk_core */ @@ -324,7 +329,7 @@ _mali_osk_errcode_t _mali_ukk_get_api_version( _mali_uk_get_api_version_s *args * @note This function is for Mali-MMU builds \b only. It should not be called * when the drivers are built without Mali-MMU support. * - * @param args see \ref _mali_uk_init_mem_s in mali_uk_types.h + * @param args see \ref _mali_uk_init_mem_s in mali_utgard_uk_types.h * @return _MALI_OSK_ERR_OK on success, otherwise a suitable * _mali_osk_errcode_t on failure. */ @@ -340,43 +345,18 @@ _mali_osk_errcode_t _mali_ukk_init_mem( _mali_uk_init_mem_s *args ); * @note This function is for Mali-MMU builds \b only. It should not be called * when the drivers are built without Mali-MMU support. * - * @param args see \ref _mali_uk_term_mem_s in mali_uk_types.h + * @param args see \ref _mali_uk_term_mem_s in mali_utgard_uk_types.h * @return _MALI_OSK_ERR_OK on success, otherwise a suitable * _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_term_mem( _mali_uk_term_mem_s *args ); -/** @brief Map a block of memory into the current user process - * - * Allocates a minimum of minimum_size_requested bytes of MALI memory and maps it into the current - * process space. The number of bytes allocated is returned in args->block_size. - * - * This is only used for Mali-nonMMU mode. - * - * @param args see _mali_uk_get_big_block_s in "mali_uk_types.h" - * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. - */ -_mali_osk_errcode_t _mali_ukk_get_big_block( _mali_uk_get_big_block_s *args ); - -/** @brief Unmap a block of memory from the current user process - * - * Frees allocated MALI memory and unmaps it from the current process space. The previously allocated memory - * is indicated by the cookie as returned by _mali_ukk_get_big_block(). - * - * This is only used for Mali-nonMMU mode. - * - * @param args see _mali_uk_free_big_block_s in "mali_uk_types.h" - * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. - */ -_mali_osk_errcode_t _mali_ukk_free_big_block( _mali_uk_free_big_block_s *args ); - /** @brief Map Mali Memory into the current user process * * Maps Mali memory into the current user process in a generic way. * * This function is to be used for Mali-MMU mode. The function is available in both Mali-MMU and Mali-nonMMU modes, - * but should not be called by a user process in Mali-nonMMU mode. In Mali-nonMMU mode, the function is callable - * from the kernel side, and is used to implement _mali_ukk_get_big_block() in this case. + * but should not be called by a user process in Mali-nonMMU mode. * * The implementation and operation of _mali_ukk_mem_mmap() is dependant on whether the driver is built for Mali-MMU * or Mali-nonMMU: @@ -392,9 +372,6 @@ _mali_osk_errcode_t _mali_ukk_free_big_block( _mali_uk_free_big_block_s *args ); * they are unnecsessary; the \em Mali-virtual address range must be used for * programming Mali structures. * - * This means that in the first (nonMMU) case, the caller must manage the physical address allocations. The caller - * in this case is _mali_ukk_get_big_block(), which does indeed manage the Mali physical address ranges. - * * In the second (MMU) case, _mali_ukk_mem_mmap() handles management of * CPU-virtual and CPU-physical ranges, but the \em caller must manage the * \em Mali-virtual address range from the user-side. @@ -403,7 +380,7 @@ _mali_osk_errcode_t _mali_ukk_free_big_block( _mali_uk_free_big_block_s *args ); * It is not possible for a process to accidentally corrupt another process' * \em Mali-virtual address space. * - * @param args see _mali_uk_mem_mmap_s in "mali_uk_types.h" + * @param args see _mali_uk_mem_mmap_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_mem_mmap( _mali_uk_mem_mmap_s *args ); @@ -413,42 +390,42 @@ _mali_osk_errcode_t _mali_ukk_mem_mmap( _mali_uk_mem_mmap_s *args ); * Unmaps Mali memory from the current user process in a generic way. This only operates on Mali memory supplied * from _mali_ukk_mem_mmap(). * - * @param args see _mali_uk_mem_munmap_s in "mali_uk_types.h" + * @param args see _mali_uk_mem_munmap_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_mem_munmap( _mali_uk_mem_munmap_s *args ); /** @brief Determine the buffer size necessary for an MMU page table dump. - * @param args see _mali_uk_query_mmu_page_table_dump_size_s in mali_uk_types.h + * @param args see _mali_uk_query_mmu_page_table_dump_size_s in mali_utgard_uk_types.h * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_query_mmu_page_table_dump_size( _mali_uk_query_mmu_page_table_dump_size_s *args ); /** @brief Dump MMU Page tables. - * @param args see _mali_uk_dump_mmu_page_table_s in mali_uk_types.h + * @param args see _mali_uk_dump_mmu_page_table_s in mali_utgard_uk_types.h * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_dump_mmu_page_table( _mali_uk_dump_mmu_page_table_s * args ); /** @brief Map a physically contiguous range of memory into Mali - * @param args see _mali_uk_map_external_mem_s in mali_uk_types.h + * @param args see _mali_uk_map_external_mem_s in mali_utgard_uk_types.h * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_map_external_mem( _mali_uk_map_external_mem_s *args ); /** @brief Unmap a physically contiguous range of memory from Mali - * @param args see _mali_uk_unmap_external_mem_s in mali_uk_types.h + * @param args see _mali_uk_unmap_external_mem_s in mali_utgard_uk_types.h * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_unmap_external_mem( _mali_uk_unmap_external_mem_s *args ); #if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 /** @brief Map UMP memory into Mali - * @param args see _mali_uk_attach_ump_mem_s in mali_uk_types.h + * @param args see _mali_uk_attach_ump_mem_s in mali_utgard_uk_types.h * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_attach_ump_mem( _mali_uk_attach_ump_mem_s *args ); /** @brief Unmap UMP memory from Mali - * @param args see _mali_uk_release_ump_mem_s in mali_uk_types.h + * @param args see _mali_uk_release_ump_mem_s in mali_utgard_uk_types.h * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_release_ump_mem( _mali_uk_release_ump_mem_s *args ); @@ -492,7 +469,7 @@ _mali_osk_errcode_t _mali_ukk_release_ump_mem( _mali_uk_release_ump_mem_s *args * @note if implemented, this function is entirely platform-dependant, and does * not exist in common code. * - * @param args see _mali_uk_va_to_mali_pa_s in "mali_uk_types.h" + * @param args see _mali_uk_va_to_mali_pa_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_va_to_mali_pa( _mali_uk_va_to_mali_pa_s * args ); @@ -519,20 +496,16 @@ _mali_osk_errcode_t _mali_ukk_va_to_mali_pa( _mali_uk_va_to_mali_pa_s * args ); * existing one returned, otherwise the new job is started and the status field args->status is set to * _MALI_UK_START_JOB_STARTED. * - * If an existing lower priority job is returned, args->returned_user_job_ptr contains a - * pointer to the returned job and the status field args->status is set to - * _MALI_UK_START_JOB_STARTED_LOW_PRI_JOB_RETURNED. - * * Job completion can be awaited with _mali_ukk_wait_for_notification(). * - * @param args see _mali_uk_pp_start_job_s in "mali_uk_types.h" + * @param args see _mali_uk_pp_start_job_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_pp_start_job( _mali_uk_pp_start_job_s *args ); /** @brief Returns the number of Fragment Processors in the system * - * @param args see _mali_uk_get_pp_number_of_cores_s in "mali_uk_types.h" + * @param args see _mali_uk_get_pp_number_of_cores_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_get_pp_number_of_cores( _mali_uk_get_pp_number_of_cores_s *args ); @@ -542,22 +515,18 @@ _mali_osk_errcode_t _mali_ukk_get_pp_number_of_cores( _mali_uk_get_pp_number_of_ * This function may only be called when _mali_ukk_get_pp_number_of_cores() indicated at least one Fragment * Processor core is available. * - * @param args see _mali_uk_get_pp_core_version_s in "mali_uk_types.h" + * @param args see _mali_uk_get_pp_core_version_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_get_pp_core_version( _mali_uk_get_pp_core_version_s *args ); -/** @brief Abort any PP jobs with the given ID. +/** @brief Disable Write-back unit(s) on specified job * - * Jobs internally queued or currently running on the hardware is to be stopped/aborted. - * Jobs aborted are reported via the normal job completion system. - * Any jobs, running or internally queued should be aborted imediately. - * Normal notifiction procedures to report on the status of these jobs. - * - * - * @param args see _malu_uk_pp_abort_job_s in "mali_uk_types.h" + * @param args see _mali_uk_get_pp_core_version_s in "mali_utgard_uk_types.h" */ -void _mali_ukk_pp_abort_job( _mali_uk_pp_abort_job_s *args ); +void _mali_ukk_pp_job_disable_wb(_mali_uk_pp_disable_wb_s *args); + + /** @} */ /* end group _mali_uk_pp */ @@ -580,20 +549,16 @@ void _mali_ukk_pp_abort_job( _mali_uk_pp_abort_job_s *args ); * existing one returned, otherwise the new job is started and the status field args->status is set to * _MALI_UK_START_JOB_STARTED. * - * If an existing lower priority job is returned, args->returned_user_job_ptr contains a pointer to - * the returned job and the status field args->status is set to - * _MALI_UK_START_JOB_STARTED_LOW_PRI_JOB_RETURNED. - * * Job completion can be awaited with _mali_ukk_wait_for_notification(). * - * @param args see _mali_uk_gp_start_job_s in "mali_uk_types.h" + * @param args see _mali_uk_gp_start_job_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_gp_start_job( _mali_uk_gp_start_job_s *args ); /** @brief Returns the number of Vertex Processors in the system. * - * @param args see _mali_uk_get_gp_number_of_cores_s in "mali_uk_types.h" + * @param args see _mali_uk_get_gp_number_of_cores_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_get_gp_number_of_cores( _mali_uk_get_gp_number_of_cores_s *args ); @@ -603,7 +568,7 @@ _mali_osk_errcode_t _mali_ukk_get_gp_number_of_cores( _mali_uk_get_gp_number_of_ * This function may only be called when _mali_uk_get_gp_number_of_cores() indicated at least one Vertex * Processor core is available. * - * @param args see _mali_uk_get_gp_core_version_s in "mali_uk_types.h" + * @param args see _mali_uk_get_gp_core_version_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_get_gp_core_version( _mali_uk_get_gp_core_version_s *args ); @@ -613,85 +578,47 @@ _mali_osk_errcode_t _mali_ukk_get_gp_core_version( _mali_uk_get_gp_core_version_ * After receiving notification that a Vertex Processor job was suspended from * _mali_ukk_wait_for_notification() you can use this function to resume or abort the job. * - * @param args see _mali_uk_gp_suspend_response_s in "mali_uk_types.h" + * @param args see _mali_uk_gp_suspend_response_s in "mali_utgard_uk_types.h" * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. */ _mali_osk_errcode_t _mali_ukk_gp_suspend_response( _mali_uk_gp_suspend_response_s *args ); -/** @brief Abort any GP jobs with the given ID. - * - * Jobs internally queued or currently running on the hardware is to be stopped/aborted. - * Jobs aborted are reported via the normal job completion system. - * - * Any jobs, running or internally queued should be aborted imediately. - * Normal notifiction procedures to report on the status of these jobs. - * - * @param args see _mali_uk_gp_abort_job_s in "mali_uk_types.h" - */ -void _mali_ukk_gp_abort_job( _mali_uk_gp_abort_job_s *args ); /** @} */ /* end group _mali_uk_gp */ -#if USING_MALI_PMM -/** @addtogroup _mali_uk_pmm U/K Power Management Module - * @{ */ - -/* @brief Power Management Module event message - * - * @note The event message can fail to be sent due to OOM but this is - * stored in the PMM state machine to be handled later - * - * @param args see _mali_uk_pmm_event_message_s in "mali_uk_types.h" - */ -void _mali_ukk_pmm_event_message( _mali_uk_pmm_message_s *args ); -/** @} */ /* end group _mali_uk_pmm */ -#endif /* USING_MALI_PMM */ - #if MALI_TIMELINE_PROFILING_ENABLED /** @addtogroup _mali_uk_profiling U/K Timeline profiling module * @{ */ /** @brief Start recording profiling events. * - * @param args see _mali_uk_profiling_start_s in "mali_uk_types.h" + * @param args see _mali_uk_profiling_start_s in "mali_utgard_uk_types.h" */ _mali_osk_errcode_t _mali_ukk_profiling_start(_mali_uk_profiling_start_s *args); /** @brief Add event to profiling buffer. * - * @param args see _mali_uk_profiling_add_event_s in "mali_uk_types.h" + * @param args see _mali_uk_profiling_add_event_s in "mali_utgard_uk_types.h" */ _mali_osk_errcode_t _mali_ukk_profiling_add_event(_mali_uk_profiling_add_event_s *args); /** @brief Stop recording profiling events. * - * @param args see _mali_uk_profiling_stop_s in "mali_uk_types.h" + * @param args see _mali_uk_profiling_stop_s in "mali_utgard_uk_types.h" */ _mali_osk_errcode_t _mali_ukk_profiling_stop(_mali_uk_profiling_stop_s *args); /** @brief Retrieve a recorded profiling event. * - * @param args see _mali_uk_profiling_get_event_s in "mali_uk_types.h" + * @param args see _mali_uk_profiling_get_event_s in "mali_utgard_uk_types.h" */ _mali_osk_errcode_t _mali_ukk_profiling_get_event(_mali_uk_profiling_get_event_s *args); /** @brief Clear recorded profiling events. * - * @param args see _mali_uk_profiling_clear_s in "mali_uk_types.h" + * @param args see _mali_uk_profiling_clear_s in "mali_utgard_uk_types.h" */ _mali_osk_errcode_t _mali_ukk_profiling_clear(_mali_uk_profiling_clear_s *args); -/** @brief Get the profiling config applicable for calling process. - * - * @param args see _mali_uk_profiling_get_config_s in "mali_uk_types.h" - */ -_mali_osk_errcode_t _mali_ukk_profiling_get_config(_mali_uk_profiling_get_config_s *args); - -/** @brief Transfer software counters from user to kernel space - * - * @param args see _mali_uk_transfer_sw_counters_s in "mali_uk_types.h" - */ -_mali_osk_errcode_t _mali_ukk_transfer_sw_counters(_mali_uk_sw_counters_s *args); - /** @} */ /* end group _mali_uk_profiling */ #endif @@ -704,12 +631,23 @@ _mali_osk_errcode_t _mali_ukk_transfer_sw_counters(_mali_uk_sw_counters_s *args) * waiting is finished. This information can then be used in kernel space to * complement the GPU utilization metric. * - * @param args see _mali_uk_vsync_event_report_s in "mali_uk_types.h" + * @param args see _mali_uk_vsync_event_report_s in "mali_utgard_uk_types.h" */ _mali_osk_errcode_t _mali_ukk_vsync_event_report(_mali_uk_vsync_event_report_s *args); /** @} */ /* end group _mali_uk_vsync */ +/** @addtogroup _mali_sw_counters_report U/K Software counter reporting + * @{ */ + +/** @brief Report software counters. + * + * @param args see _mali_uk_sw_counters_report_s in "mali_uk_types.h" + */ +_mali_osk_errcode_t _mali_ukk_sw_counters_report(_mali_uk_sw_counters_report_s *args); + +/** @} */ /* end group _mali_sw_counters_report */ + /** @} */ /* end group u_k_api */ /** @} */ /* end group uddapi */ diff --git a/drivers/media/video/samsung/mali/common/mali_user_settings_db.c b/drivers/media/video/samsung/mali/common/mali_user_settings_db.c new file mode 100644 index 0000000..681c2b0 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_user_settings_db.c @@ -0,0 +1,88 @@ +/** + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mali_osk.h" +#include "mali_kernel_common.h" +#include "mali_uk_types.h" +#include "mali_user_settings_db.h" +#include "mali_session.h" + +static u32 mali_user_settings[_MALI_UK_USER_SETTING_MAX]; +const char *_mali_uk_user_setting_descriptions[] = _MALI_UK_USER_SETTING_DESCRIPTIONS; + +static void mali_user_settings_notify(_mali_uk_user_setting_t setting, u32 value) +{ + struct mali_session_data *session, *tmp; + + mali_session_lock(); + MALI_SESSION_FOREACH(session, tmp, link) + { + _mali_osk_notification_t *notobj = _mali_osk_notification_create(_MALI_NOTIFICATION_SETTINGS_CHANGED, sizeof(_mali_uk_settings_changed_s)); + _mali_uk_settings_changed_s *data = notobj->result_buffer; + data->setting = setting; + data->value = value; + + mali_session_send_notification(session, notobj); + } + mali_session_unlock(); +} + +void mali_set_user_setting(_mali_uk_user_setting_t setting, u32 value) +{ + mali_bool notify = MALI_FALSE; + + MALI_DEBUG_ASSERT(setting < _MALI_UK_USER_SETTING_MAX && setting >= 0); + + if (mali_user_settings[setting] != value) + { + notify = MALI_TRUE; + } + + mali_user_settings[setting] = value; + + if (notify) + { + mali_user_settings_notify(setting, value); + } +} + +u32 mali_get_user_setting(_mali_uk_user_setting_t setting) +{ + MALI_DEBUG_ASSERT(setting < _MALI_UK_USER_SETTING_MAX && setting >= 0); + + return mali_user_settings[setting]; +} + +_mali_osk_errcode_t _mali_ukk_get_user_setting(_mali_uk_get_user_setting_s *args) +{ + _mali_uk_user_setting_t setting; + MALI_DEBUG_ASSERT_POINTER(args); + + setting = args->setting; + + if (0 <= setting && _MALI_UK_USER_SETTING_MAX > setting) + { + args->value = mali_user_settings[setting]; + return _MALI_OSK_ERR_OK; + } + else + { + return _MALI_OSK_ERR_INVALID_ARGS; + } +} + +_mali_osk_errcode_t _mali_ukk_get_user_settings(_mali_uk_get_user_settings_s *args) +{ + MALI_DEBUG_ASSERT_POINTER(args); + + _mali_osk_memcpy(args->settings, mali_user_settings, (sizeof(u32) * _MALI_UK_USER_SETTING_MAX)); + + return _MALI_OSK_ERR_OK; +} diff --git a/drivers/media/video/samsung/mali/common/mali_user_settings_db.h b/drivers/media/video/samsung/mali/common/mali_user_settings_db.h new file mode 100644 index 0000000..fbb9415 --- /dev/null +++ b/drivers/media/video/samsung/mali/common/mali_user_settings_db.h @@ -0,0 +1,40 @@ +/** + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MALI_USER_SETTINGS_DB_H__ +#define __MALI_USER_SETTINGS_DB_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "mali_uk_types.h" + +/** @brief Set Mali user setting in DB + * + * Update the DB with a new value for \a setting. If the value is different from theprevious set value running sessions will be notified of the change. + * + * @param setting the setting to be changed + * @param value the new value to set + */ +void mali_set_user_setting(_mali_uk_user_setting_t setting, u32 value); + +/** @brief Get current Mali user setting value from DB + * + * @param setting the setting to extract + * @return the value of the selected setting + */ +u32 mali_get_user_setting(_mali_uk_user_setting_t setting); + +#ifdef __cplusplus +} +#endif +#endif /* __MALI_KERNEL_USER_SETTING__ */ diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm.c b/drivers/media/video/samsung/mali/common/pmm/mali_pmm.c deleted file mode 100644 index 7041391..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm.c +++ /dev/null @@ -1,1024 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** - * @file mali_pmm.c - * Implementation of the power management module for the kernel device driver - */ - -#if USING_MALI_PMM - -#include "mali_ukk.h" -#include "mali_kernel_common.h" -#include "mali_kernel_subsystem.h" - -#include "mali_pmm.h" -#include "mali_pmm_system.h" -#include "mali_pmm_state.h" -#include "mali_pmm_policy.h" -#include "mali_pmm_pmu.h" -#include "mali_platform.h" -#include "mali_kernel_pm.h" - -/* Internal PMM subsystem state */ -static _mali_pmm_internal_state_t *pmm_state = NULL; -/* Mali kernel subsystem id */ -static mali_kernel_subsystem_identifier mali_subsystem_pmm_id = -1; - -#define GET_PMM_STATE_PTR (pmm_state) - -/* Internal functions */ -static _mali_osk_errcode_t malipmm_create(_mali_osk_resource_t *resource); -static void pmm_event_process( void ); -_mali_osk_errcode_t malipmm_irq_uhandler(void *data); -void malipmm_irq_bhandler(void *data); - -/** @brief Start the PMM subsystem - * - * @param id Subsystem id to uniquely identify this subsystem - * @return _MALI_OSK_ERR_OK if the system started successfully, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t malipmm_kernel_subsystem_start( mali_kernel_subsystem_identifier id ); - -/** @brief Perform post start up of the PMM subsystem - * - * Post start up includes initializing the current policy, now that the system is - * completely started - to stop policies turning off hardware during the start up - * - * @param id the unique subsystem id - * @return _MALI_OSK_ERR_OK if the post startup was successful, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t malipmm_kernel_load_complete( mali_kernel_subsystem_identifier id ); - -/** @brief Terminate the PMM subsystem - * - * @param id the unique subsystem id - */ -void malipmm_kernel_subsystem_terminate( mali_kernel_subsystem_identifier id ); - -#if MALI_STATE_TRACKING -u32 malipmm_subsystem_dump_state( char *buf, u32 size ); -#endif - - -/* This will be one of the subsystems in the array of subsystems: - static struct mali_kernel_subsystem * subsystems[]; - found in file: mali_kernel_core.c -*/ -struct mali_kernel_subsystem mali_subsystem_pmm= -{ - malipmm_kernel_subsystem_start, /* startup */ - NULL, /*malipmm_kernel_subsystem_terminate,*/ /* shutdown */ - malipmm_kernel_load_complete, /* loaded all subsystems */ - NULL, - NULL, - NULL, - NULL, -#if MALI_STATE_TRACKING - malipmm_subsystem_dump_state, /* dump_state */ -#endif -}; - -#if PMM_OS_TEST - -u32 power_test_event = 0; -mali_bool power_test_flag = MALI_FALSE; -_mali_osk_timer_t *power_test_timer = NULL; - -void _mali_osk_pmm_power_up_done(mali_pmm_message_data data) -{ - MALI_PRINT(("POWER TEST OS UP DONE\n")); -} - -void _mali_osk_pmm_power_down_done(mali_pmm_message_data data) -{ - MALI_PRINT(("POWER TEST OS DOWN DONE\n")); -} - -/** - * Symbian OS Power Up call to the driver - */ -void power_test_callback( void *arg ) -{ - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - MALI_DEBUG_ASSERT_POINTER(pmm); - - power_test_flag = MALI_TRUE; - _mali_osk_irq_schedulework( pmm->irq ); -} - -void power_test_start() -{ - power_test_timer = _mali_osk_timer_init(); - _mali_osk_timer_setcallback( power_test_timer, power_test_callback, NULL ); - - /* First event is power down */ - power_test_event = MALI_PMM_EVENT_OS_POWER_DOWN; - _mali_osk_timer_add( power_test_timer, 10000 ); -} - -mali_bool power_test_check() -{ - if( power_test_flag ) - { - _mali_uk_pmm_message_s event = { - NULL, - 0, - 1 }; - event.id = power_test_event; - - power_test_flag = MALI_FALSE; - - /* Send event */ - _mali_ukk_pmm_event_message( &event ); - - /* Switch to next event to test */ - if( power_test_event == MALI_PMM_EVENT_OS_POWER_DOWN ) - { - power_test_event = MALI_PMM_EVENT_OS_POWER_UP; - } - else - { - power_test_event = MALI_PMM_EVENT_OS_POWER_DOWN; - } - _mali_osk_timer_add( power_test_timer, 5000 ); - - return MALI_TRUE; - } - - return MALI_FALSE; -} - -void power_test_end() -{ - _mali_osk_timer_del( power_test_timer ); - _mali_osk_timer_term( power_test_timer ); - power_test_timer = NULL; -} - -#endif - -void _mali_ukk_pmm_event_message( _mali_uk_pmm_message_s *args ) -{ - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - _mali_osk_notification_t *msg; - mali_pmm_message_t *event; - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_DEBUG_ASSERT_POINTER(args); - - MALIPMM_DEBUG_PRINT( ("PMM: sending message\n") ); - -#if MALI_PMM_TRACE && MALI_PMM_TRACE_SENT_EVENTS - _mali_pmm_trace_event_message( args, MALI_FALSE ); -#endif - - msg = _mali_osk_notification_create( MALI_PMM_NOTIFICATION_TYPE, sizeof( mali_pmm_message_t ) ); - - if( msg ) - { - event = (mali_pmm_message_t *)msg->result_buffer; - event->id = args->id; - event->ts = _mali_osk_time_tickcount(); - event->data = args->data; - - _mali_osk_atomic_inc( &(pmm->messages_queued) ); - - if( args->id > MALI_PMM_EVENT_INTERNALS ) - { - /* Internal PMM message */ - _mali_osk_notification_queue_send( pmm->iqueue, msg ); - #if (MALI_PMM_TRACE || MALI_STATE_TRACKING) - pmm->imessages_sent++; - #endif - } - else - { - /* Real event */ - _mali_osk_notification_queue_send( pmm->queue, msg ); - #if (MALI_PMM_TRACE || MALI_STATE_TRACKING) - pmm->messages_sent++; - #endif - } - } - else - { - MALI_PRINT_ERROR( ("PMM: Could not send message %d", args->id) ); - /* Make note of this OOM - which has caused a missed event */ - pmm->missed++; - } - - /* Schedule time to look at the event or the fact we couldn't create an event */ - _mali_osk_irq_schedulework( pmm->irq ); -} - -mali_pmm_state _mali_pmm_state( void ) -{ - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - MALI_DEBUG_ASSERT_POINTER(pmm); - - if( pmm && (mali_subsystem_pmm_id != -1) ) - { - return pmm->state; - } - - /* No working subsystem yet */ - return MALI_PMM_STATE_UNAVAILABLE; -} - - -mali_pmm_core_mask _mali_pmm_cores_list( void ) -{ - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - MALI_DEBUG_ASSERT_POINTER(pmm); - - return pmm->cores_registered; -} - -mali_pmm_core_mask _mali_pmm_cores_powered( void ) -{ - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - MALI_DEBUG_ASSERT_POINTER(pmm); - - return pmm->cores_powered; -} - - -_mali_osk_errcode_t _mali_pmm_list_policies( - u32 policy_list_size, - mali_pmm_policy *policy_list, - u32 *policies_available ) -{ - /* TBD - This is currently a stub function for basic power management */ - - MALI_ERROR( _MALI_OSK_ERR_UNSUPPORTED ); -} - -_mali_osk_errcode_t _mali_pmm_set_policy( mali_pmm_policy policy ) -{ - /* TBD - This is currently a stub function for basic power management */ - -/* TBD - When this is not a stub... include tracing... -#if MALI_PMM_TRACE - _mali_pmm_trace_policy_change( old, newpolicy ); -#endif -*/ - MALI_ERROR( _MALI_OSK_ERR_UNSUPPORTED ); -} - -_mali_osk_errcode_t _mali_pmm_get_policy( mali_pmm_policy *policy ) -{ - if( policy ) - { - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - MALI_DEBUG_ASSERT_POINTER(pmm); - - if( pmm ) - { - *policy = pmm->policy; - MALI_SUCCESS; - } - else - { - *policy = MALI_PMM_POLICY_NONE; - MALI_ERROR( _MALI_OSK_ERR_FAULT ); - } - } - - /* No return argument */ - MALI_ERROR( _MALI_OSK_ERR_INVALID_ARGS ); -} - -#if ( MALI_PMM_TRACE || MALI_STATE_TRACKING ) - -/* Event names - order must match mali_pmm_event_id enum */ -static char *pmm_trace_events[] = { - "OS_POWER_UP", - "OS_POWER_DOWN", - "JOB_SCHEDULED", - "JOB_QUEUED", - "JOB_FINISHED", - "TIMEOUT", -}; - -/* State names - order must match mali_pmm_state enum */ -static char *pmm_trace_state[] = { - "UNAVAILABLE", - "SYSTEM ON", - "SYSTEM OFF", - "SYSTEM TRANSITION", -}; - -/* Policy names - order must match mali_pmm_policy enum */ -static char *pmm_trace_policy[] = { - "NONE", - "ALWAYS ON", - "JOB CONTROL", -}; - -/* Status names - order must match mali_pmm_status enum */ -static char *pmm_trace_status[] = { - "MALI_PMM_STATUS_IDLE", /**< PMM is waiting next event */ - "MALI_PMM_STATUS_POLICY_POWER_DOWN", /**< Policy initiated power down */ - "MALI_PMM_STATUS_POLICY_POWER_UP", /**< Policy initiated power down */ - "MALI_PMM_STATUS_OS_WAITING", /**< PMM is waiting for OS power up */ - "MALI_PMM_STATUS_OS_POWER_DOWN", /**< OS initiated power down */ - "MALI_PMM_STATUS_RUNTIME_IDLE_IN_PROGRESS", - "MALI_PMM_STATUS_DVFS_PAUSE", /**< PMM DVFS Status Pause */ - "MALI_PMM_STATUS_OS_POWER_UP", /**< OS initiated power up */ - "MALI_PMM_STATUS_OFF", /**< PMM is not active */ -}; - -#endif /* MALI_PMM_TRACE || MALI_STATE_TRACKING */ -#if MALI_PMM_TRACE - -/* UK event names - order must match mali_pmm_event_id enum */ -static char *pmm_trace_events_uk[] = { - "UKS", - "UK_EXAMPLE", -}; - -/* Internal event names - order must match mali_pmm_event_id enum */ -static char *pmm_trace_events_internal[] = { - "INTERNALS", - "INTERNAL_POWER_UP_ACK", - "INTERNAL_POWER_DOWN_ACK", -}; - -void _mali_pmm_trace_hardware_change( mali_pmm_core_mask old, mali_pmm_core_mask newstate ) -{ - const char *dname; - const char *cname; - const char *ename; - - if( old != newstate ) - { - if( newstate == 0 ) - { - dname = "NO cores"; - } - else - { - dname = pmm_trace_get_core_name( newstate ); - } - - /* These state checks only work if the assumption that only cores can be - * turned on or turned off in seperate actions is true. If core power states can - * be toggled (some one, some off) at the same time, this check does not work - */ - if( old > newstate ) - { - /* Cores have turned off */ - cname = pmm_trace_get_core_name( old - newstate ); - ename = "OFF"; - } - else - { - /* Cores have turned on */ - cname = pmm_trace_get_core_name( newstate - old ); - ename = "ON"; - } - MALI_PRINT( ("PMM Trace: Hardware %s ON, %s just turned %s. { 0x%08x -> 0x%08x }", dname, cname, ename, old, newstate) ); - } -} - -void _mali_pmm_trace_state_change( mali_pmm_state old, mali_pmm_state newstate ) -{ - if( old != newstate ) - { - MALI_PRINT( ("PMM Trace: State changed from %s to %s", pmm_trace_state[old], pmm_trace_state[newstate]) ); - } -} - -void _mali_pmm_trace_policy_change( mali_pmm_policy old, mali_pmm_policy newpolicy ) -{ - if( old != newpolicy ) - { - MALI_PRINT( ("PMM Trace: Policy changed from %s to %s", pmm_trace_policy[old], pmm_trace_policy[newpolicy]) ); - } -} - -void _mali_pmm_trace_event_message( mali_pmm_message_t *event, mali_bool received ) -{ - const char *ename; - const char *dname; - const char *tname; - const char *format = "PMM Trace: Event %s { (%d) %s, %d ticks, (0x%x) %s }"; - - MALI_DEBUG_ASSERT_POINTER(event); - - tname = (received) ? "received" : "sent"; - - if( event->id >= MALI_PMM_EVENT_INTERNALS ) - { - ename = pmm_trace_events_internal[((int)event->id) - MALI_PMM_EVENT_INTERNALS]; - } - else if( event->id >= MALI_PMM_EVENT_UKS ) - { - ename = pmm_trace_events_uk[((int)event->id) - MALI_PMM_EVENT_UKS]; - } - else - { - ename = pmm_trace_events[event->id]; - } - - switch( event->id ) - { - case MALI_PMM_EVENT_OS_POWER_UP: - case MALI_PMM_EVENT_OS_POWER_DOWN: - dname = "os event"; - break; - - case MALI_PMM_EVENT_JOB_SCHEDULED: - case MALI_PMM_EVENT_JOB_QUEUED: - case MALI_PMM_EVENT_JOB_FINISHED: - case MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK: - case MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK: - dname = pmm_trace_get_core_name( (mali_pmm_core_mask)event->data ); - break; - - case MALI_PMM_EVENT_TIMEOUT: - dname = "timeout start"; - /* Print data with a different format */ - format = "PMM Trace: Event %s { (%d) %s, %d ticks, %d ticks %s }"; - break; - default: - dname = "unknown data"; - } - - MALI_PRINT( (format, tname, (u32)event->id, ename, event->ts, (u32)event->data, dname) ); -} - -#endif /* MALI_PMM_TRACE */ - - -/****************** Mali Kernel API *****************/ - -_mali_osk_errcode_t malipmm_kernel_subsystem_start( mali_kernel_subsystem_identifier id ) -{ - mali_subsystem_pmm_id = id; - MALI_CHECK_NO_ERROR(_mali_kernel_core_register_resource_handler(PMU, malipmm_create)); - MALI_SUCCESS; -} - -_mali_osk_errcode_t malipmm_create(_mali_osk_resource_t *resource) -{ - /* Create PMM state memory */ - MALI_DEBUG_ASSERT( pmm_state == NULL ); - pmm_state = (_mali_pmm_internal_state_t *) _mali_osk_malloc(sizeof(*pmm_state)); - MALI_CHECK_NON_NULL( pmm_state, _MALI_OSK_ERR_NOMEM ); - - /* All values get 0 as default */ - _mali_osk_memset(pmm_state, 0, sizeof(*pmm_state)); - - /* Set up the initial PMM state */ - pmm_state->waiting = 0; - pmm_state->status = MALI_PMM_STATUS_IDLE; - pmm_state->state = MALI_PMM_STATE_UNAVAILABLE; /* Until a core registers */ - - /* Set up policy via compile time option for the moment */ -#if MALI_PMM_ALWAYS_ON - pmm_state->policy = MALI_PMM_POLICY_ALWAYS_ON; -#else - pmm_state->policy = MALI_PMM_POLICY_JOB_CONTROL; -#endif - -#if MALI_PMM_TRACE - _mali_pmm_trace_policy_change( MALI_PMM_POLICY_NONE, pmm_state->policy ); -#endif - - /* Set up assumes all values are initialized to NULL or MALI_FALSE, so - * we can exit halfway through set up and perform clean up - */ - -#if USING_MALI_PMU - if( mali_pmm_pmu_init(resource) != _MALI_OSK_ERR_OK ) goto pmm_fail_cleanup; - pmm_state->pmu_initialized = MALI_TRUE; -#endif - pmm_state->queue = _mali_osk_notification_queue_init(); - if( !pmm_state->queue ) goto pmm_fail_cleanup; - - pmm_state->iqueue = _mali_osk_notification_queue_init(); - if( !pmm_state->iqueue ) goto pmm_fail_cleanup; - - /* We are creating an IRQ handler just for the worker thread it gives us */ - pmm_state->irq = _mali_osk_irq_init( _MALI_OSK_IRQ_NUMBER_PMM, - malipmm_irq_uhandler, - malipmm_irq_bhandler, - NULL, - NULL, - (void *)pmm_state, /* PMM state is passed to IRQ */ - "PMM handler" ); - - if( !pmm_state->irq ) goto pmm_fail_cleanup; - - pmm_state->lock = _mali_osk_lock_init((_mali_osk_lock_flags_t)(_MALI_OSK_LOCKFLAG_READERWRITER | _MALI_OSK_LOCKFLAG_ORDERED), 0, 75); - if( !pmm_state->lock ) goto pmm_fail_cleanup; - - if( _mali_osk_atomic_init( &(pmm_state->messages_queued), 0 ) != _MALI_OSK_ERR_OK ) - { - goto pmm_fail_cleanup; - } - - MALIPMM_DEBUG_PRINT( ("PMM: subsystem created, policy=%d\n", pmm_state->policy) ); - - MALI_SUCCESS; - -pmm_fail_cleanup: - MALI_PRINT_ERROR( ("PMM: subsystem failed to be created\n") ); - if( pmm_state ) - { - if( pmm_state->lock ) _mali_osk_lock_term( pmm_state->lock ); - if( pmm_state->irq ) _mali_osk_irq_term( pmm_state->irq ); - if( pmm_state->queue ) _mali_osk_notification_queue_term( pmm_state->queue ); - if( pmm_state->iqueue ) _mali_osk_notification_queue_term( pmm_state->iqueue ); -#if USING_MALI_PMU - if( pmm_state->pmu_initialized ) - { - _mali_osk_resource_type_t t = PMU; - mali_pmm_pmu_deinit(&t); - } -#endif /* USING_MALI_PMU */ - - _mali_osk_free(pmm_state); - pmm_state = NULL; - } - MALI_ERROR( _MALI_OSK_ERR_FAULT ); -} - -_mali_osk_errcode_t malipmm_kernel_load_complete( mali_kernel_subsystem_identifier id ) -{ - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - MALI_DEBUG_ASSERT_POINTER(pmm); - - MALIPMM_DEBUG_PRINT( ("PMM: subsystem loaded, policy initializing\n") ); - -#if PMM_OS_TEST - power_test_start(); -#endif - - /* Initialize the profile now the system has loaded - so that cores are - * not turned off during start up - */ - return pmm_policy_init( pmm ); -} - -void malipmm_force_powerup( void ) -{ - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_PMM_LOCK(pmm); - pmm->status = MALI_PMM_STATUS_OFF; - MALI_PMM_UNLOCK(pmm); - - /* flush PMM workqueue */ - _mali_osk_flush_workqueue( pmm->irq ); - - if (pmm->cores_powered == 0) - { - malipmm_powerup(pmm->cores_registered); - } -} - -void malipmm_kernel_subsystem_terminate( mali_kernel_subsystem_identifier id ) -{ - /* Check this is the right system */ - MALI_DEBUG_ASSERT( id == mali_subsystem_pmm_id ); - MALI_DEBUG_ASSERT_POINTER(pmm_state); - - if( pmm_state ) - { -#if PMM_OS_TEST - power_test_end(); -#endif - /* Get the lock so we can shutdown */ - MALI_PMM_LOCK(pmm_state); -#if MALI_STATE_TRACKING - pmm_state->mali_pmm_lock_acquired = 1; -#endif /* MALI_STATE_TRACKING */ - pmm_state->status = MALI_PMM_STATUS_OFF; -#if MALI_STATE_TRACKING - pmm_state->mali_pmm_lock_acquired = 0; -#endif /* MALI_STATE_TRACKING */ - MALI_PMM_UNLOCK(pmm_state); - _mali_osk_pmm_ospmm_cleanup(); - pmm_policy_term(pmm_state); - _mali_osk_irq_term( pmm_state->irq ); - _mali_osk_notification_queue_term( pmm_state->queue ); - _mali_osk_notification_queue_term( pmm_state->iqueue ); - if (pmm_state->cores_registered) malipmm_powerdown(pmm_state->cores_registered,MALI_POWER_MODE_LIGHT_SLEEP); -#if USING_MALI_PMU - if( pmm_state->pmu_initialized ) - { - _mali_osk_resource_type_t t = PMU; - mali_pmm_pmu_deinit(&t); - } -#endif /* USING_MALI_PMU */ - - _mali_osk_atomic_term( &(pmm_state->messages_queued) ); - MALI_PMM_LOCK_TERM(pmm_state); - _mali_osk_free(pmm_state); - pmm_state = NULL; - } - - MALIPMM_DEBUG_PRINT( ("PMM: subsystem terminated\n") ); -} - -_mali_osk_errcode_t malipmm_powerup( u32 cores ) -{ - _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - - /* If all the cores are powered down, power up the MALI */ - if (pmm->cores_powered == 0) { - mali_platform_power_mode_change(MALI_POWER_MODE_ON); -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON - /* Initiate the power up */ - if (_mali_osk_pmm_dev_activate() < 0) { - MALI_PRINT(("PMM: Try again PD_G3D enable\n")); - if (mali_pd_enable() < 0) { - MALI_PRINT(("PMM: Mali PMM device activate failed\n")); - err = _MALI_OSK_ERR_FAULT; - return err; - } - } -#endif - } - -#if USING_MALI_PMU - err = mali_pmm_pmu_powerup( cores ); -#endif - -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON - mali_platform_powerup(cores); -#endif - - return err; -} - -_mali_osk_errcode_t malipmm_powerdown( u32 cores, mali_power_mode power_mode ) -{ - _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON - mali_platform_powerdown(cores); -#endif - -#if USING_MALI_PMU - err = mali_pmm_pmu_powerdown( cores ); -#endif - - /* If all cores are powered down, power off the MALI */ - if (pmm->cores_powered == 0) - { -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON - /* Initiate the power down */ - _mali_osk_pmm_dev_idle(); -#endif - mali_platform_power_mode_change(power_mode); - } - return err; -} - -_mali_osk_errcode_t malipmm_core_register( mali_pmm_core_id core ) -{ - _mali_osk_errcode_t err; - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - - if( pmm == NULL ) - { - /* PMM state has not been created, this is because the PMU resource has not been - * created yet. - * This probably means that the PMU resource has not been specfied as the first - * resource in the config file - */ - MALI_PRINT_ERROR( ("PMM: Cannot register core %s because the PMU resource has not been\n initialized. Please make sure the PMU resource is the first resource in the\n resource configuration.\n", - pmm_trace_get_core_name(core)) ); - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - MALI_PMM_LOCK(pmm); - -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 1; -#endif /* MALI_STATE_TRACKING */ - - - /* Check if the core is registered more than once in PMM */ - MALI_DEBUG_ASSERT( (pmm->cores_registered & core) == 0 ); - - MALIPMM_DEBUG_PRINT( ("PMM: core registered: (0x%x) %s\n", core, pmm_trace_get_core_name(core)) ); - -#if !MALI_PMM_NO_PMU - /* Make sure the core is powered up */ - err = malipmm_powerup( core ); -#else - err = _MALI_OSK_ERR_OK; -#endif - if( _MALI_OSK_ERR_OK == err ) - { -#if MALI_PMM_TRACE - mali_pmm_core_mask old_power = pmm->cores_powered; -#endif - /* Assume a registered core is now powered up and idle */ - pmm->cores_registered |= core; - pmm->cores_idle |= core; - pmm->cores_powered |= core; - pmm_update_system_state( pmm ); - -#if MALI_PMM_TRACE - _mali_pmm_trace_hardware_change( old_power, pmm->cores_powered ); -#endif - } - else - { - MALI_PRINT_ERROR( ("PMM: Error(%d) powering up registered core: (0x%x) %s\n", - err, core, pmm_trace_get_core_name(core)) ); - } - -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 0; -#endif /* MALI_STATE_TRACKING */ - - MALI_PMM_UNLOCK(pmm); - - return err; -} - -void malipmm_core_unregister( mali_pmm_core_id core ) -{ - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - MALI_DEBUG_ASSERT_POINTER(pmm); - - MALI_PMM_LOCK(pmm); -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 1; -#endif /* MALI_STATE_TRACKING */ - - - /* Check if the core is registered in PMM */ - MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, core ); - - MALIPMM_DEBUG_PRINT( ("PMM: core unregistered: (0x%x) %s\n", core, pmm_trace_get_core_name(core)) ); - - { -#if MALI_PMM_TRACE - mali_pmm_core_mask old_power = pmm->cores_powered; -#endif - - /* Remove the core from the system */ - pmm->cores_idle &= (~core); - pmm->cores_powered &= (~core); - pmm->cores_pend_down &= (~core); - pmm->cores_pend_up &= (~core); - pmm->cores_ack_down &= (~core); - pmm->cores_ack_up &= (~core); - - pmm_update_system_state( pmm ); - -#if MALI_PMM_TRACE - _mali_pmm_trace_hardware_change( old_power, pmm->cores_powered ); -#endif - } - -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 0; -#endif /* MALI_STATE_TRACKING */ - - MALI_PMM_UNLOCK(pmm); -} -void malipmm_core_power_down_okay( mali_pmm_core_id core ) -{ - _mali_uk_pmm_message_s event = { - NULL, - MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK, - 0 }; - - event.data = core; - - _mali_ukk_pmm_event_message( &event ); -} - -void malipmm_set_policy_check() -{ - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - MALI_DEBUG_ASSERT_POINTER(pmm); - pmm->check_policy = MALI_TRUE; - - /* To check the policy we need to schedule some work */ - _mali_osk_irq_schedulework( pmm->irq ); -} - -_mali_osk_errcode_t malipmm_irq_uhandler(void *data) -{ - MALIPMM_DEBUG_PRINT( ("PMM: uhandler - not expected to be used\n") ); - - MALI_SUCCESS; -} - -void malipmm_irq_bhandler(void *data) -{ - _mali_pmm_internal_state_t *pmm; - pmm = (_mali_pmm_internal_state_t *)data; - MALI_DEBUG_ASSERT_POINTER(pmm); - -#if PMM_OS_TEST - if( power_test_check() ) return; -#endif - - MALI_PMM_LOCK(pmm); -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 1; -#endif /* MALI_STATE_TRACKING */ - - /* Quick out when we are shutting down */ - if( pmm->status == MALI_PMM_STATUS_OFF ) - { - - #if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 0; - #endif /* MALI_STATE_TRACKING */ - - MALI_PMM_UNLOCK(pmm); - return; - } - - MALIPMM_DEBUG_PRINT( ("PMM: bhandler - Processing event\n") ); - - if( pmm->missed > 0 ) - { - MALI_PRINT_ERROR( ("PMM: Failed to send %d events", pmm->missed) ); - pmm_fatal_reset( pmm ); - } - - if( pmm->check_policy ) - { - pmm->check_policy = MALI_FALSE; - pmm_policy_check_policy(pmm); - } - else - { - /* Perform event processing */ - pmm_event_process(); - if( pmm->fatal_power_err ) - { - /* Try a reset */ - pmm_fatal_reset( pmm ); - } - } - -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 0; -#endif /* MALI_STATE_TRACKING */ - - MALI_PMM_UNLOCK(pmm); -} - -static void pmm_event_process( void ) -{ - _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; - _mali_osk_notification_t *msg = NULL; - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - mali_pmm_message_t *event; - u32 process_messages; - - MALI_DEBUG_ASSERT_POINTER(pmm); - - - /* Max number of messages to process before exiting - as we shouldn't stay - * processing the messages for a long time - */ - process_messages = _mali_osk_atomic_read( &(pmm->messages_queued) ); - - while( process_messages > 0 ) - { - /* Check internal message queue first */ - err = _mali_osk_notification_queue_dequeue( pmm->iqueue, &msg ); - - if( err != _MALI_OSK_ERR_OK ) - { - if( pmm->status == MALI_PMM_STATUS_IDLE || pmm->status == MALI_PMM_STATUS_OS_WAITING || pmm->status == MALI_PMM_STATUS_DVFS_PAUSE) - { - if( pmm->waiting > 0 ) pmm->waiting--; - - /* We aren't busy changing state, so look at real events */ - err = _mali_osk_notification_queue_dequeue( pmm->queue, &msg ); - - if( err != _MALI_OSK_ERR_OK ) - { - pmm->no_events++; - MALIPMM_DEBUG_PRINT( ("PMM: event_process - No message to process\n") ); - /* Nothing to do - so return */ - return; - } - else - { - #if (MALI_PMM_TRACE || MALI_STATE_TRACKING) - pmm->messages_received++; - #endif - } - } - else - { - /* Waiting for an internal message */ - pmm->waiting++; - MALIPMM_DEBUG_PRINT( ("PMM: event_process - Waiting for internal message, messages queued=%d\n", pmm->waiting) ); - return; - } - } - else - { - #if (MALI_PMM_TRACE || MALI_STATE_TRACKING) - pmm->imessages_received++; - #endif - } - - MALI_DEBUG_ASSERT_POINTER( msg ); - /* Check the message type matches */ - MALI_DEBUG_ASSERT( msg->notification_type == MALI_PMM_NOTIFICATION_TYPE ); - - event = msg->result_buffer; - - _mali_osk_atomic_dec( &(pmm->messages_queued) ); - process_messages--; - - #if MALI_PMM_TRACE - /* Trace before we process the event in case we have an error */ - _mali_pmm_trace_event_message( event, MALI_TRUE ); - #endif - err = pmm_policy_process( pmm, event ); - - - if( err != _MALI_OSK_ERR_OK ) - { - MALI_PRINT_ERROR( ("PMM: Error(%d) in policy %d when processing event message with id: %d", - err, pmm->policy, event->id) ); - } - - /* Delete notification */ - _mali_osk_notification_delete ( msg ); - - if( pmm->fatal_power_err ) - { - /* Nothing good has happened - exit */ - return; - } - - - #if MALI_PMM_TRACE - MALI_PRINT( ("PMM Trace: Event processed, msgs (sent/read) = %d/%d, int msgs (sent/read) = %d/%d, no events = %d, waiting = %d\n", - pmm->messages_sent, pmm->messages_received, pmm->imessages_sent, pmm->imessages_received, pmm->no_events, pmm->waiting) ); - #endif - } - - if( pmm->status == MALI_PMM_STATUS_IDLE && pmm->waiting > 0 ) - { - /* For events we ignored whilst we were busy, add a new - * scheduled time to look at them */ - _mali_osk_irq_schedulework( pmm->irq ); - } -} - -#if MALI_STATE_TRACKING -u32 malipmm_subsystem_dump_state(char *buf, u32 size) -{ - int len = 0; - _mali_pmm_internal_state_t *pmm = GET_PMM_STATE_PTR; - - if( !pmm ) - { - len += _mali_osk_snprintf(buf + len, size + len, "PMM: Null state\n"); - } - else - { - len += _mali_osk_snprintf(buf+len, size+len, "Locks:\n PMM lock acquired: %s\n", - pmm->mali_pmm_lock_acquired ? "true" : "false"); - len += _mali_osk_snprintf(buf+len, size+len, - "PMM state:\n Previous status: %s\n Status: %s\n Current event: %s\n Policy: %s\n Check policy: %s\n State: %s\n", - pmm_trace_status[pmm->mali_last_pmm_status], pmm_trace_status[pmm->status], - pmm_trace_events[pmm->mali_new_event_status], pmm_trace_policy[pmm->policy], - pmm->check_policy ? "true" : "false", pmm_trace_state[pmm->state]); - len += _mali_osk_snprintf(buf+len, size+len, - "PMM cores:\n Cores registered: %d\n Cores powered: %d\n Cores idle: %d\n" - " Cores pending down: %d\n Cores pending up: %d\n Cores ack down: %d\n Cores ack up: %d\n", - pmm->cores_registered, pmm->cores_powered, pmm->cores_idle, pmm->cores_pend_down, - pmm->cores_pend_up, pmm->cores_ack_down, pmm->cores_ack_up); - len += _mali_osk_snprintf(buf+len, size+len, "PMM misc:\n PMU init: %s\n Messages queued: %d\n" - " Waiting: %d\n No events: %d\n Missed events: %d\n Fatal power error: %s\n", - pmm->pmu_initialized ? "true" : "false", _mali_osk_atomic_read(&(pmm->messages_queued)), - pmm->waiting, pmm->no_events, pmm->missed, pmm->fatal_power_err ? "true" : "false"); - } - return len; -} -#endif /* MALI_STATE_TRACKING */ - -#endif /* USING_MALI_PMM */ diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm.h b/drivers/media/video/samsung/mali/common/pmm/mali_pmm.h deleted file mode 100644 index 5170650..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm.h +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** - * @file mali_pmm.h - * Defines the power management module for the kernel device driver - */ - -#ifndef __MALI_PMM_H__ -#define __MALI_PMM_H__ - -/* For mali_pmm_message_data and MALI_PMM_EVENT_UK_* defines */ -#include "mali_uk_types.h" -#include "mali_platform.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** - * @defgroup pmmapi Power Management Module APIs - * - * @{ - */ - -/** OS event tester */ -#define PMM_OS_TEST 0 - -/** @brief Compile option to turn on/off tracing */ -#define MALI_PMM_TRACE 0 -#define MALI_PMM_TRACE_SENT_EVENTS 0 - -/** @brief Compile option to switch between always on or job control PMM policy */ -#define MALI_PMM_ALWAYS_ON 0 - -/** @brief Overrides hardware PMU and uses software simulation instead - * @note This even stops intialization of PMU and cores being powered on at start up - */ -#define MALI_PMM_NO_PMU 0 - -/** @brief PMM debug print to control debug message level */ -#define MALIPMM_DEBUG_PRINT(args) \ - MALI_DEBUG_PRINT(3, args) - - -/** @brief power management event message identifiers. - */ -/* These must match up with the pmm_trace_events & pmm_trace_events_internal - * arrays - */ -typedef enum mali_pmm_event_id -{ - MALI_PMM_EVENT_OS_POWER_UP = 0, /**< OS power up event */ - MALI_PMM_EVENT_OS_POWER_DOWN = 1, /**< OS power down event */ - MALI_PMM_EVENT_JOB_SCHEDULED = 2, /**< Job scheduled to run event */ - MALI_PMM_EVENT_JOB_QUEUED = 3, /**< Job queued (but not run) event */ - MALI_PMM_EVENT_JOB_FINISHED = 4, /**< Job finished event */ - MALI_PMM_EVENT_TIMEOUT = 5, /**< Time out timer has expired */ - MALI_PMM_EVENT_DVFS_PAUSE = 6, /**< Mali device pause event */ - MALI_PMM_EVENT_DVFS_RESUME = 7, /**< Mali device resume event */ - - MALI_PMM_EVENT_UKS = 200, /**< Events from the user-side start here */ - MALI_PMM_EVENT_UK_EXAMPLE = _MALI_PMM_EVENT_UK_EXAMPLE, - - MALI_PMM_EVENT_INTERNALS = 1000, - MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK = 1001, /**< Internal power up acknowledgement */ - MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK = 1002, /**< Internal power down acknowledgment */ -} mali_pmm_event_id; - - -/** @brief Use this when the power up/down callbacks do not need any OS data. */ -#define MALI_PMM_NO_OS_DATA 1 - - -/* @brief Geometry and pixel processor identifiers for the PMM - * - * @note these match the ARM Mali 400 PMU hardware definitions, apart from the "SYSTEM" - */ -typedef enum mali_pmm_core_id_tag -{ - MALI_PMM_CORE_SYSTEM = 0x00000000, /**< All of the Mali hardware */ - MALI_PMM_CORE_GP = 0x00000001, /**< Mali GP2 */ - MALI_PMM_CORE_L2 = 0x00000002, /**< Level 2 cache */ - MALI_PMM_CORE_PP0 = 0x00000004, /**< Mali 200 pixel processor 0 */ - MALI_PMM_CORE_PP1 = 0x00000008, /**< Mali 200 pixel processor 1 */ - MALI_PMM_CORE_PP2 = 0x00000010, /**< Mali 200 pixel processor 2 */ - MALI_PMM_CORE_PP3 = 0x00000020, /**< Mali 200 pixel processor 3 */ - MALI_PMM_CORE_PP_ALL = 0x0000003C /**< Mali 200 pixel processors 0-3 */ -} mali_pmm_core_id; - - -/* @brief PMM bitmask of mali_pmm_core_ids - */ -typedef u32 mali_pmm_core_mask; - -/* @brief PMM event timestamp type - */ -typedef u32 mali_pmm_timestamp; - -/** @brief power management event message struct - */ -typedef struct _mali_pmm_message -{ - mali_pmm_event_id id; /**< event id */ - mali_pmm_message_data data; /**< specific data associated with the event */ - mali_pmm_timestamp ts; /**< timestamp the event was placed in the event queue */ -} mali_pmm_message_t; - - - -/** @brief the state of the power management module. - */ -/* These must match up with the pmm_trace_state array */ -typedef enum mali_pmm_state_tag -{ - MALI_PMM_STATE_UNAVAILABLE = 0, /**< PMM is not available */ - MALI_PMM_STATE_SYSTEM_ON = 1, /**< All of the Mali hardware is on */ - MALI_PMM_STATE_SYSTEM_OFF = 2, /**< All of the Mali hardware is off */ - MALI_PMM_STATE_SYSTEM_TRANSITION = 3 /**< System is changing state */ -} mali_pmm_state; - - -/** @brief a power management policy. - */ -/* These must match up with the pmm_trace_policy array */ -typedef enum mali_pmm_policy_tag -{ - MALI_PMM_POLICY_NONE = 0, /**< No policy */ - MALI_PMM_POLICY_ALWAYS_ON = 1, /**< Always on policy */ - MALI_PMM_POLICY_JOB_CONTROL = 2, /**< Job control policy */ - MALI_PMM_POLICY_RUNTIME_JOB_CONTROL = 3 /**< Run time power management control policy */ -} mali_pmm_policy; - -/** @brief Function to power up MALI - * - * @param cores core mask to power up the cores - * - * @return error code if MALI fails to power up - */ -_mali_osk_errcode_t malipmm_powerup( u32 cores ); - -/** @brief Function to power down MALI - * - * @param cores core mask to power down the cores - * @param The power mode to which MALI transitions - * - * @return error code if MALI fails to power down - */ -_mali_osk_errcode_t malipmm_powerdown( u32 cores, mali_power_mode power_mode ); - -/** @brief Function to report to the OS when the power down has finished - * - * @param data The event message data that initiated the power down - */ -void _mali_osk_pmm_power_down_done(mali_pmm_message_data data); - -/** @brief Function to report to the OS when the power up has finished - * - * @param data The event message data that initiated the power up - */ -void _mali_osk_pmm_power_up_done(mali_pmm_message_data data); - -/** @brief Function to report that DVFS operation done - * - * @param data The event message data - */ -void _mali_osk_pmm_dvfs_operation_done(mali_pmm_message_data data); - -#if MALI_POWER_MGMT_TEST_SUITE -/** @brief Function to notify power management events - * - * @param data The event message data - */ -void _mali_osk_pmm_policy_events_notifications(mali_pmm_event_id event_id); - -#endif - -/** @brief Function to power up MALI - * - * @note powers up the MALI during MALI device driver is unloaded - */ -void malipmm_force_powerup( void ); - -/** @brief Function to report the OS that device is idle - * - * @note inform the OS that device is idle - */ -_mali_osk_errcode_t _mali_osk_pmm_dev_idle( void ); - -/** @brief Function to report the OS to activate device - * - * @note inform the os that device needs to be activated - */ -int _mali_osk_pmm_dev_activate( void ); - -/** @brief Function to report OS PMM for cleanup - * - * @note Function to report OS PMM for cleanup - */ -void _mali_osk_pmm_ospmm_cleanup( void ); - -/** @brief Queries the current state of the PMM software - * - * @note the state of the PMM can change after this call has returned - * - * @return the current PMM state value - */ -mali_pmm_state _mali_pmm_state( void ); - -/** @brief List of cores that are registered with the PMM - * - * This will return the cores that have been currently registered with the PMM, - * which is a bitwise OR of the mali_pmm_core_id_tags. A value of 0x0 means that - * there are no cores registered. - * - * @note the list of cores can change after this call has returned - * - * @return a bit mask representing all the cores that have been registered with the PMM - */ -mali_pmm_core_mask _mali_pmm_cores_list( void ); - -/** @brief List of cores that are powered up in the PMM - * - * This will return the subset of the cores that can be listed using mali_pmm_cores_ - * list, that have power. It is a bitwise OR of the mali_pmm_core_id_tags. A value of - * 0x0 means that none of the cores registered are powered. - * - * @note the list of cores can change after this call has returned - * - * @return a bit mask representing all the cores that are powered up - */ -mali_pmm_core_mask _mali_pmm_cores_powered( void ); - - -/** @brief List of power management policies that are supported by the PMM - * - * Given an empty array of policies - policy_list - which contains the number - * of entries as specified by - policy_list_size, this function will populate - * the list with the available policies. If the policy_list is too small for - * all the policies then only policy_list_size entries will be returned. If the - * policy_list is bigger than the number of available policies then, the extra - * entries will be set to MALI_PMM_POLICY_NONE. - * The function will also update available_policies with the number of policies - * that are available, even if it exceeds the policy_list_size. - * The function will succeed if all policies could be returned, else it will - * fail if none or only a subset of policies could be returned. - * The function will also fail if no policy_list is supplied, though - * available_policies is optional. - * - * @note this is a STUB function and is not yet implemented - * - * @param policy_list_size is the number of policies that can be returned in - * the policy_list argument - * @param policy_list is an array of policies that should be populated with - * the list of policies that are supported by the PMM - * @param policies_available optional argument, if non-NULL will be set to the - * number of policies available - * @return _MALI_OSK_ERR_OK if the policies could be listed, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t _mali_pmm_list_policies( - u32 policy_list_size, - mali_pmm_policy *policy_list, - u32 *policies_available ); - -/** @brief Set the power management policy in the PMM - * - * Given a valid supported policy, this function will change the PMM to use - * this new policy - * The function will fail if the policy given is invalid or unsupported. - * - * @note this is a STUB function and is not yet implemented - * - * @param policy the new policy to be set - * @return _MALI_OSK_ERR_OK if the policy could be set, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t _mali_pmm_set_policy( mali_pmm_policy policy ); - -/** @brief Get the current power management policy in the PMM - * - * Given a pointer to a policy data type, this function will return the current - * policy that is in effect for the PMM. This maybe out of date if there is a - * pending set policy call that has not been serviced. - * The function will fail if the policy given is NULL. - * - * @note the policy of the PMM can change after this call has returned - * - * @param policy a pointer to a policy that can be updated to the current - * policy - * @return _MALI_OSK_ERR_OK if the policy could be returned, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t _mali_pmm_get_policy( mali_pmm_policy *policy ); - -#if MALI_PMM_TRACE - -/** @brief Indicates when a hardware state change occurs in the PMM - * - * @param old a mask of the cores indicating the previous state of the cores - * @param newstate a mask of the cores indicating the new current state of the cores - */ -void _mali_pmm_trace_hardware_change( mali_pmm_core_mask old, mali_pmm_core_mask newstate ); - -/** @brief Indicates when a state change occurs in the PMM - * - * @param old the previous state for the PMM - * @param newstate the new current state of the PMM - */ -void _mali_pmm_trace_state_change( mali_pmm_state old, mali_pmm_state newstate ); - -/** @brief Indicates when a policy change occurs in the PMM - * - * @param old the previous policy for the PMM - * @param newpolicy the new current policy of the PMM - */ -void _mali_pmm_trace_policy_change( mali_pmm_policy old, mali_pmm_policy newpolicy ); - -/** @brief Records when an event message is read by the event system - * - * @param event the message details - * @param received MALI_TRUE when the message is received by the PMM, else it is being sent - */ -void _mali_pmm_trace_event_message( mali_pmm_message_t *event, mali_bool received ); - -#endif /* MALI_PMM_TRACE */ - -/** @brief Dumps the current state of OS PMM thread - */ -#if MALI_STATE_TRACKING -u32 mali_pmm_dump_os_thread_state( char *buf, u32 size ); -#endif /* MALI_STATE_TRACKING */ - -/** @} */ /* end group pmmapi */ - -#ifdef __cplusplus -} -#endif - -#endif /* __MALI_PMM_H__ */ diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_pmu.c b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_pmu.c deleted file mode 100644 index a8160ac..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_pmu.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** - * @file mali_pmm_pmu.c - * Mali driver functions for Mali 400 PMU hardware - */ -#include "mali_kernel_common.h" -#include "mali_osk.h" -#include "mali_platform.h" - -#if USING_MALI_PMU -#if USING_MALI_PMM - -#include "mali_pmm.h" - -/* Internal test on/off */ -#define PMU_TEST 0 - -#if MALI_POWER_MGMT_TEST_SUITE -#include "mali_platform_pmu_internal_testing.h" -#endif /* MALI_POWER_MGMT_TEST_SUITE */ - -/** @brief PMU hardware info - */ -typedef struct platform_pmu -{ - u32 reg_base_addr; /**< PMU registers base address */ - u32 reg_size; /**< PMU registers size */ - const char *name; /**< PMU name */ - u32 irq_num; /**< PMU irq number */ - - mali_io_address reg_mapped; /**< IO-mapped pointer to registers */ -} platform_pmu_t; - -static platform_pmu_t *pmu_info = NULL; - -/** @brief Register layout for hardware PMU - */ -typedef enum { - PMU_REG_ADDR_MGMT_POWER_UP = 0x00, /*< Power up register */ - PMU_REG_ADDR_MGMT_POWER_DOWN = 0x04, /*< Power down register */ - PMU_REG_ADDR_MGMT_STATUS = 0x08, /*< Core sleep status register */ - PMU_REG_ADDR_MGMT_INT_MASK = 0x0C, /*< Interrupt mask register */ - PMU_REG_ADDR_MGMT_INT_RAWSTAT = 0x10, /*< Interrupt raw status register */ - PMU_REG_ADDR_MGMT_INT_STAT = 0x14, /*< Interrupt status register */ - PMU_REG_ADDR_MGMT_INT_CLEAR = 0x18, /*< Interrupt clear register */ - PMU_REG_ADDR_MGMT_SW_DELAY = 0x1C, /*< Software delay register */ - PMU_REG_ADDR_MGMT_MASTER_PWR_UP = 0x24, /*< Master power up register */ - PMU_REGISTER_ADDRESS_SPACE_SIZE = 0x28, /*< Size of register space */ -} pmu_reg_addr_mgmt_addr; - -/* Internal functions */ -static u32 pmu_reg_read(platform_pmu_t *pmu, u32 relative_address); -static void pmu_reg_write(platform_pmu_t *pmu, u32 relative_address, u32 new_val); -static mali_pmm_core_mask pmu_translate_cores_to_pmu(mali_pmm_core_mask cores); -#if PMU_TEST -static void pmm_pmu_dump_regs( platform_pmu_t *pmu ); -static pmm_pmu_test( platform_pmu_t *pmu, u32 cores ); -#endif - -_mali_osk_errcode_t mali_pmm_pmu_init(_mali_osk_resource_t *resource) -{ - - if( resource->type == PMU ) - { - if( (resource->base == 0) || - (resource->description == NULL) ) - { - /* NOTE: We currently don't care about any other resource settings */ - MALI_PRINT_ERROR(("PLATFORM mali400-pmu: Missing PMU set up information\n")); - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - pmu_info = (platform_pmu_t *)_mali_osk_malloc(sizeof(*pmu_info)); - MALI_CHECK_NON_NULL( pmu_info, _MALI_OSK_ERR_NOMEM ); - - /* All values get 0 as default */ - _mali_osk_memset(pmu_info, 0, sizeof(*pmu_info)); - - pmu_info->reg_base_addr = resource->base; - pmu_info->reg_size = (u32)PMU_REGISTER_ADDRESS_SPACE_SIZE; - pmu_info->name = resource->description; - pmu_info->irq_num = resource->irq; - - if( _MALI_OSK_ERR_OK != _mali_osk_mem_reqregion(pmu_info->reg_base_addr, pmu_info->reg_size, pmu_info->name) ) - { - MALI_PRINT_ERROR(("PLATFORM mali400-pmu: Could not request register region (0x%08X - 0x%08X) for %s\n", - pmu_info->reg_base_addr, pmu_info->reg_base_addr + pmu_info->reg_size - 1, pmu_info->name)); - goto cleanup; - } - else - { - MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Success: request_mem_region: (0x%08X - 0x%08X) for %s\n", - pmu_info->reg_base_addr, pmu_info->reg_base_addr + pmu_info->reg_size - 1, pmu_info->name)); - } - - pmu_info->reg_mapped = _mali_osk_mem_mapioregion( pmu_info->reg_base_addr, pmu_info->reg_size, pmu_info->name ); - - if( 0 == pmu_info->reg_mapped ) - { - MALI_PRINT_ERROR(("PLATFORM mali400-pmu: Could not ioremap registers for %s .\n", pmu_info->name)); - _mali_osk_mem_unreqregion( pmu_info->reg_base_addr, pmu_info->reg_size ); - goto cleanup; - } - else - { - MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Success: ioremap_nocache: Internal ptr: (0x%08X - 0x%08X) for %s\n", - (u32) pmu_info->reg_mapped, - ((u32)pmu_info->reg_mapped)+ pmu_info->reg_size - 1, - pmu_info->name)); - } - - MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Success: Mapping registers to %s\n", pmu_info->name)); - -#if PMU_TEST - pmu_test(pmu_info, (MALI_PMM_CORE_GP)); - pmu_test(pmu_info, (MALI_PMM_CORE_GP|MALI_PMM_CORE_L2|MALI_PMM_CORE_PP0)); -#endif - - MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Initialized - %s\n", pmu_info->name) ); - } - else - { - /* Didn't expect a different resource */ - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - - MALI_SUCCESS; - -cleanup: - _mali_osk_free(pmu_info); - pmu_info = NULL; - MALI_ERROR(_MALI_OSK_ERR_NOMEM); -} - -_mali_osk_errcode_t mali_pmm_pmu_deinit(_mali_osk_resource_type_t *type) -{ - if (*type == PMU) - { - if( pmu_info ) - { - _mali_osk_mem_unmapioregion(pmu_info->reg_base_addr, pmu_info->reg_size, pmu_info->reg_mapped); - _mali_osk_mem_unreqregion(pmu_info->reg_base_addr, pmu_info->reg_size); - _mali_osk_free(pmu_info); - pmu_info = NULL; - MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: Terminated PMU\n") ); - } - } - else - { - /* Didn't expect a different resource */ - MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); - } - - MALI_SUCCESS; - -} - -_mali_osk_errcode_t mali_pmm_pmu_powerdown(u32 cores) -{ - u32 stat; - u32 timeout; - u32 cores_pmu; - - MALI_DEBUG_ASSERT_POINTER(pmu_info); - MALI_DEBUG_ASSERT( cores != 0 ); /* Shouldn't receive zero from PMM */ - MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: power down (0x%x)\n", cores) ); - - cores_pmu = pmu_translate_cores_to_pmu(cores); - pmu_reg_write( pmu_info, (u32)PMU_REG_ADDR_MGMT_POWER_DOWN, cores_pmu ); - - /* Wait for cores to be powered down */ - timeout = 10; /* 10ms */ - do - { - /* Get status of sleeping cores */ - stat = pmu_reg_read( pmu_info, (u32)PMU_REG_ADDR_MGMT_STATUS ); - stat &= cores_pmu; - if( stat == cores_pmu ) break; /* All cores we wanted are now asleep */ - _mali_osk_time_ubusydelay(1000); /* 1ms */ - timeout--; - } while( timeout > 0 ); - - if( timeout == 0 ) MALI_ERROR(_MALI_OSK_ERR_TIMEOUT); - - MALI_SUCCESS; -} - -_mali_osk_errcode_t mali_pmm_pmu_powerup(u32 cores) -{ - u32 cores_pmu; - u32 stat; - u32 timeout; - - MALI_DEBUG_ASSERT_POINTER(pmu_info); - MALI_DEBUG_ASSERT( cores != 0 ); /* Shouldn't receive zero from PMM */ - MALI_DEBUG_PRINT( 4, ("PLATFORM mali400-pmu: power up (0x%x)\n", cores) ); - - /* Don't use interrupts - just poll status */ - pmu_reg_write( pmu_info, (u32)PMU_REG_ADDR_MGMT_INT_MASK, 0 ); - cores_pmu = pmu_translate_cores_to_pmu(cores); - pmu_reg_write( pmu_info, (u32)PMU_REG_ADDR_MGMT_POWER_UP, cores_pmu ); - - timeout = 10; /* 10ms */ - do - { - /* Get status of sleeping cores */ - stat = pmu_reg_read( pmu_info, (u32)PMU_REG_ADDR_MGMT_STATUS ); - stat &= cores_pmu; - if( stat == 0 ) break; /* All cores we wanted are now awake */ - _mali_osk_time_ubusydelay(1000); /* 1ms */ - timeout--; - } while( timeout > 0 ); - - if( timeout == 0 ) MALI_ERROR(_MALI_OSK_ERR_TIMEOUT); - - MALI_SUCCESS; -} - - -/***** INTERNAL *****/ - -/** @brief Internal PMU function to translate the cores bit mask - * into something the hardware PMU understands - * - * @param cores PMM cores bitmask - * @return PMU hardware cores bitmask - */ -static u32 pmu_translate_cores_to_pmu(mali_pmm_core_mask cores) -{ - /* For Mali 400 PMU the cores mask is already the same as what - * the hardware PMU expects. - * For other hardware, some translation can be done here, by - * translating the MALI_PMM_CORE_* bits into specific hardware - * bits - */ - return cores; -} - -/** @brief Internal PMU function to read a PMU register - * - * @param pmu handle that identifies the PMU hardware - * @param relative_address relative PMU hardware address to read from - * @return 32-bit value that was read from the address - */ -static u32 pmu_reg_read(platform_pmu_t *pmu, u32 relative_address) -{ - u32 read_val; - - MALI_DEBUG_ASSERT_POINTER(pmu); - MALI_DEBUG_ASSERT((relative_address & 0x03) == 0); - MALI_DEBUG_ASSERT(relative_address < pmu->reg_size); - - read_val = _mali_osk_mem_ioread32(pmu->reg_mapped, relative_address); - - MALI_DEBUG_PRINT( 5, ("PMU: reg_read: %s Addr:0x%04X Val:0x%08x\n", - pmu->name, relative_address, read_val)); - - return read_val; -} - -/** @brief Internal PMU function to write to a PMU register - * - * @param pmu handle that identifies the PMU hardware - * @param relative_address relative PMU hardware address to write to - * @param new_val new 32-bit value to write into the address - */ -static void pmu_reg_write(platform_pmu_t *pmu, u32 relative_address, u32 new_val) -{ - MALI_DEBUG_ASSERT_POINTER(pmu); - MALI_DEBUG_ASSERT((relative_address & 0x03) == 0); - MALI_DEBUG_ASSERT(relative_address < pmu->reg_size); - - MALI_DEBUG_PRINT( 5, ("PMU: reg_write: %s Addr:0x%04X Val:0x%08x\n", - pmu->name, relative_address, new_val)); - - _mali_osk_mem_iowrite32(pmu->reg_mapped, relative_address, new_val); -} - -#if PMU_TEST - -/***** TEST *****/ - -static void pmu_dump_regs( platform_pmu_t *pmu ) -{ - u32 addr; - for( addr = 0x0; addr < PMU_REGISTER_ADDRESS_SPACE_SIZE; addr += 0x4 ) - { - MALI_PRINT( ("PMU_REG: 0x%08x: 0x%04x\n", (addr + pmu->reg_base_addr), pmu_reg_read( pmu, addr ) ) ); - } -} - -/* This function is an internal test for the PMU without any Mali h/w interaction */ -static void pmu_test( platform_pmu_t *pmu, u32 cores ) -{ - u32 stat; - u32 timeout; - - MALI_PRINT( ("PMU_TEST: Start\n") ); - - pmu_dump_regs( pmu ); - - MALI_PRINT( ("PMU_TEST: Power down cores: 0x%x\n", cores) ); - _mali_pmm_pmu_power_down( pmu, cores, MALI_TRUE ); - - stat = pmu_reg_read( pmu, (u32)PMU_REG_ADDR_MGMT_STATUS ); - MALI_PRINT( ("PMU_TEST: %s\n", (stat & cores) == cores ? "SUCCESS" : "FAIL" ) ); - - pmu_dump_regs( pmu ); - - MALI_PRINT( ("PMU_TEST: Power up cores: 0x%x\n", cores) ); - _mali_pmm_pmu_power_up( pmu, cores, MALI_FALSE ); - - MALI_PRINT( ("PMU_TEST: Waiting for power up...\n") ); - timeout = 1000; /* 1 sec */ - while( !_mali_pmm_pmu_irq_power_up(pmu) && timeout > 0 ) - { - _mali_osk_time_ubusydelay(1000); /* 1ms */ - timeout--; - } - - MALI_PRINT( ("PMU_TEST: Waited %dms for interrupt\n", (1000-timeout)) ); - stat = pmu_reg_read( pmu, (u32)PMU_REG_ADDR_MGMT_STATUS ); - MALI_PRINT( ("PMU_TEST: %s\n", (stat & cores) == 0 ? "SUCCESS" : "FAIL" ) ); - - _mali_pmm_pmu_irq_power_up_clear(pmu); - - pmu_dump_regs( pmu ); - - MALI_PRINT( ("PMU_TEST: Finish\n") ); -} -#endif /* PMU_TEST */ - -#if MALI_POWER_MGMT_TEST_SUITE - -u32 pmu_get_power_up_down_info(void) -{ - return pmu_reg_read(pmu_info, (u32)PMU_REG_ADDR_MGMT_STATUS); -} - -#endif /* MALI_POWER_MGMT_TEST_SUITE */ -#endif /* USING_MALI_PMM */ -#endif /* USING_MALI_PMU */ diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_pmu.h b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_pmu.h deleted file mode 100644 index 7525cac..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_pmu.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -/** - * @file mali_platform.h - * Platform specific Mali driver functions - */ - -#include "mali_osk.h" - -#if !USING_MALI_PMM -/* @brief System power up/down cores that can be passed into mali_platform_powerdown/up() */ -#define MALI_PLATFORM_SYSTEM 0 -#endif - -#if USING_MALI_PMM -#if USING_MALI_PMU -#include "mali_pmm.h" - -/** @brief Platform specific setup and initialisation of MALI - * - * This is called from the entrypoint of the driver to initialize the platform - * When using PMM, it is also called from the PMM start up to initialise the - * system PMU - * - * @param resource This is NULL when called on first driver start up, else it will - * be a pointer to a PMU resource - * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. - */ -_mali_osk_errcode_t mali_pmm_pmu_init(_mali_osk_resource_t *resource); - -/** @brief Platform specific deinitialisation of MALI - * - * This is called on the exit of the driver to terminate the platform - * When using PMM, it is also called from the PMM termination code to clean up the - * system PMU - * - * @param type This is NULL when called on driver exit, else it will - * be a pointer to a PMU resource type (not the full resource) - * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. - */ -_mali_osk_errcode_t mali_pmm_pmu_deinit(_mali_osk_resource_type_t *type); - -/** @brief Platform specific powerdown sequence of MALI - * - * Called as part of platform init if there is no PMM support, else the - * PMM will call it. - * - * @param cores This is MALI_PLATFORM_SYSTEM when called without PMM, else it will - * be a mask of cores to power down based on the mali_pmm_core_id enum - * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. - */ -_mali_osk_errcode_t mali_pmm_pmu_powerdown(u32 cores); - -/** @brief Platform specific powerup sequence of MALI - * - * Called as part of platform deinit if there is no PMM support, else the - * PMM will call it. - * - * @param cores This is MALI_PLATFORM_SYSTEM when called without PMM, else it will - * be a mask of cores to power down based on the mali_pmm_core_id enum - * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. - */ -_mali_osk_errcode_t mali_pmm_pmu_powerup(u32 cores); - -#if MALI_POWER_MGMT_TEST_SUITE -#if USING_MALI_PMM -#if USING_MALI_PMU -/** @brief function to get status of individual cores - * - * This function is used by power management test suite to get the status of powered up/down the number - * of cores - * @param utilization The workload utilization of the Mali GPU. 0 = no utilization, 256 = full utilization. - */ -u32 pmu_get_power_up_down_info(void); -#endif -#endif -#endif -#endif -#endif diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy.c b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy.c deleted file mode 100644 index 87b6ec2..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** - * @file mali_pmm_policy.c - * Implementation of the common routines for power management module - * policies - */ - -#if USING_MALI_PMM - -#include "mali_ukk.h" -#include "mali_kernel_common.h" - -#include "mali_pmm.h" -#include "mali_pmm_system.h" -#include "mali_pmm_state.h" -#include "mali_pmm_policy.h" - -#include "mali_pmm_policy_alwayson.h" -#include "mali_pmm_policy_jobcontrol.h" - -/* Call back function for timer expiration */ -static void pmm_policy_timer_callback( void *arg ); - -_mali_osk_errcode_t pmm_policy_timer_init( _pmm_policy_timer_t *pptimer, u32 timeout, mali_pmm_event_id id ) -{ - MALI_DEBUG_ASSERT_POINTER(pptimer); - - /* All values get 0 as default */ - _mali_osk_memset(pptimer, 0, sizeof(*pptimer)); - - pptimer->timer = _mali_osk_timer_init(); - if( pptimer->timer ) - { - _mali_osk_timer_setcallback( pptimer->timer, pmm_policy_timer_callback, (void *)pptimer ); - pptimer->timeout = timeout; - pptimer->event_id = id; - MALI_SUCCESS; - } - - return _MALI_OSK_ERR_FAULT; -} - -static void pmm_policy_timer_callback( void *arg ) -{ - _pmm_policy_timer_t *pptimer = (_pmm_policy_timer_t *)arg; - - MALI_DEBUG_ASSERT_POINTER(pptimer); - MALI_DEBUG_ASSERT( pptimer->set ); - - /* Set timer expired and flag there is a policy to check */ - pptimer->expired = MALI_TRUE; - malipmm_set_policy_check(); -} - - -void pmm_policy_timer_term( _pmm_policy_timer_t *pptimer ) -{ - MALI_DEBUG_ASSERT_POINTER(pptimer); - - _mali_osk_timer_del( pptimer->timer ); - _mali_osk_timer_term( pptimer->timer ); - pptimer->timer = NULL; -} - -mali_bool pmm_policy_timer_start( _pmm_policy_timer_t *pptimer ) -{ - MALI_DEBUG_ASSERT_POINTER(pptimer); - MALI_DEBUG_ASSERT_POINTER(pptimer->timer); - - if( !(pptimer->set) ) - { - pptimer->set = MALI_TRUE; - pptimer->expired = MALI_FALSE; - pptimer->start = _mali_osk_time_tickcount(); - _mali_osk_timer_add( pptimer->timer, pptimer->timeout ); - return MALI_TRUE; - } - - return MALI_FALSE; -} - -mali_bool pmm_policy_timer_stop( _pmm_policy_timer_t *pptimer ) -{ - MALI_DEBUG_ASSERT_POINTER(pptimer); - MALI_DEBUG_ASSERT_POINTER(pptimer->timer); - - if( pptimer->set ) - { - _mali_osk_timer_del( pptimer->timer ); - pptimer->set = MALI_FALSE; - pptimer->expired = MALI_FALSE; - return MALI_TRUE; - } - - return MALI_FALSE; -} - -mali_bool pmm_policy_timer_raise_event( _pmm_policy_timer_t *pptimer ) -{ - MALI_DEBUG_ASSERT_POINTER(pptimer); - - if( pptimer->expired ) - { - _mali_uk_pmm_message_s event = { - NULL, - MALI_PMM_EVENT_TIMEOUT, /* Assume timeout id, but set it below */ - 0 }; - - event.id = pptimer->event_id; - event.data = (mali_pmm_message_data)pptimer->start; - - /* Don't need to do any other notification with this timer */ - pptimer->expired = MALI_FALSE; - /* Unset timer so it is free to be set again */ - pptimer->set = MALI_FALSE; - - _mali_ukk_pmm_event_message( &event ); - - return MALI_TRUE; - } - - return MALI_FALSE; -} - -mali_bool pmm_policy_timer_valid( u32 timer_start, u32 other_start ) -{ - return (_mali_osk_time_after( other_start, timer_start ) == 0); -} - - -_mali_osk_errcode_t pmm_policy_init(_mali_pmm_internal_state_t *pmm) -{ - _mali_osk_errcode_t err; - - MALI_DEBUG_ASSERT_POINTER(pmm); - - switch( pmm->policy ) - { - case MALI_PMM_POLICY_ALWAYS_ON: - { - err = pmm_policy_init_always_on(); - } - break; - - case MALI_PMM_POLICY_JOB_CONTROL: - { - err = pmm_policy_init_job_control(pmm); - } - break; - - case MALI_PMM_POLICY_NONE: - default: - err = _MALI_OSK_ERR_FAULT; - } - - return err; -} - -void pmm_policy_term(_mali_pmm_internal_state_t *pmm) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - - switch( pmm->policy ) - { - case MALI_PMM_POLICY_ALWAYS_ON: - { - pmm_policy_term_always_on(); - } - break; - - case MALI_PMM_POLICY_JOB_CONTROL: - { - pmm_policy_term_job_control(); - } - break; - - case MALI_PMM_POLICY_NONE: - default: - MALI_PRINT_ERROR( ("PMM: Invalid policy terminated %d\n", pmm->policy) ); - } -} - - -_mali_osk_errcode_t pmm_policy_process(_mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event) -{ - _mali_osk_errcode_t err; - - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_DEBUG_ASSERT_POINTER(event); - - switch( pmm->policy ) - { - case MALI_PMM_POLICY_ALWAYS_ON: - { - err = pmm_policy_process_always_on( pmm, event ); - } - break; - - case MALI_PMM_POLICY_JOB_CONTROL: - { - err = pmm_policy_process_job_control( pmm, event ); - } - break; - - case MALI_PMM_POLICY_NONE: - default: - err = _MALI_OSK_ERR_FAULT; - } - - return err; -} - - -void pmm_policy_check_policy( _mali_pmm_internal_state_t *pmm ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - - switch( pmm->policy ) - { - case MALI_PMM_POLICY_JOB_CONTROL: - { - pmm_policy_check_job_control(); - } - break; - - default: - /* Nothing needs to be done */ - break; - } -} - - -#endif /* USING_MALI_PMM */ - diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy.h b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy.h deleted file mode 100644 index 75ac8c8..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** - * @file mali_pmm_policy.h - * Defines the power management module policies - */ - -#ifndef __MALI_PMM_POLICY_H__ -#define __MALI_PMM_POLICY_H__ - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** - * @addtogroup pmmapi Power Management Module APIs - * - * @{ - * - * @defgroup pmmapi_policy Power Management Module Policies - * - * @{ - */ - -/** @brief Generic timer for use with policies - */ -typedef struct _pmm_policy_timer -{ - u32 timeout; /**< Timeout for this timer in ticks */ - mali_pmm_event_id event_id; /**< Event id that will be raised when timer expires */ - _mali_osk_timer_t *timer; /**< Timer */ - mali_bool set; /**< Timer set */ - mali_bool expired; /**< Timer expired - event needs to be raised */ - u32 start; /**< Timer start ticks */ -} _pmm_policy_timer_t; - -/** @brief Policy timer initialization - * - * This will create a timer for use in policies, but won't start it - * - * @param pptimer An empty timer structure to be initialized - * @param timeout Timeout in ticks for the timer - * @param id Event id that will be raised on timeout - * @return _MALI_OSK_ERR_OK if the policy could be initialized, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t pmm_policy_timer_init( _pmm_policy_timer_t *pptimer, u32 timeout, mali_pmm_event_id id ); - -/** @brief Policy timer termination - * - * This will clean up a timer that was previously used in policies, it - * will also stop it if started - * - * @param pptimer An initialized timer structure to be terminated - */ -void pmm_policy_timer_term( _pmm_policy_timer_t *pptimer ); - -/** @brief Policy timer start - * - * This will start a previously created timer for use in policies - * When the timer expires after the initialized timeout it will raise - * a PMM event of the event id given on initialization - * As data for the event it will pass the start time of the timer - * - * @param pptimer A previously initialized policy timer - * @return MALI_TRUE if the timer was started, MALI_FALSE if it is already started - */ -mali_bool pmm_policy_timer_start( _pmm_policy_timer_t *pptimer ); - -/** @brief Policy timer stop - * - * This will stop a previously created timer for use in policies - * - * @param pptimer A previously started policy timer - * @return MALI_TRUE if the timer was stopped, MALI_FALSE if it is already stopped - */ -mali_bool pmm_policy_timer_stop( _pmm_policy_timer_t *pptimer ); - -/** @brief Policy timer stop - * - * This raise an event for an expired timer - * - * @param pptimer An expired policy timer - * @return MALI_TRUE if an event was raised, else MALI_FALSE - */ -mali_bool pmm_policy_timer_raise_event( _pmm_policy_timer_t *pptimer ); - -/** @brief Policy timer valid checker - * - * This will check that a timer was started after a given time - * - * @param timer_start Time the timer was started - * @param other_start Time when another event or action occurred - * @return MALI_TRUE if the timer was started after the other time, else MALI_FALSE - */ -mali_bool pmm_policy_timer_valid( u32 timer_start, u32 other_start ); - - -/** @brief Common policy initialization - * - * This will initialize the current policy - * - * @note Any previously initialized policy should be terminated first - * - * @return _MALI_OSK_ERR_OK if the policy could be initialized, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t pmm_policy_init( _mali_pmm_internal_state_t *pmm ); - -/** @brief Common policy termination - * - * This will terminate the current policy. - * @note This can be called when a policy has not been initialized - */ -void pmm_policy_term( _mali_pmm_internal_state_t *pmm ); - -/** @brief Common policy state changer - * - * Given the next available event message, this routine passes it to - * the current policy for processing - * - * @param pmm internal PMM state - * @param event PMM event to process - * @return _MALI_OSK_ERR_OK if the policy state completed okay, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t pmm_policy_process( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event ); - - -/** @brief Common policy checker - * - * If a policy timer fires then this function will be called to - * allow the policy to take the correct action - * - * @param pmm internal PMM state - */ -void pmm_policy_check_policy( _mali_pmm_internal_state_t *pmm ); - -/** @} */ /* End group pmmapi_policy */ -/** @} */ /* End group pmmapi */ - -#ifdef __cplusplus -} -#endif - -#endif /* __MALI_PMM_POLICY_H__ */ diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_alwayson.c b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_alwayson.c deleted file mode 100644 index 0a6b471..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_alwayson.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** - * @file mali_pmm_policy_alwayson.c - * Implementation of the power management module policy - always on - */ - -#if USING_MALI_PMM - -#include "mali_ukk.h" -#include "mali_kernel_common.h" - -#include "mali_pmm.h" -#include "mali_pmm_system.h" -#include "mali_pmm_state.h" -#include "mali_pmm_policy_alwayson.h" - -_mali_osk_errcode_t pmm_policy_init_always_on(void) -{ - /* Nothing to set up */ - MALI_SUCCESS; -} - -void pmm_policy_term_always_on(void) -{ - /* Nothing to tear down */ -} - -_mali_osk_errcode_t pmm_policy_process_always_on( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_DEBUG_ASSERT_POINTER(event); - - switch( event->id ) - { - case MALI_PMM_EVENT_OS_POWER_DOWN: - /* We aren't going to do anything, but signal so we don't block the OS - * NOTE: This may adversely affect any jobs Mali is currently running - */ - _mali_osk_pmm_power_down_done( event->data ); - break; - - case MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK: - case MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK: - /* Not expected in this policy */ - MALI_DEBUG_ASSERT( MALI_FALSE ); - break; - - case MALI_PMM_EVENT_OS_POWER_UP: - /* Nothing to do */ - _mali_osk_pmm_power_up_done( event->data ); - break; - - case MALI_PMM_EVENT_JOB_SCHEDULED: - case MALI_PMM_EVENT_JOB_QUEUED: - case MALI_PMM_EVENT_JOB_FINISHED: - /* Nothing to do - we are always on */ - break; - - case MALI_PMM_EVENT_TIMEOUT: - /* Not expected in this policy */ - MALI_DEBUG_ASSERT( MALI_FALSE ); - break; - - default: - MALI_ERROR(_MALI_OSK_ERR_ITEM_NOT_FOUND); - } - - MALI_SUCCESS; -} - -#endif diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_alwayson.h b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_alwayson.h deleted file mode 100644 index da13224..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_alwayson.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** - * @file mali_pmm_policy_alwayson.h - * Defines the power management module policy for always on - */ - -#ifndef __MALI_PMM_POLICY_ALWAYSON_H__ -#define __MALI_PMM_POLICY_ALWAYSON_H__ - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** - * @addtogroup pmmapi_policy Power Management Module Policies - * - * @{ - */ - -/** @brief Always on policy initialization - * - * @return _MALI_OSK_ERR_OK if the policy could be initialized, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t pmm_policy_init_always_on(void); - -/** @brief Always on policy termination - */ -void pmm_policy_term_always_on(void); - -/** @brief Always on policy state changer - * - * Given the next available event message, this routine processes it - * for the policy and changes state as needed. - * - * Always on policy will ignore all events and keep the Mali cores on - * all the time - * - * @param pmm internal PMM state - * @param event PMM event to process - * @return _MALI_OSK_ERR_OK if the policy state completed okay, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t pmm_policy_process_always_on( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event ); - -/** @} */ /* End group pmmapi_policies */ - -#ifdef __cplusplus -} -#endif - -#endif /* __MALI_PMM_POLICY_ALWAYSON_H__ */ diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_jobcontrol.c b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_jobcontrol.c deleted file mode 100644 index 237d702..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_jobcontrol.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** - * @file mali_pmm_policy_jobcontrol.c - * Implementation of the power management module policy - job control - */ - -#if USING_MALI_PMM - -#include "mali_ukk.h" -#include "mali_kernel_common.h" -#include "mali_platform.h" - -#include "mali_pmm.h" -#include "mali_pmm_system.h" -#include "mali_pmm_state.h" -#include "mali_pmm_policy.h" -#include "mali_pmm_policy_jobcontrol.h" - -typedef struct _pmm_policy_data_job_control -{ - _pmm_policy_timer_t latency; /**< Latency timeout timer for all cores */ - u32 core_active_start; /**< Last time a core was set to active */ - u32 timeout; /**< Timeout in ticks for latency timer */ -} _pmm_policy_data_job_control_t; - - -/* @ brief Local data for this policy - */ -static _pmm_policy_data_job_control_t *data_job_control = NULL; - -/* @brief Set up the timeout if it hasn't already been set and if there are active cores */ -static void job_control_timeout_setup( _mali_pmm_internal_state_t *pmm, _pmm_policy_timer_t *pptimer ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_DEBUG_ASSERT_POINTER(pptimer); - - /* Do we have an inactivity time out and some powered cores? */ - if( pptimer->timeout > 0 && pmm->cores_powered != 0 ) - { - /* Is the system idle and all the powered cores are idle? */ - if( pmm->status == MALI_PMM_STATUS_IDLE && pmm->cores_idle == pmm->cores_powered ) - { - if( pmm_policy_timer_start(pptimer) ) - { - MALIPMM_DEBUG_PRINT( ("PMM policy - Job control: Setting in-activity latency timer\n") ); - } - } - else - { - /* We are not idle so there is no need for an inactivity timer - */ - if( pmm_policy_timer_stop(pptimer) ) - { - MALIPMM_DEBUG_PRINT( ("PMM policy - Job control: Removing in-activity latency timer\n") ); - } - } - } -} - -/* @brief Check the validity of the timeout - and if there is one set */ -static mali_bool job_control_timeout_valid( _mali_pmm_internal_state_t *pmm, _pmm_policy_timer_t *pptimer, u32 timer_start ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_DEBUG_ASSERT_POINTER(pptimer); - - /* Not a valid timer! */ - if( pptimer->timeout == 0 ) return MALI_FALSE; - - /* Are some cores powered and are they all idle? */ - if( (pmm->cores_powered != 0) && (pmm->cores_idle == pmm->cores_powered) ) - { - /* Has latency timeout started after the last core was active? */ - if( pmm_policy_timer_valid( timer_start, data_job_control->core_active_start ) ) - { - return MALI_TRUE; - } - else - { - MALIPMM_DEBUG_PRINT( ("PMM: In-activity latency time out ignored - out of date\n") ); - } - } - else - { - if( pmm->cores_powered == 0 ) - { - MALIPMM_DEBUG_PRINT( ("PMM: In-activity latency time out ignored - cores already off\n") ); - } - else - { - MALIPMM_DEBUG_PRINT( ("PMM: In-activity latency time out ignored - cores active\n") ); - } - } - - return MALI_FALSE; -} - -_mali_osk_errcode_t pmm_policy_init_job_control( _mali_pmm_internal_state_t *pmm ) -{ - _mali_osk_errcode_t err; - MALI_DEBUG_ASSERT_POINTER( pmm ); - MALI_DEBUG_ASSERT( data_job_control == NULL ); - - data_job_control = (_pmm_policy_data_job_control_t *) _mali_osk_malloc(sizeof(*data_job_control)); - MALI_CHECK_NON_NULL( data_job_control, _MALI_OSK_ERR_NOMEM ); - - data_job_control->core_active_start = _mali_osk_time_tickcount(); - data_job_control->timeout = MALI_PMM_POLICY_JOBCONTROL_INACTIVITY_TIMEOUT; - - err = pmm_policy_timer_init( &data_job_control->latency, data_job_control->timeout, MALI_PMM_EVENT_TIMEOUT ); - if( err != _MALI_OSK_ERR_OK ) - { - _mali_osk_free( data_job_control ); - data_job_control = NULL; - return err; - } - - /* Start the latency timeout */ - job_control_timeout_setup( pmm, &data_job_control->latency ); - - MALI_SUCCESS; -} - -void pmm_policy_term_job_control(void) -{ - if( data_job_control != NULL ) - { - pmm_policy_timer_term( &data_job_control->latency ); - _mali_osk_free( data_job_control ); - data_job_control = NULL; - } -} - -static void pmm_policy_job_control_job_queued( _mali_pmm_internal_state_t *pmm ) -{ - mali_pmm_core_mask cores; - mali_pmm_core_mask cores_subset; - - /* Make sure that all cores are powered in this - * simple policy - */ - cores = pmm->cores_registered; - cores_subset = pmm_cores_to_power_up( pmm, cores ); - if( cores_subset != 0 ) - { - /* There are some cores that need powering up */ - if( !pmm_invoke_power_up( pmm ) ) - { - /* Need to wait until finished */ - pmm->status = MALI_PMM_STATUS_POLICY_POWER_UP; - } - } -} - -_mali_osk_errcode_t pmm_policy_process_job_control( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event ) -{ - mali_pmm_core_mask cores; - mali_pmm_core_mask cores_subset; - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_DEBUG_ASSERT_POINTER(event); - MALI_DEBUG_ASSERT_POINTER(data_job_control); - - MALIPMM_DEBUG_PRINT( ("PMM: Job control policy process start - status=%d\n", pmm->status) ); - - /* Mainly the data is the cores */ - cores = pmm_cores_from_event_data( pmm, event ); - -#if MALI_STATE_TRACKING - pmm->mali_last_pmm_status = pmm->status; -#endif /* MALI_STATE_TRACKING */ - - switch( pmm->status ) - { - /**************** IDLE ****************/ - case MALI_PMM_STATUS_IDLE: - switch( event->id ) - { - case MALI_PMM_EVENT_OS_POWER_UP: - /* Not expected in this state */ - break; - - case MALI_PMM_EVENT_JOB_SCHEDULED: - - /* Update idle cores to indicate active - remove these! */ - pmm_cores_set_active( pmm, cores ); - /* Remember when this happened */ - data_job_control->core_active_start = event->ts; -#if MALI_POWER_MGMT_TEST_SUITE - _mali_osk_pmm_policy_events_notifications(MALI_PMM_EVENT_JOB_SCHEDULED); -#endif - - /*** FALL THROUGH to QUEUED to check POWER UP ***/ - - case MALI_PMM_EVENT_JOB_QUEUED: - - pmm_policy_job_control_job_queued( pmm ); -#if MALI_POWER_MGMT_TEST_SUITE - _mali_osk_pmm_policy_events_notifications(MALI_PMM_EVENT_JOB_QUEUED); -#endif - break; - - case MALI_PMM_EVENT_DVFS_PAUSE: - - cores_subset = pmm_cores_to_power_down( pmm, cores, MALI_FALSE ); - if ( cores_subset != 0 ) - { - if ( !pmm_power_down_okay( pmm ) ) - { - pmm->is_dvfs_active = 1; - pmm->status = MALI_PMM_STATUS_OS_POWER_DOWN; - pmm_save_os_event_data( pmm, event->data ); - break; - } - } - pmm->status = MALI_PMM_STATUS_DVFS_PAUSE; - _mali_osk_pmm_dvfs_operation_done(0); - break; - - case MALI_PMM_EVENT_OS_POWER_DOWN: - - /* Need to power down all cores even if we need to wait for them */ - cores_subset = pmm_cores_to_power_down( pmm, cores, MALI_FALSE ); - if( cores_subset != 0 ) - { - /* There are some cores that need powering down */ - if( !pmm_invoke_power_down( pmm, MALI_POWER_MODE_DEEP_SLEEP ) ) - { - /* We need to wait until they are idle */ - - pmm->status = MALI_PMM_STATUS_OS_POWER_DOWN; - /* Save the OS data to respond later */ - pmm_save_os_event_data( pmm, event->data ); - /* Exit this case - as we have to wait */ - break; - } - } - else - { - mali_platform_power_mode_change(MALI_POWER_MODE_DEEP_SLEEP); - - } - /* Set waiting status */ - pmm->status = MALI_PMM_STATUS_OS_WAITING; - /* All cores now down - respond to OS power event */ - _mali_osk_pmm_power_down_done( event->data ); - break; - - case MALI_PMM_EVENT_JOB_FINISHED: - - /* Update idle cores - add these! */ - pmm_cores_set_idle( pmm, cores ); -#if MALI_POWER_MGMT_TEST_SUITE - _mali_osk_pmm_policy_events_notifications(MALI_PMM_EVENT_JOB_FINISHED); -#endif - if( data_job_control->timeout > 0 ) - { - /* Wait for time out to fire */ - break; - } - /* For job control policy - turn off all cores */ - cores = pmm->cores_powered; - - /*** FALL THROUGH to TIMEOUT TEST as NO TIMEOUT ***/ - - case MALI_PMM_EVENT_TIMEOUT: - - /* Main job control policy - turn off cores after inactivity */ - if( job_control_timeout_valid( pmm, &data_job_control->latency, (u32)event->data ) ) - { - /* Valid timeout of inactivity - so find out if we can power down - * immedately - if we can't then this means the cores are still in fact - * active - */ - cores_subset = pmm_cores_to_power_down( pmm, cores, MALI_TRUE ); - if( cores_subset != 0 ) - { - /* Check if we can really power down, if not then we are not - * really in-active - */ - if( !pmm_invoke_power_down( pmm, MALI_POWER_MODE_LIGHT_SLEEP ) ) - { - pmm_power_down_cancel( pmm ); - } - } - /* else there are no cores powered up! */ - } -#if MALI_POWER_MGMT_TEST_SUITE - _mali_osk_pmm_policy_events_notifications(MALI_PMM_EVENT_TIMEOUT); -#endif - break; - - default: - /* Unexpected event */ - MALI_ERROR(_MALI_OSK_ERR_ITEM_NOT_FOUND); - } - break; - - /******************DVFS PAUSE**************/ - case MALI_PMM_STATUS_DVFS_PAUSE: - switch ( event->id ) - { - case MALI_PMM_EVENT_DVFS_RESUME: - - if ( pmm->cores_powered != 0 ) - { - pmm->cores_ack_down =0; - pmm_power_down_cancel( pmm ); - pmm->status = MALI_PMM_STATUS_IDLE; - } - else - { - pmm_policy_job_control_job_queued( pmm ); - } - _mali_osk_pmm_dvfs_operation_done( 0 ); - break; - - case MALI_PMM_EVENT_OS_POWER_DOWN: - /* Set waiting status */ - pmm->status = MALI_PMM_STATUS_OS_WAITING; - if ( pmm->cores_powered != 0 ) - { - if ( pmm_invoke_power_down( pmm, MALI_POWER_MODE_DEEP_SLEEP ) ) - { - _mali_osk_pmm_power_down_done( 0 ); - break; - } - } - else - { - mali_platform_power_mode_change(MALI_POWER_MODE_DEEP_SLEEP); - } - _mali_osk_pmm_power_down_done( 0 ); - break; - default: - break; - } - break; - - /**************** POWER UP ****************/ - case MALI_PMM_STATUS_OS_POWER_UP: - case MALI_PMM_STATUS_POLICY_POWER_UP: - switch( event->id ) - { - case MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK: - /* Make sure cores powered off equal what we expect */ - MALI_DEBUG_ASSERT( cores == pmm->cores_pend_up ); - pmm_cores_set_up_ack( pmm, cores ); - - if( pmm_invoke_power_up( pmm ) ) - { - if( pmm->status == MALI_PMM_STATUS_OS_POWER_UP ) - { - /* Get the OS data and respond to the power up */ - _mali_osk_pmm_power_up_done( pmm_retrieve_os_event_data( pmm ) ); - } - pmm->status = MALI_PMM_STATUS_IDLE; - } - break; - - default: - /* Unexpected event */ - MALI_ERROR(_MALI_OSK_ERR_ITEM_NOT_FOUND); - } - break; - - /**************** POWER DOWN ****************/ - case MALI_PMM_STATUS_OS_POWER_DOWN: - case MALI_PMM_STATUS_POLICY_POWER_DOWN: - switch( event->id ) - { - - case MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK: - - pmm_cores_set_down_ack( pmm, cores ); - - if ( pmm->is_dvfs_active == 1 ) - { - if( pmm_power_down_okay( pmm ) ) - { - pmm->is_dvfs_active = 0; - pmm->status = MALI_PMM_STATUS_DVFS_PAUSE; - _mali_osk_pmm_dvfs_operation_done( pmm_retrieve_os_event_data( pmm ) ); - } - break; - } - - /* Now check if we can power down */ - if( pmm_invoke_power_down( pmm, MALI_POWER_MODE_DEEP_SLEEP ) ) - { - if( pmm->status == MALI_PMM_STATUS_OS_POWER_DOWN ) - { - /* Get the OS data and respond to the power down */ - _mali_osk_pmm_power_down_done( pmm_retrieve_os_event_data( pmm ) ); - } - pmm->status = MALI_PMM_STATUS_OS_WAITING; - } - break; - - default: - /* Unexpected event */ - MALI_ERROR(_MALI_OSK_ERR_ITEM_NOT_FOUND); - } - break; - - case MALI_PMM_STATUS_OS_WAITING: - switch( event->id ) - { - case MALI_PMM_EVENT_OS_POWER_UP: - cores_subset = pmm_cores_to_power_up( pmm, cores ); - if( cores_subset != 0 ) - { - /* There are some cores that need powering up */ - if( !pmm_invoke_power_up( pmm ) ) - { - /* Need to wait until power up complete */ - pmm->status = MALI_PMM_STATUS_OS_POWER_UP; - /* Save the OS data to respond later */ - pmm_save_os_event_data( pmm, event->data ); - /* Exit this case - as we have to wait */ - break; - } - } - pmm->status = MALI_PMM_STATUS_IDLE; - /* All cores now up - respond to OS power up event */ - _mali_osk_pmm_power_up_done( event->data ); - break; - - default: - /* All other messages are ignored in this state */ - break; - } - break; - - default: - /* Unexpected state */ - MALI_ERROR(_MALI_OSK_ERR_FAULT); - } - - /* Set in-activity latency timer - if required */ - job_control_timeout_setup( pmm, &data_job_control->latency ); - - /* Update the PMM state */ - pmm_update_system_state( pmm ); -#if MALI_STATE_TRACKING - pmm->mali_new_event_status = event->id; -#endif /* MALI_STATE_TRACKING */ - - MALIPMM_DEBUG_PRINT( ("PMM: Job control policy process end - status=%d and event=%d\n", pmm->status,event->id) ); - - MALI_SUCCESS; -} - -void pmm_policy_check_job_control() -{ - MALI_DEBUG_ASSERT_POINTER(data_job_control); - - /* Latency timer must have expired raise the event */ - pmm_policy_timer_raise_event(&data_job_control->latency); -} - - -#endif /* USING_MALI_PMM */ diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_jobcontrol.h b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_jobcontrol.h deleted file mode 100644 index dcfa438..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_policy_jobcontrol.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** - * @file mali_pmm_policy.h - * Defines the power management module policies - */ - -#ifndef __MALI_PMM_POLICY_JOBCONTROL_H__ -#define __MALI_PMM_POLICY_JOBCONTROL_H__ - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** - * @addtogroup pmmapi_policy Power Management Module Policies - * - * @{ - */ - -/** @brief The jobcontrol policy inactivity latency timeout (in ticks) - * before the hardware is switched off - * - * @note Setting this low whilst tracing or producing debug output can - * cause alot of timeouts to fire which can affect the PMM behaviour - */ -#define MALI_PMM_POLICY_JOBCONTROL_INACTIVITY_TIMEOUT 50 - -/** @brief Job control policy initialization - * - * @return _MALI_OSK_ERR_OK if the policy could be initialized, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t pmm_policy_init_job_control(_mali_pmm_internal_state_t *pmm); - -/** @brief Job control policy termination - */ -void pmm_policy_term_job_control(void); - -/** @brief Job control policy state changer - * - * Given the next available event message, this routine processes it - * for the policy and changes state as needed. - * - * Job control policy depends on events from the Mali cores, and will - * power down all cores after an inactivity latency timeout. It will - * power the cores back on again when a job is scheduled to run. - * - * @param pmm internal PMM state - * @param event PMM event to process - * @return _MALI_OSK_ERR_OK if the policy state completed okay, or a suitable - * _mali_osk_errcode_t otherwise. - */ -_mali_osk_errcode_t pmm_policy_process_job_control( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event ); - -/** @brief Job control policy checker - * - * The latency timer has fired and we need to raise the correct event to - * handle it - * - * @param pmm internal PMM state - */ -void pmm_policy_check_job_control(void); - -/** @} */ /* End group pmmapi_policy */ - -#ifdef __cplusplus -} -#endif - -#endif /* __MALI_PMM_POLICY_JOBCONTROL_H__ */ diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_state.c b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_state.c deleted file mode 100644 index d529b9a..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_state.c +++ /dev/null @@ -1,716 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#if USING_MALI_PMM - -#include "mali_ukk.h" -#include "mali_kernel_common.h" -#include "mali_kernel_subsystem.h" - -#include "mali_pmm.h" -#include "mali_pmm_state.h" -#include "mali_pmm_system.h" - -#include "mali_kernel_core.h" -#include "mali_platform.h" - -#define SIZEOF_CORES_LIST 6 - -/* NOTE: L2 *MUST* be first on the list so that it - * is correctly powered on first and powered off last - */ -static mali_pmm_core_id cores_list[] = { MALI_PMM_CORE_L2, - MALI_PMM_CORE_GP, - MALI_PMM_CORE_PP0, - MALI_PMM_CORE_PP1, - MALI_PMM_CORE_PP2, - MALI_PMM_CORE_PP3 }; - - - -void pmm_update_system_state( _mali_pmm_internal_state_t *pmm ) -{ - mali_pmm_state state; - - MALI_DEBUG_ASSERT_POINTER(pmm); - - if( pmm->cores_registered == 0 ) - { - state = MALI_PMM_STATE_UNAVAILABLE; - } - else if( pmm->cores_powered == 0 ) - { - state = MALI_PMM_STATE_SYSTEM_OFF; - } - else if( pmm->cores_powered == pmm->cores_registered ) - { - state = MALI_PMM_STATE_SYSTEM_ON; - } - else - { - /* Some other state where not everything is on or off */ - state = MALI_PMM_STATE_SYSTEM_TRANSITION; - } - -#if MALI_PMM_TRACE - _mali_pmm_trace_state_change( pmm->state, state ); -#endif - pmm->state = state; -} - -mali_pmm_core_mask pmm_cores_from_event_data( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event ) -{ - mali_pmm_core_mask cores; - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_DEBUG_ASSERT_POINTER(event); - - switch( event->id ) - { - case MALI_PMM_EVENT_OS_POWER_UP: - case MALI_PMM_EVENT_OS_POWER_DOWN: - /* All cores - the system */ - cores = pmm->cores_registered; - break; - - case MALI_PMM_EVENT_JOB_SCHEDULED: - case MALI_PMM_EVENT_JOB_QUEUED: - case MALI_PMM_EVENT_JOB_FINISHED: - case MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK: - case MALI_PMM_EVENT_INTERNAL_POWER_DOWN_ACK: - /* Currently the main event data is only the cores - * for these messages - */ - cores = (mali_pmm_core_mask)event->data; - if( cores == MALI_PMM_CORE_SYSTEM ) - { - cores = pmm->cores_registered; - } - else if( cores == MALI_PMM_CORE_PP_ALL ) - { - /* Get the subset of registered PP cores */ - cores = (pmm->cores_registered & MALI_PMM_CORE_PP_ALL); - } - MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores ); - break; - - default: - /* Assume timeout messages - report cores still powered */ - cores = pmm->cores_powered; - break; - } - - return cores; -} - -mali_pmm_core_mask pmm_cores_to_power_up( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ) -{ - mali_pmm_core_mask cores_subset; - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores ); - - /* Check that cores aren't pending power down when asked for power up */ - MALI_DEBUG_ASSERT( pmm->cores_pend_down == 0 ); - - cores_subset = (~(pmm->cores_powered) & cores); - if( cores_subset != 0 ) - { - /* There are some cores that need powering up */ - pmm->cores_pend_up = cores_subset; - } - - return cores_subset; -} - -mali_pmm_core_mask pmm_cores_to_power_down( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores, mali_bool immediate_only ) -{ - mali_pmm_core_mask cores_subset; - _mali_osk_errcode_t err; - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores ); - - /* Check that cores aren't pending power up when asked for power down */ - MALI_DEBUG_ASSERT( pmm->cores_pend_up == 0 ); - - cores_subset = (pmm->cores_powered & cores); - if( cores_subset != 0 ) - { - int n; - volatile mali_pmm_core_mask *ppowered = &(pmm->cores_powered); - - /* There are some cores that need powering up, but we may - * need to wait until they are idle - */ - for( n = SIZEOF_CORES_LIST-1; n >= 0; n-- ) - { - if( (cores_list[n] & cores_subset) != 0 ) - { - /* Core is to be powered down */ - pmm->cores_pend_down |= cores_list[n]; - - /* Can't hold the power lock, when acessing subsystem mutex via - * the core power call. - * Due to terminatation of driver requiring a subsystem mutex - * and then power lock held to unregister a core. - * This does mean that the following function could fail - * as the core is unregistered before we tell it to power - * down, but it does not matter as we are terminating - */ -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 0; -#endif /* MALI_STATE_TRACKING */ - - MALI_PMM_UNLOCK(pmm); - /* Signal the core to power down - * If it is busy (not idle) it will set a pending power down flag - * (as long as we don't want to only immediately power down). - * If it isn't busy it will move out of the idle queue right - * away - */ - err = mali_core_signal_power_down( cores_list[n], immediate_only ); - MALI_PMM_LOCK(pmm); - -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 1; -#endif /* MALI_STATE_TRACKING */ - - - /* Re-read cores_subset in case it has changed */ - cores_subset = (*ppowered & cores); - - if( err == _MALI_OSK_ERR_OK ) - { - /* We moved an idle core to the power down queue - * which means it is now acknowledged (if it is still - * registered) - */ - pmm->cores_ack_down |= (cores_list[n] & cores_subset); - } - else - { - MALI_DEBUG_PRINT(1,("PMM: In pmm_cores_to_power_down, the error and cores powered are..%x....%x",err,*ppowered)); - MALI_DEBUG_ASSERT( err == _MALI_OSK_ERR_BUSY || - (err == _MALI_OSK_ERR_FAULT && - (*ppowered & cores_list[n]) == 0) ); - /* If we didn't move a core - it must be active, so - * leave it pending, so we get an acknowledgement (when - * not in immediate only mode) - * Alternatively we are shutting down and the core has - * been unregistered - */ - } - } - } - } - - return cores_subset; -} - -void pmm_power_down_cancel( _mali_pmm_internal_state_t *pmm ) -{ - int n; - mali_pmm_core_mask pd, ad; - _mali_osk_errcode_t err; - volatile mali_pmm_core_mask *pregistered; - - MALI_DEBUG_ASSERT_POINTER(pmm); - - MALIPMM_DEBUG_PRINT( ("PMM: Cancelling power down\n") ); - - pd = pmm->cores_pend_down; - ad = pmm->cores_ack_down; - /* Clear the pending cores so that they don't move to the off - * queue if they haven't already - */ - pmm->cores_pend_down = 0; - pmm->cores_ack_down = 0; - pregistered = &(pmm->cores_registered); - - /* Power up all the pending power down cores - just so - * we make sure the system is in a known state, as a - * pending core might have sent an acknowledged message - * which hasn't been read yet. - */ - for( n = 0; n < SIZEOF_CORES_LIST; n++ ) - { - if( (cores_list[n] & pd) != 0 ) - { - /* Can't hold the power lock, when acessing subsystem mutex via - * the core power call. - * Due to terminatation of driver requiring a subsystem mutex - * and then power lock held to unregister a core. - * This does mean that the following power up function could fail - * as the core is unregistered before we tell it to power - * up, but it does not matter as we are terminating - */ -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 0; -#endif /* MALI_STATE_TRACKING */ - - MALI_PMM_UNLOCK(pmm); - /* As we are cancelling - only move the cores back to the queue - - * no reset needed - */ - err = mali_core_signal_power_up( cores_list[n], MALI_TRUE ); - MALI_PMM_LOCK(pmm); -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 1; -#endif /* MALI_STATE_TRACKING */ - - /* Update pending list with the current registered cores */ - pd &= (*pregistered); - - if( err != _MALI_OSK_ERR_OK ) - { - MALI_DEBUG_ASSERT( (err == _MALI_OSK_ERR_BUSY && - ((cores_list[n] & ad) == 0)) || - (err == _MALI_OSK_ERR_FAULT && - (*pregistered & cores_list[n]) == 0) ); - /* If we didn't power up a core - it must be active and - * hasn't actually tried to power down - this is expected - * for cores that haven't acknowledged - * Alternatively we are shutting down and the core has - * been unregistered - */ - } - } - } - /* Only used in debug builds */ - MALI_IGNORE(ad); -} - - -mali_bool pmm_power_down_okay( _mali_pmm_internal_state_t *pmm ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - - return ( pmm->cores_pend_down == pmm->cores_ack_down ? MALI_TRUE : MALI_FALSE ); -} - -mali_bool pmm_invoke_power_down( _mali_pmm_internal_state_t *pmm, mali_power_mode power_mode ) -{ - _mali_osk_errcode_t err; - MALI_DEBUG_ASSERT_POINTER(pmm); - - /* Check that cores are pending power down during power down invoke */ - MALI_DEBUG_ASSERT( pmm->cores_pend_down != 0 ); - /* Check that cores are not pending power up during power down invoke */ - MALI_DEBUG_ASSERT( pmm->cores_pend_up == 0 ); - - if( !pmm_power_down_okay( pmm ) ) - { - MALIPMM_DEBUG_PRINT( ("PMM: Waiting for cores to go idle for power off - 0x%08x / 0x%08x\n", - pmm->cores_pend_down, pmm->cores_ack_down) ); - return MALI_FALSE; - } - else - { - pmm->cores_powered &= ~(pmm->cores_pend_down); -#if !MALI_PMM_NO_PMU - err = malipmm_powerdown( pmm->cores_pend_down, power_mode); -#else - err = _MALI_OSK_ERR_OK; -#endif - - if( err == _MALI_OSK_ERR_OK ) - { -#if MALI_PMM_TRACE - mali_pmm_core_mask old_power = pmm->cores_powered; -#endif - /* Remove powered down cores from idle and powered list */ - pmm->cores_idle &= ~(pmm->cores_pend_down); - /* Reset pending/acknowledged status */ - pmm->cores_pend_down = 0; - pmm->cores_ack_down = 0; -#if MALI_PMM_TRACE - _mali_pmm_trace_hardware_change( old_power, pmm->cores_powered ); -#endif - } - else - { - pmm->cores_powered |= pmm->cores_pend_down; - MALI_PRINT_ERROR( ("PMM: Failed to get PMU to power down cores - (0x%x) %s", - pmm->cores_pend_down, pmm_trace_get_core_name(pmm->cores_pend_down)) ); - pmm->fatal_power_err = MALI_TRUE; - } - } - - return MALI_TRUE; -} - - -mali_bool pmm_power_up_okay( _mali_pmm_internal_state_t *pmm ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - - return ( pmm->cores_pend_up == pmm->cores_ack_up ? MALI_TRUE : MALI_FALSE ); -} - - -mali_bool pmm_invoke_power_up( _mali_pmm_internal_state_t *pmm ) -{ - _mali_osk_errcode_t err; - - MALI_DEBUG_ASSERT_POINTER(pmm); - - /* Check that cores are pending power up during power up invoke */ - MALI_DEBUG_ASSERT( pmm->cores_pend_up != 0 ); - /* Check that cores are not pending power down during power up invoke */ - MALI_DEBUG_ASSERT( pmm->cores_pend_down == 0 ); - - if( pmm_power_up_okay( pmm ) ) - { - /* Power up has completed - sort out subsystem core status */ - - int n; - /* Use volatile to access, so that it is updated if any cores are unregistered */ - volatile mali_pmm_core_mask *ppendup = &(pmm->cores_pend_up); -#if MALI_PMM_TRACE - mali_pmm_core_mask old_power = pmm->cores_powered; -#endif - /* Move cores into idle queues */ - for( n = 0; n < SIZEOF_CORES_LIST; n++ ) - { - if( (cores_list[n] & (*ppendup)) != 0 ) - { - /* Can't hold the power lock, when acessing subsystem mutex via - * the core power call. - * Due to terminatation of driver requiring a subsystem mutex - * and then power lock held to unregister a core. - * This does mean that the following function could fail - * as the core is unregistered before we tell it to power - * up, but it does not matter as we are terminating - */ -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 0; -#endif /* MALI_STATE_TRACKING */ - - MALI_PMM_UNLOCK(pmm); - err = mali_core_signal_power_up( cores_list[n], MALI_FALSE ); - MALI_PMM_LOCK(pmm); - -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 1; -#endif /* MALI_STATE_TRACKING */ - - - if( err != _MALI_OSK_ERR_OK ) - { - MALI_DEBUG_PRINT(1,("In pmm_invoke_power_up:: The error and pending cores to be powered up are...%x...%x",err,*ppendup)); - MALI_DEBUG_ASSERT( (err == _MALI_OSK_ERR_FAULT && - (*ppendup & cores_list[n]) == 0) ); - /* We only expect this to fail when we are shutting down - * and the core has been unregistered - */ - } - } - } - /* Finished power up - add cores to idle and powered list */ - pmm->cores_powered |= (*ppendup); - pmm->cores_idle |= (*ppendup); - /* Reset pending/acknowledge status */ - pmm->cores_pend_up = 0; - pmm->cores_ack_up = 0; - -#if MALI_PMM_TRACE - _mali_pmm_trace_hardware_change( old_power, pmm->cores_powered ); -#endif - return MALI_TRUE; - } - else - { -#if !MALI_PMM_NO_PMU - /* Power up must now be done */ - err = malipmm_powerup( pmm->cores_pend_up ); -#else - err = _MALI_OSK_ERR_OK; -#endif - if( err != _MALI_OSK_ERR_OK ) - { - MALI_PRINT_ERROR( ("PMM: Failed to get PMU to power up cores - (0x%x) %s", - pmm->cores_pend_up, pmm_trace_get_core_name(pmm->cores_pend_up)) ); - pmm->fatal_power_err = MALI_TRUE; - } - else - { - /* TBD - Update core status immediately rather than use event message */ - _mali_uk_pmm_message_s event = { - NULL, - MALI_PMM_EVENT_INTERNAL_POWER_UP_ACK, - 0 }; - /* All the cores that were pending power up, have now completed power up */ - event.data = pmm->cores_pend_up; - _mali_ukk_pmm_event_message( &event ); - MALIPMM_DEBUG_PRINT( ("PMM: Sending ACK to power up") ); - } - } - - /* Always return false, as we need an interrupt to acknowledge - * when power up is complete - */ - return MALI_FALSE; -} - -mali_pmm_core_mask pmm_cores_set_active( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores ); - - pmm->cores_idle &= (~cores); - return pmm->cores_idle; -} - -mali_pmm_core_mask pmm_cores_set_idle( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores ); - - pmm->cores_idle |= (cores); - return pmm->cores_idle; -} - -mali_pmm_core_mask pmm_cores_set_down_ack( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores ); - - /* Check core is not pending a power down */ - MALI_DEBUG_ASSERT( (pmm->cores_pend_down & cores) != 0 ); - /* Check core has not acknowledged power down more than once */ - MALI_DEBUG_ASSERT( (pmm->cores_ack_down & cores) == 0 ); - - pmm->cores_ack_down |= (cores); - - return pmm->cores_ack_down; -} - -void pmm_fatal_reset( _mali_pmm_internal_state_t *pmm ) -{ - _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; - _mali_osk_notification_t *msg = NULL; - mali_pmm_status status; - MALI_DEBUG_ASSERT_POINTER(pmm); - MALIPMM_DEBUG_PRINT( ("PMM: Fatal Reset called") ); - - MALI_DEBUG_ASSERT( pmm->status != MALI_PMM_STATUS_OFF ); - - /* Reset the common status */ - pmm->waiting = 0; - pmm->missed = 0; - pmm->fatal_power_err = MALI_FALSE; - pmm->no_events = 0; - pmm->check_policy = MALI_FALSE; - pmm->cores_pend_down = 0; - pmm->cores_pend_up = 0; - pmm->cores_ack_down = 0; - pmm->cores_ack_up = 0; - pmm->is_dvfs_active = 0; -#if MALI_PMM_TRACE - pmm->messages_sent = 0; - pmm->messages_received = 0; - pmm->imessages_sent = 0; - pmm->imessages_received = 0; - MALI_PRINT( ("PMM Trace: *** Fatal reset occurred ***") ); -#endif - - /* Set that we are unavailable whilst resetting */ - pmm->state = MALI_PMM_STATE_UNAVAILABLE; - status = pmm->status; - pmm->status = MALI_PMM_STATUS_OFF; - - /* We want all cores powered */ - pmm->cores_powered = pmm->cores_registered; - /* The cores may not be idle, but this state will be rectified later */ - pmm->cores_idle = pmm->cores_registered; - - /* So power on any cores that are registered */ - if( pmm->cores_registered != 0 ) - { - int n; - volatile mali_pmm_core_mask *pregistered = &(pmm->cores_registered); -#if !MALI_PMM_NO_PMU - err = malipmm_powerup( pmm->cores_registered ); -#endif - if( err != _MALI_OSK_ERR_OK ) - { - /* This is very bad as we can't even be certain the cores are now - * powered up - */ - MALI_PRINT_ERROR( ("PMM: Failed to perform PMM reset!\n") ); - /* TBD driver exit? */ - } - - for( n = SIZEOF_CORES_LIST-1; n >= 0; n-- ) - { - if( (cores_list[n] & (*pregistered)) != 0 ) - { -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 0; -#endif /* MALI_STATE_TRACKING */ - - MALI_PMM_UNLOCK(pmm); - /* Core is now active - so try putting it in the idle queue */ - err = mali_core_signal_power_up( cores_list[n], MALI_FALSE ); - MALI_PMM_LOCK(pmm); -#if MALI_STATE_TRACKING - pmm->mali_pmm_lock_acquired = 1; -#endif /* MALI_STATE_TRACKING */ - - /* We either succeeded, or we were not off anyway, or we have - * just be deregistered - */ - MALI_DEBUG_ASSERT( (err == _MALI_OSK_ERR_OK) || - (err == _MALI_OSK_ERR_BUSY) || - (err == _MALI_OSK_ERR_FAULT && - (*pregistered & cores_list[n]) == 0) ); - } - } - } - - /* Unblock any pending OS event */ - if( status == MALI_PMM_STATUS_OS_POWER_UP ) - { - /* Get the OS data and respond to the power up */ - _mali_osk_pmm_power_up_done( pmm_retrieve_os_event_data( pmm ) ); - } - if( status == MALI_PMM_STATUS_OS_POWER_DOWN ) - { - /* Get the OS data and respond to the power down - * NOTE: We are not powered down at this point due to power problems, - * so we are lying to the system, but something bad has already - * happened and we are trying unstick things - * TBD - Add busy loop to power down cores? - */ - _mali_osk_pmm_power_down_done( pmm_retrieve_os_event_data( pmm ) ); - } - - /* Purge the event queues */ - do - { - if( _mali_osk_notification_queue_dequeue( pmm->iqueue, &msg ) == _MALI_OSK_ERR_OK ) - { - _mali_osk_notification_delete ( msg ); - break; - } - } while (MALI_TRUE); - - do - { - if( _mali_osk_notification_queue_dequeue( pmm->queue, &msg ) == _MALI_OSK_ERR_OK ) - { - _mali_osk_notification_delete ( msg ); - break; - } - } while (MALI_TRUE); - - /* Return status/state to normal */ - pmm->status = MALI_PMM_STATUS_IDLE; - pmm_update_system_state(pmm); -} - -mali_pmm_core_mask pmm_cores_set_up_ack( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( pmm->cores_registered, cores ); - - /* Check core is not pending a power up */ - MALI_DEBUG_ASSERT( (pmm->cores_pend_up & cores) != 0 ); - /* Check core has not acknowledged power up more than once */ - MALI_DEBUG_ASSERT( (pmm->cores_ack_up & cores) == 0 ); - - pmm->cores_ack_up |= (cores); - - return pmm->cores_ack_up; -} - -void pmm_save_os_event_data(_mali_pmm_internal_state_t *pmm, mali_pmm_message_data data) -{ - MALI_DEBUG_ASSERT_POINTER(pmm); - /* Check that there is no saved data */ - MALI_DEBUG_ASSERT( pmm->os_data == 0 ); - /* Can't store zero data - as retrieve check will fail */ - MALI_DEBUG_ASSERT( data != 0 ); - - pmm->os_data = data; -} - -mali_pmm_message_data pmm_retrieve_os_event_data(_mali_pmm_internal_state_t *pmm) -{ - mali_pmm_message_data data; - - MALI_DEBUG_ASSERT_POINTER(pmm); - /* Check that there is saved data */ - MALI_DEBUG_ASSERT( pmm->os_data != 0 ); - - /* Get data, and clear the saved version */ - data = pmm->os_data; - pmm->os_data = 0; - - return data; -} - -/* Create list of core names to look up - * We are doing it this way to overcome the need for - * either string allocation, or stack space, so we - * use constant strings instead - */ -typedef struct pmm_trace_corelist -{ - mali_pmm_core_mask id; - const char *name; -} pmm_trace_corelist_t; - -static pmm_trace_corelist_t pmm_trace_cores[] = { - { MALI_PMM_CORE_SYSTEM, "SYSTEM" }, - { MALI_PMM_CORE_GP, "GP" }, - { MALI_PMM_CORE_L2, "L2" }, - { MALI_PMM_CORE_PP0, "PP0" }, - { MALI_PMM_CORE_PP1, "PP1" }, - { MALI_PMM_CORE_PP2, "PP2" }, - { MALI_PMM_CORE_PP3, "PP3" }, - { MALI_PMM_CORE_PP_ALL, "PP (all)" }, - { (MALI_PMM_CORE_GP | MALI_PMM_CORE_L2 | MALI_PMM_CORE_PP0), - "GP+L2+PP0" }, - { (MALI_PMM_CORE_GP | MALI_PMM_CORE_PP0), - "GP+PP0" }, - { (MALI_PMM_CORE_GP | MALI_PMM_CORE_L2 | MALI_PMM_CORE_PP0 | MALI_PMM_CORE_PP1), - "GP+L2+PP0+PP1" }, - { (MALI_PMM_CORE_GP | MALI_PMM_CORE_PP0 | MALI_PMM_CORE_PP1), - "GP+PP0+PP1" }, - { 0, NULL } /* Terminator of list */ -}; - -const char *pmm_trace_get_core_name( mali_pmm_core_mask cores ) -{ - const char *dname = NULL; - int cl; - - /* Look up name in corelist */ - cl = 0; - while( pmm_trace_cores[cl].name != NULL ) - { - if( pmm_trace_cores[cl].id == cores ) - { - dname = pmm_trace_cores[cl].name; - break; - } - cl++; - } - - if( dname == NULL ) - { - /* We don't know a good short-hand for the configuration */ - dname = "[multi-core]"; - } - - return dname; -} - -#endif /* USING_MALI_PMM */ - diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_state.h b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_state.h deleted file mode 100644 index 4768344..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_state.h +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __MALI_PMM_STATE_H__ -#define __MALI_PMM_STATE_H__ - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** - * @addtogroup pmmapi Power Management Module APIs - * - * @{ - * - * @defgroup pmmapi_state Power Management Module State - * - * @{ - */ - -/* Check that the subset is really a subset of cores */ -#define MALI_PMM_DEBUG_ASSERT_CORES_SUBSET( cores, subset ) \ - MALI_DEBUG_ASSERT( ((~(cores)) & (subset)) == 0 ) - - -/* Locking macros */ -#define MALI_PMM_LOCK(pmm) \ - _mali_osk_lock_wait( pmm->lock, _MALI_OSK_LOCKMODE_RW ) -#define MALI_PMM_UNLOCK(pmm) \ - _mali_osk_lock_signal( pmm->lock, _MALI_OSK_LOCKMODE_RW ) -#define MALI_PMM_LOCK_TERM(pmm) \ - _mali_osk_lock_term( pmm->lock ) - -/* Notification type for messages */ -#define MALI_PMM_NOTIFICATION_TYPE 0 - -/** @brief Status of the PMM state machine - */ -typedef enum mali_pmm_status_tag -{ - MALI_PMM_STATUS_IDLE, /**< PMM is waiting next event */ - MALI_PMM_STATUS_POLICY_POWER_DOWN, /**< Policy initiated power down */ - MALI_PMM_STATUS_POLICY_POWER_UP, /**< Policy initiated power down */ - MALI_PMM_STATUS_OS_WAITING, /**< PMM is waiting for OS power up */ - MALI_PMM_STATUS_OS_POWER_DOWN, /**< OS initiated power down */ - MALI_PMM_STATUS_DVFS_PAUSE, /**< PMM DVFS Status Pause */ - MALI_PMM_STATUS_OS_POWER_UP, /**< OS initiated power up */ - MALI_PMM_STATUS_OFF, /**< PMM is not active */ -} mali_pmm_status; - - -/** @brief Internal state of the PMM - */ -typedef struct _mali_pmm_internal_state -{ - mali_pmm_status status; /**< PMM state machine */ - mali_pmm_policy policy; /**< PMM policy */ - mali_bool check_policy; /**< PMM policy needs checking */ - mali_pmm_state state; /**< PMM state */ - mali_pmm_core_mask cores_registered; /**< Bitmask of cores registered */ - mali_pmm_core_mask cores_powered; /**< Bitmask of cores powered up */ - mali_pmm_core_mask cores_idle; /**< Bitmask of cores idle */ - mali_pmm_core_mask cores_pend_down; /**< Bitmask of cores pending power down */ - mali_pmm_core_mask cores_pend_up; /**< Bitmask of cores pending power up */ - mali_pmm_core_mask cores_ack_down; /**< Bitmask of cores acknowledged power down */ - mali_pmm_core_mask cores_ack_up; /**< Bitmask of cores acknowledged power up */ - - _mali_osk_notification_queue_t *queue; /**< PMM event queue */ - _mali_osk_notification_queue_t *iqueue; /**< PMM internal event queue */ - _mali_osk_irq_t *irq; /**< PMM irq handler */ - _mali_osk_lock_t *lock; /**< PMM lock */ - - mali_pmm_message_data os_data; /**< OS data sent via the OS events */ - - mali_bool pmu_initialized; /**< PMU initialized */ - - _mali_osk_atomic_t messages_queued; /**< PMM event messages queued */ - u32 waiting; /**< PMM waiting events - due to busy */ - u32 no_events; /**< PMM called to process when no events */ - - u32 missed; /**< PMM missed events due to OOM */ - mali_bool fatal_power_err; /**< PMM has had a fatal power error? */ - u32 is_dvfs_active; /**< PMM DVFS activity */ - -#if MALI_STATE_TRACKING - mali_pmm_status mali_last_pmm_status; /**< The previous PMM status */ - mali_pmm_event_id mali_new_event_status;/**< The type of the last PMM event */ - mali_bool mali_pmm_lock_acquired; /**< Is the PMM lock held somewhere or not */ -#endif - -#if (MALI_PMM_TRACE || MALI_STATE_TRACKING) - u32 messages_sent; /**< Total event messages sent */ - u32 messages_received; /**< Total event messages received */ - u32 imessages_sent; /**< Total event internal messages sent */ - u32 imessages_received; /**< Total event internal messages received */ -#endif -} _mali_pmm_internal_state_t; - -/** @brief Sets that a policy needs a check before processing events - * - * A timer or something has expired that needs dealing with - */ -void malipmm_set_policy_check(void); - -/** @brief Update the PMM externally viewable state depending on the current PMM internal state - * - * @param pmm internal PMM state - * @return MALI_TRUE if the timeout is valid, else MALI_FALSE - */ -void pmm_update_system_state( _mali_pmm_internal_state_t *pmm ); - -/** @brief Returns the core mask from the event data - if applicable - * - * @param pmm internal PMM state - * @param event event message to get the core mask from - * @return mask of cores that is relevant to this event message - */ -mali_pmm_core_mask pmm_cores_from_event_data( _mali_pmm_internal_state_t *pmm, mali_pmm_message_t *event ); - -/** @brief Sort out which cores need to be powered up from the given core mask - * - * All cores that can be powered up will be put into a pending state - * - * @param pmm internal PMM state - * @param cores mask of cores to check if they need to be powered up - * @return mask of cores that need to be powered up, this can be 0 if all cores - * are powered up already - */ -mali_pmm_core_mask pmm_cores_to_power_up( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ); - -/** @brief Sort out which cores need to be powered down from the given core mask - * - * All cores that can be powered down will be put into a pending state. If they - * can be powered down immediately they will also be acknowledged that they can be - * powered down. If the immediate_only flag is set, then only those cores that - * can be acknowledged for power down will be put into a pending state. - * - * @param pmm internal PMM state - * @param cores mask of cores to check if they need to be powered down - * @param immediate_only MALI_TRUE means that only cores that can power down now will - * be put into a pending state - * @return mask of cores that need to be powered down, this can be 0 if all cores - * are powered down already - */ -mali_pmm_core_mask pmm_cores_to_power_down( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores, mali_bool immediate_only ); - -/** @brief Cancel an invokation to power down (pmm_invoke_power_down) - * - * @param pmm internal PMM state - */ -void pmm_power_down_cancel( _mali_pmm_internal_state_t *pmm ); - -/** @brief Check if a call to invoke power down should succeed, or fail - * - * This will report MALI_FALSE if some of the cores are still active and need - * to acknowledge that they are ready to power down - * - * @param pmm internal PMM state - * @return MALI_TRUE if the pending cores to power down have acknowledged they - * can power down, else MALI_FALSE - */ -mali_bool pmm_power_down_okay( _mali_pmm_internal_state_t *pmm ); - -/** @brief Try to make all the pending cores power down - * - * If all the pending cores have acknowledged they can power down, this will call the - * PMU power down function to turn them off - * - * @param pmm internal PMM state - * @return MALI_TRUE if the pending cores have been powered down, else MALI_FALSE - */ -mali_bool pmm_invoke_power_down( _mali_pmm_internal_state_t *pmm, mali_power_mode power_mode ); - -/** @brief Check if all the pending cores to power up have done so - * - * This will report MALI_FALSE if some of the cores are still powered off - * and have not acknowledged that they have powered up - * - * @param pmm internal PMM state - * @return MALI_TRUE if the pending cores to power up have acknowledged they - * are now powered up, else MALI_FALSE - */ -mali_bool pmm_power_up_okay( _mali_pmm_internal_state_t *pmm ); - -/** @brief Try to make all the pending cores power up - * - * If all the pending cores have acknowledged they have powered up, this will - * make the cores start processing jobs again, else this will call the PMU - * power up function to turn them on, and the PMM is then expected to wait for an - * interrupt to acknowledge the power up - * - * @param pmm internal PMM state - * @return MALI_TRUE if the pending cores have been powered up, else MALI_FALSE - */ -mali_bool pmm_invoke_power_up( _mali_pmm_internal_state_t *pmm ); - -/** @brief Set the cores that are now active in the system - * - * Updates which cores are active and returns which cores are still idle - * - * @param pmm internal PMM state - * @param cores mask of cores to set to active - * @return mask of all the cores that are idle - */ -mali_pmm_core_mask pmm_cores_set_active( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ); - -/** @brief Set the cores that are now idle in the system - * - * Updates which cores are idle and returns which cores are still idle - * - * @param pmm internal PMM state - * @param cores mask of cores to set to idle - * @return mask of all the cores that are idle - */ -mali_pmm_core_mask pmm_cores_set_idle( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ); - -/** @brief Set the cores that have acknowledged a pending power down - * - * Updates which cores have acknowledged the pending power down and are now ready - * to be turned off - * - * @param pmm internal PMM state - * @param cores mask of cores that have acknowledged the pending power down - * @return mask of all the cores that have acknowledged the power down - */ -mali_pmm_core_mask pmm_cores_set_down_ack( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ); - -/** @brief Set the cores that have acknowledged a pending power up - * - * Updates which cores have acknowledged the pending power up and are now - * fully powered and ready to run jobs - * - * @param pmm internal PMM state - * @param cores mask of cores that have acknowledged the pending power up - * @return mask of all the cores that have acknowledged the power up - */ -mali_pmm_core_mask pmm_cores_set_up_ack( _mali_pmm_internal_state_t *pmm, mali_pmm_core_mask cores ); - - -/** @brief Tries to reset the PMM and PMU hardware to a known state after any fatal issues - * - * This will try and make all the cores powered up and reset the PMM state - * to its initial state after core registration - all cores powered but not - * pending or active. - * All events in the event queues will be thrown away. - * - * @note: Any pending power down will be cancelled including the OS calling for power down - */ -void pmm_fatal_reset( _mali_pmm_internal_state_t *pmm ); - -/** @brief Save the OS specific data for an OS power up/down event - * - * @param pmm internal PMM state - * @param data OS specific event data - */ -void pmm_save_os_event_data(_mali_pmm_internal_state_t *pmm, mali_pmm_message_data data); - -/** @brief Retrieve the OS specific data for an OS power up/down event - * - * This will clear the stored OS data, as well as return it. - * - * @param pmm internal PMM state - * @return OS specific event data that was saved previously - */ -mali_pmm_message_data pmm_retrieve_os_event_data(_mali_pmm_internal_state_t *pmm); - - -/** @brief Get a human readable name for the cores in a core mask - * - * @param core the core mask - * @return string containing a name relating to the given core mask - */ -const char *pmm_trace_get_core_name( mali_pmm_core_mask core ); - -/** @} */ /* End group pmmapi_state */ -/** @} */ /* End group pmmapi */ - -#ifdef __cplusplus -} -#endif - -#endif /* __MALI_PMM_STATE_H__ */ diff --git a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_system.h b/drivers/media/video/samsung/mali/common/pmm/mali_pmm_system.h deleted file mode 100644 index eccd35b..0000000 --- a/drivers/media/video/samsung/mali/common/pmm/mali_pmm_system.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __MALI_PMM_SYSTEM_H__ -#define __MALI_PMM_SYSTEM_H__ - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** - * @addtogroup pmmapi Power Management Module APIs - * - * @{ - * - * @defgroup pmmapi_system Power Management Module System Functions - * - * @{ - */ - -extern struct mali_kernel_subsystem mali_subsystem_pmm; - -/** @brief Register a core with the PMM, which will power up - * the core - * - * @param core the core to register with the PMM - * @return error if the core cannot be powered up - */ -_mali_osk_errcode_t malipmm_core_register( mali_pmm_core_id core ); - -/** @brief Unregister a core with the PMM - * - * @param core the core to unregister with the PMM - */ -void malipmm_core_unregister( mali_pmm_core_id core ); - -/** @brief Acknowledge that a power down is okay to happen - * - * A core should not be running a job, or be in the idle queue when this - * is called. - * - * @param core the core that can now be powered down - */ -void malipmm_core_power_down_okay( mali_pmm_core_id core ); - -/** @} */ /* End group pmmapi_system */ -/** @} */ /* End group pmmapi */ - -#ifdef __cplusplus -} -#endif - -#endif /* __MALI_PMM_H__ */ diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_gp.h b/drivers/media/video/samsung/mali/include/linux/mali/mali_utgard.h index efd3b43..7c78947 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_gp.h +++ b/drivers/media/video/samsung/mali/include/linux/mali/mali_utgard.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010, 2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -8,14 +8,21 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __MALI_KERNEL_GP2_H__ -#define __MALI_KERNEL_GP2_H__ +#ifndef __MALI_UTGARD_H__ +#define __MALI_UTGARD_H__ -extern struct mali_kernel_subsystem mali_subsystem_gp2; +/** @brief MALI GPU power down using MALI in-built PMU + * + * called to power down all cores + */ +int mali_pmu_powerdown(void); + + +/** @brief MALI GPU power up using MALI in-built PMU + * + * called to power up all cores + */ +int mali_pmu_powerup(void); -#if USING_MALI_PMM -_mali_osk_errcode_t maligp_signal_power_up( mali_bool queue_only ); -_mali_osk_errcode_t maligp_signal_power_down( mali_bool immediate_only ); -#endif +#endif /* __MALI_UTGARD_H__ */ -#endif /* __MALI_KERNEL_GP2_H__ */ diff --git a/drivers/media/video/samsung/mali/include/linux/mali/mali_utgard_counters.h b/drivers/media/video/samsung/mali/include/linux/mali/mali_utgard_counters.h new file mode 100644 index 0000000..40822f7 --- /dev/null +++ b/drivers/media/video/samsung/mali/include/linux/mali/mali_utgard_counters.h @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _MALI_UTGARD_COUNTERS_H_ +#define _MALI_UTGARD_COUNTERS_H_ + +typedef struct +{ + void *unused; +} mali_cinstr_counter_info; + +typedef enum +{ + MALI_CINSTR_COUNTER_SOURCE_EGL = 0, + MALI_CINSTR_COUNTER_SOURCE_OPENGLES = 1000, + MALI_CINSTR_COUNTER_SOURCE_OPENVG = 2000, + MALI_CINSTR_COUNTER_SOURCE_GP = 3000, + MALI_CINSTR_COUNTER_SOURCE_PP = 4000, +} cinstr_counter_source; + +#define MALI_CINSTR_EGL_FIRST_COUNTER MALI_CINSTR_COUNTER_SOURCE_EGL +#define MALI_CINSTR_EGL_LAST_COUNTER (MALI_CINSTR_COUNTER_SOURCE_EGL + 999) + +#define MALI_CINSTR_GLES_FIRST_COUNTER MALI_CINSTR_COUNTER_SOURCE_OPENGLES +#define MALI_CINSTR_GLES_LAST_COUNTER (MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 999) + +#define MALI_CINSTR_VG_FIRST_COUNTER MALI_CINSTR_COUNTER_SOURCE_OPENVG +#define MALI_CINSTR_VG_LAST_COUNTER (MALI_CINSTR_COUNTER_SOURCE_OPENVG + 999) + +#define MALI_CINSTR_GP_FIRST_COUNTER MALI_CINSTR_COUNTER_SOURCE_GP +#define MALI_CINSTR_GP_LAST_COUNTER (MALI_CINSTR_COUNTER_SOURCE_GP + 999) + +#define MALI_CINSTR_PP_FIRST_COUNTER MALI_CINSTR_COUNTER_SOURCE_PP +#define MALI_CINSTR_PP_LAST_COUNTER (MALI_CINSTR_COUNTER_SOURCE_PP + 999) + + +typedef enum +{ + /* EGL counters */ + + MALI_CINSTR_EGL_BLIT_TIME = MALI_CINSTR_COUNTER_SOURCE_EGL + 0, + + /* Last counter in the EGL set */ + MALI_CINSTR_EGL_MAX_COUNTER = MALI_CINSTR_COUNTER_SOURCE_EGL + 1, + + /* GLES counters */ + + MALI_CINSTR_GLES_DRAW_ELEMENTS_CALLS = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 0, + MALI_CINSTR_GLES_DRAW_ELEMENTS_NUM_INDICES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 1, + MALI_CINSTR_GLES_DRAW_ELEMENTS_NUM_TRANSFORMED = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 2, + MALI_CINSTR_GLES_DRAW_ARRAYS_CALLS = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 3, + MALI_CINSTR_GLES_DRAW_ARRAYS_NUM_TRANSFORMED = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 4, + MALI_CINSTR_GLES_DRAW_POINTS = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 5, + MALI_CINSTR_GLES_DRAW_LINES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 6, + MALI_CINSTR_GLES_DRAW_LINE_LOOP = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 7, + MALI_CINSTR_GLES_DRAW_LINE_STRIP = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 8, + MALI_CINSTR_GLES_DRAW_TRIANGLES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 9, + MALI_CINSTR_GLES_DRAW_TRIANGLE_STRIP = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 10, + MALI_CINSTR_GLES_DRAW_TRIANGLE_FAN = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 11, + MALI_CINSTR_GLES_NON_VBO_DATA_COPY_TIME = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 12, + MALI_CINSTR_GLES_UNIFORM_BYTES_COPIED_TO_MALI = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 13, + MALI_CINSTR_GLES_UPLOAD_TEXTURE_TIME = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 14, + MALI_CINSTR_GLES_UPLOAD_VBO_TIME = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 15, + MALI_CINSTR_GLES_NUM_FLUSHES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 16, + MALI_CINSTR_GLES_NUM_VSHADERS_GENERATED = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 17, + MALI_CINSTR_GLES_NUM_FSHADERS_GENERATED = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 18, + MALI_CINSTR_GLES_VSHADER_GEN_TIME = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 19, + MALI_CINSTR_GLES_FSHADER_GEN_TIME = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 20, + MALI_CINSTR_GLES_INPUT_TRIANGLES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 21, + MALI_CINSTR_GLES_VXCACHE_HIT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 22, + MALI_CINSTR_GLES_VXCACHE_MISS = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 23, + MALI_CINSTR_GLES_VXCACHE_COLLISION = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 24, + MALI_CINSTR_GLES_CULLED_TRIANGLES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 25, + MALI_CINSTR_GLES_CULLED_LINES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 26, + MALI_CINSTR_GLES_BACKFACE_TRIANGLES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 27, + MALI_CINSTR_GLES_GBCLIP_TRIANGLES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 28, + MALI_CINSTR_GLES_GBCLIP_LINES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 29, + MALI_CINSTR_GLES_TRIANGLES_DRAWN = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 30, + MALI_CINSTR_GLES_DRAWCALL_TIME = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 31, + MALI_CINSTR_GLES_TRIANGLES_COUNT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 32, + MALI_CINSTR_GLES_INDEPENDENT_TRIANGLES_COUNT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 33, + MALI_CINSTR_GLES_STRIP_TRIANGLES_COUNT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 34, + MALI_CINSTR_GLES_FAN_TRIANGLES_COUNT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 35, + MALI_CINSTR_GLES_LINES_COUNT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 36, + MALI_CINSTR_GLES_INDEPENDENT_LINES_COUNT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 37, + MALI_CINSTR_GLES_STRIP_LINES_COUNT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 38, + MALI_CINSTR_GLES_LOOP_LINES_COUNT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 39, + MALI_CINSTR_GLES_POINTS_COUNT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 40, + + /* Last counter in the GLES set */ + MALI_CINSTR_GLES_MAX_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 41, + + /* OpenVG counters */ + + MALI_CINSTR_VG_MASK_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 0, + MALI_CINSTR_VG_CLEAR_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 1, + MALI_CINSTR_VG_APPEND_PATH_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 2, + MALI_CINSTR_VG_APPEND_PATH_DATA_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 3, + MALI_CINSTR_VG_MODIFY_PATH_COORDS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 4, + MALI_CINSTR_VG_TRANSFORM_PATH_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 5, + MALI_CINSTR_VG_INTERPOLATE_PATH_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 6, + MALI_CINSTR_VG_PATH_LENGTH_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 7, + MALI_CINSTR_VG_POINT_ALONG_PATH_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 8, + MALI_CINSTR_VG_PATH_BOUNDS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 9, + MALI_CINSTR_VG_PATH_TRANSFORMED_BOUNDS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 10, + MALI_CINSTR_VG_DRAW_PATH_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 11, + MALI_CINSTR_VG_CLEAR_IMAGE_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 12, + MALI_CINSTR_VG_IMAGE_SUB_DATA_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 13, + MALI_CINSTR_VG_GET_IMAGE_SUB_DATA_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 14, + MALI_CINSTR_VG_COPY_IMAGE_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 15, + MALI_CINSTR_VG_DRAW_IMAGE_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 16, + MALI_CINSTR_VG_SET_PIXELS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 17, + MALI_CINSTR_VG_WRITE_PIXELS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 18, + MALI_CINSTR_VG_GET_PIXELS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 19, + MALI_CINSTR_VG_READ_PIXELS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 20, + MALI_CINSTR_VG_COPY_PIXELS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 21, + MALI_CINSTR_VG_COLOR_MATRIX_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 22, + MALI_CINSTR_VG_CONVOLVE_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 23, + MALI_CINSTR_VG_SEPARABLE_CONVOLVE_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 24, + MALI_CINSTR_VG_GAUSSIAN_BLUR_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 25, + MALI_CINSTR_VG_LOOKUP_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 26, + MALI_CINSTR_VG_LOOKUP_SINGLE_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 27, + MALI_CINSTR_VG_CONTEXT_CREATE_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 28, + MALI_CINSTR_VG_STROKED_CUBICS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 29, + MALI_CINSTR_VG_STROKED_QUADS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 30, + MALI_CINSTR_VG_STROKED_ARCS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 31, + MALI_CINSTR_VG_STROKED_LINES_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 32, + MALI_CINSTR_VG_FILLED_CUBICS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 33, + MALI_CINSTR_VG_FILLED_QUADS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 34, + MALI_CINSTR_VG_FILLED_ARCS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 35, + MALI_CINSTR_VG_FILLED_LINES_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 36, + MALI_CINSTR_VG_DRAW_PATH_CALLS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 37, + MALI_CINSTR_VG_TRIANGLES_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 38, + MALI_CINSTR_VG_VERTICES_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 39, + MALI_CINSTR_VG_INDICES_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 40, + MALI_CINSTR_VG_FILLED_PATHS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 41, + MALI_CINSTR_VG_STROKED_PATHS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 42, + MALI_CINSTR_VG_FILL_EXTRACT_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 43, + MALI_CINSTR_VG_DRAW_FILLED_PATH_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 44, + MALI_CINSTR_VG_STROKE_EXTRACT_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 45, + MALI_CINSTR_VG_DRAW_STROKED_PATH_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 46, + MALI_CINSTR_VG_DRAW_PAINT_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 47, + MALI_CINSTR_VG_DATA_STRUCTURES_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 48, + MALI_CINSTR_VG_MEM_PATH_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 49, + MALI_CINSTR_VG_RSW_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 50, + + /* Last counter in the VG set */ + MALI_CINSTR_VG_MAX_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 51, + + /* Mali GP counters */ + + MALI_CINSTR_GP_DEPRECATED_0 = MALI_CINSTR_COUNTER_SOURCE_GP + 0, + MALI_CINSTR_GP_ACTIVE_CYCLES_GP = MALI_CINSTR_COUNTER_SOURCE_GP + 1, + MALI_CINSTR_GP_ACTIVE_CYCLES_VERTEX_SHADER = MALI_CINSTR_COUNTER_SOURCE_GP + 2, + MALI_CINSTR_GP_ACTIVE_CYCLES_VERTEX_STORER = MALI_CINSTR_COUNTER_SOURCE_GP + 3, + MALI_CINSTR_GP_ACTIVE_CYCLES_VERTEX_LOADER = MALI_CINSTR_COUNTER_SOURCE_GP + 4, + MALI_CINSTR_GP_CYCLES_VERTEX_LOADER_WAITING_FOR_VERTEX_SHADER = MALI_CINSTR_COUNTER_SOURCE_GP + 5, + MALI_CINSTR_GP_NUMBER_OF_WORDS_READ = MALI_CINSTR_COUNTER_SOURCE_GP + 6, + MALI_CINSTR_GP_NUMBER_OF_WORDS_WRITTEN = MALI_CINSTR_COUNTER_SOURCE_GP + 7, + MALI_CINSTR_GP_NUMBER_OF_READ_BURSTS = MALI_CINSTR_COUNTER_SOURCE_GP + 8, + MALI_CINSTR_GP_NUMBER_OF_WRITE_BURSTS = MALI_CINSTR_COUNTER_SOURCE_GP + 9, + MALI_CINSTR_GP_NUMBER_OF_VERTICES_PROCESSED = MALI_CINSTR_COUNTER_SOURCE_GP + 10, + MALI_CINSTR_GP_NUMBER_OF_VERTICES_FETCHED = MALI_CINSTR_COUNTER_SOURCE_GP + 11, + MALI_CINSTR_GP_NUMBER_OF_PRIMITIVES_FETCHED = MALI_CINSTR_COUNTER_SOURCE_GP + 12, + MALI_CINSTR_GP_RESERVED_13 = MALI_CINSTR_COUNTER_SOURCE_GP + 13, + MALI_CINSTR_GP_NUMBER_OF_BACKFACE_CULLINGS_DONE = MALI_CINSTR_COUNTER_SOURCE_GP + 14, + MALI_CINSTR_GP_NUMBER_OF_COMMANDS_WRITTEN_TO_TILES = MALI_CINSTR_COUNTER_SOURCE_GP + 15, + MALI_CINSTR_GP_NUMBER_OF_MEMORY_BLOCKS_ALLOCATED = MALI_CINSTR_COUNTER_SOURCE_GP + 16, + MALI_CINSTR_GP_RESERVED_17 = MALI_CINSTR_COUNTER_SOURCE_GP + 17, + MALI_CINSTR_GP_RESERVED_18 = MALI_CINSTR_COUNTER_SOURCE_GP + 18, + MALI_CINSTR_GP_NUMBER_OF_VERTEX_LOADER_CACHE_MISSES = MALI_CINSTR_COUNTER_SOURCE_GP + 19, + MALI_CINSTR_GP_RESERVED_20 = MALI_CINSTR_COUNTER_SOURCE_GP + 20, + MALI_CINSTR_GP_RESERVED_21 = MALI_CINSTR_COUNTER_SOURCE_GP + 21, + MALI_CINSTR_GP_ACTIVE_CYCLES_VERTEX_SHADER_COMMAND_PROCESSOR = MALI_CINSTR_COUNTER_SOURCE_GP + 22, + MALI_CINSTR_GP_ACTIVE_CYCLES_PLBU_COMMAND_PROCESSOR = MALI_CINSTR_COUNTER_SOURCE_GP + 23, + MALI_CINSTR_GP_ACTIVE_CYCLES_PLBU_LIST_WRITER = MALI_CINSTR_COUNTER_SOURCE_GP + 24, + MALI_CINSTR_GP_ACTIVE_CYCLES_THROUGH_THE_PREPARE_LIST_COMMANDS = MALI_CINSTR_COUNTER_SOURCE_GP + 25, + MALI_CINSTR_GP_RESERVED_26 = MALI_CINSTR_COUNTER_SOURCE_GP + 26, + MALI_CINSTR_GP_ACTIVE_CYCLES_PRIMITIVE_ASSEMBLY = MALI_CINSTR_COUNTER_SOURCE_GP + 27, + MALI_CINSTR_GP_ACTIVE_CYCLES_PLBU_VERTEX_FETCHER = MALI_CINSTR_COUNTER_SOURCE_GP + 28, + MALI_CINSTR_GP_RESERVED_29 = MALI_CINSTR_COUNTER_SOURCE_GP + 29, + MALI_CINSTR_GP_ACTIVE_CYCLES_BOUNDINGBOX_AND_COMMAND_GENERATOR = MALI_CINSTR_COUNTER_SOURCE_GP + 30, + MALI_CINSTR_GP_RESERVED_31 = MALI_CINSTR_COUNTER_SOURCE_GP + 31, + MALI_CINSTR_GP_ACTIVE_CYCLES_SCISSOR_TILE_ITERATOR = MALI_CINSTR_COUNTER_SOURCE_GP + 32, + MALI_CINSTR_GP_ACTIVE_CYCLES_PLBU_TILE_ITERATOR = MALI_CINSTR_COUNTER_SOURCE_GP + 33, + MALI_CINSTR_GP_JOB_COUNT = MALI_CINSTR_COUNTER_SOURCE_GP + 900, + + /* Mali PP counters */ + + MALI_CINSTR_PP_ACTIVE_CLOCK_CYCLES_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 0, + MALI_CINSTR_PP_TOTAL_CLOCK_CYCLES_COUNT_REMOVED = MALI_CINSTR_COUNTER_SOURCE_PP + 1, + MALI_CINSTR_PP_TOTAL_BUS_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 2, + MALI_CINSTR_PP_TOTAL_BUS_WRITES = MALI_CINSTR_COUNTER_SOURCE_PP + 3, + MALI_CINSTR_PP_BUS_READ_REQUEST_CYCLES_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 4, + MALI_CINSTR_PP_BUS_WRITE_REQUEST_CYCLES_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 5, + MALI_CINSTR_PP_BUS_READ_TRANSACTIONS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 6, + MALI_CINSTR_PP_BUS_WRITE_TRANSACTIONS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 7, + MALI_CINSTR_PP_RESERVED_08 = MALI_CINSTR_COUNTER_SOURCE_PP + 8, + MALI_CINSTR_PP_TILE_WRITEBACK_WRITES = MALI_CINSTR_COUNTER_SOURCE_PP + 9, + MALI_CINSTR_PP_STORE_UNIT_WRITES = MALI_CINSTR_COUNTER_SOURCE_PP + 10, + MALI_CINSTR_PP_RESERVED_11 = MALI_CINSTR_COUNTER_SOURCE_PP + 11, + MALI_CINSTR_PP_PALETTE_CACHE_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 12, + MALI_CINSTR_PP_TEXTURE_CACHE_UNCOMPRESSED_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 13, + MALI_CINSTR_PP_POLYGON_LIST_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 14, + MALI_CINSTR_PP_RSW_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 15, + MALI_CINSTR_PP_VERTEX_CACHE_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 16, + MALI_CINSTR_PP_UNIFORM_REMAPPING_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 17, + MALI_CINSTR_PP_PROGRAM_CACHE_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 19, + MALI_CINSTR_PP_VARYING_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 19, + MALI_CINSTR_PP_TEXTURE_DESCRIPTORS_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 20, + MALI_CINSTR_PP_TEXTURE_DESCRIPTORS_REMAPPING_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 21, + MALI_CINSTR_PP_TEXTURE_CACHE_COMPRESSED_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 22, + MALI_CINSTR_PP_LOAD_UNIT_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 23, + MALI_CINSTR_PP_POLYGON_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 24, + MALI_CINSTR_PP_PIXEL_RECTANGLE_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 25, + MALI_CINSTR_PP_LINES_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 26, + MALI_CINSTR_PP_POINTS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 27, + MALI_CINSTR_PP_STALL_CYCLES_POLYGON_LIST_READER = MALI_CINSTR_COUNTER_SOURCE_PP + 28, + MALI_CINSTR_PP_STALL_CYCLES_TRIANGLE_SETUP = MALI_CINSTR_COUNTER_SOURCE_PP + 29, + MALI_CINSTR_PP_QUAD_RASTERIZED_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 30, + MALI_CINSTR_PP_FRAGMENT_RASTERIZED_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 31, + MALI_CINSTR_PP_FRAGMENT_REJECTED_FRAGMENT_KILL_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 32, + MALI_CINSTR_PP_FRAGMENT_REJECTED_FWD_FRAGMENT_KILL_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 33, + MALI_CINSTR_PP_FRAGMENT_PASSED_ZSTENCIL_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 34, + MALI_CINSTR_PP_PATCHES_REJECTED_EARLY_Z_STENCIL_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 35, + MALI_CINSTR_PP_PATCHES_EVALUATED = MALI_CINSTR_COUNTER_SOURCE_PP + 36, + MALI_CINSTR_PP_INSTRUCTION_COMPLETED_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 37, + MALI_CINSTR_PP_INSTRUCTION_FAILED_RENDEZVOUS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 38, + MALI_CINSTR_PP_INSTRUCTION_FAILED_VARYING_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 39, + MALI_CINSTR_PP_INSTRUCTION_FAILED_TEXTURE_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 40, + MALI_CINSTR_PP_INSTRUCTION_FAILED_LOAD_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 41, + MALI_CINSTR_PP_INSTRUCTION_FAILED_TILE_READ_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 42, + MALI_CINSTR_PP_INSTRUCTION_FAILED_STORE_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 43, + MALI_CINSTR_PP_RENDEZVOUS_BREAKAGE_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 44, + MALI_CINSTR_PP_PIPELINE_BUBBLES_CYCLE_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 45, + MALI_CINSTR_PP_TEXTURE_MAPPER_MULTIPASS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 46, + MALI_CINSTR_PP_TEXTURE_MAPPER_CYCLE_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 47, + MALI_CINSTR_PP_VERTEX_CACHE_HIT_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 48, + MALI_CINSTR_PP_VERTEX_CACHE_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 49, + MALI_CINSTR_PP_VARYING_CACHE_HIT_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 50, + MALI_CINSTR_PP_VARYING_CACHE_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 51, + MALI_CINSTR_PP_VARYING_CACHE_CONFLICT_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 52, + MALI_CINSTR_PP_TEXTURE_CACHE_HIT_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 53, + MALI_CINSTR_PP_TEXTURE_CACHE_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 54, + MALI_CINSTR_PP_TEXTURE_CACHE_CONFLICT_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 55, + MALI_CINSTR_PP_PALETTE_CACHE_HIT_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 56, /* Mali 200 only */ + MALI_CINSTR_PP_PALETTE_CACHE_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 57, /* Mali 200 only */ + MALI_CINSTR_PP_COMPRESSED_TEXTURE_CACHE_HIT_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 56, /* Mali 400 class only */ + MALI_CINSTR_PP_COMPRESSED_TEXTURE_CACHE_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 57, /* Mali 400 class only */ + MALI_CINSTR_PP_LOAD_STORE_CACHE_HIT_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 58, + MALI_CINSTR_PP_LOAD_STORE_CACHE_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 59, + MALI_CINSTR_PP_PROGRAM_CACHE_HIT_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 60, + MALI_CINSTR_PP_PROGRAM_CACHE_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 61, + MALI_CINSTR_PP_JOB_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 900, +} cinstr_counters_m200_t; + +#endif /*_MALI_UTGARD_COUNTERS_H_*/ diff --git a/drivers/media/video/samsung/mali/include/linux/mali/mali_utgard_ioctl.h b/drivers/media/video/samsung/mali/include/linux/mali/mali_utgard_ioctl.h new file mode 100644 index 0000000..31af4cf --- /dev/null +++ b/drivers/media/video/samsung/mali/include/linux/mali/mali_utgard_ioctl.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __MALI_UTGARD_IOCTL_H__ +#define __MALI_UTGARD_IOCTL_H__ + +#include <linux/types.h> +#include <linux/ioctl.h> +#include <linux/fs.h> /* file system operations */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @file mali_kernel_ioctl.h + * Interface to the Linux device driver. + * This file describes the interface needed to use the Linux device driver. + * Its interface is designed to used by the HAL implementation through a thin arch layer. + */ + +/** + * ioctl commands + */ + +#define MALI_IOC_BASE 0x82 +#define MALI_IOC_CORE_BASE (_MALI_UK_CORE_SUBSYSTEM + MALI_IOC_BASE) +#define MALI_IOC_MEMORY_BASE (_MALI_UK_MEMORY_SUBSYSTEM + MALI_IOC_BASE) +#define MALI_IOC_PP_BASE (_MALI_UK_PP_SUBSYSTEM + MALI_IOC_BASE) +#define MALI_IOC_GP_BASE (_MALI_UK_GP_SUBSYSTEM + MALI_IOC_BASE) +#define MALI_IOC_PROFILING_BASE (_MALI_UK_PROFILING_SUBSYSTEM + MALI_IOC_BASE) +#define MALI_IOC_VSYNC_BASE (_MALI_UK_VSYNC_SUBSYSTEM + MALI_IOC_BASE) + +#define MALI_IOC_GET_SYSTEM_INFO_SIZE _IOR (MALI_IOC_CORE_BASE, _MALI_UK_GET_SYSTEM_INFO_SIZE, _mali_uk_get_system_info_s *) +#define MALI_IOC_GET_SYSTEM_INFO _IOR (MALI_IOC_CORE_BASE, _MALI_UK_GET_SYSTEM_INFO, _mali_uk_get_system_info_s *) +#define MALI_IOC_WAIT_FOR_NOTIFICATION _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_WAIT_FOR_NOTIFICATION, _mali_uk_wait_for_notification_s *) +#define MALI_IOC_GET_API_VERSION _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_GET_API_VERSION, _mali_uk_get_api_version_s *) +#define MALI_IOC_POST_NOTIFICATION _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_POST_NOTIFICATION, _mali_uk_post_notification_s *) +#define MALI_IOC_GET_USER_SETTING _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_GET_USER_SETTING, _mali_uk_get_user_setting_s *) +#define MALI_IOC_GET_USER_SETTINGS _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_GET_USER_SETTINGS, _mali_uk_get_user_settings_s *) +#define MALI_IOC_MEM_GET_BIG_BLOCK _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_GET_BIG_BLOCK, void *) +#define MALI_IOC_MEM_FREE_BIG_BLOCK _IOW (MALI_IOC_MEMORY_BASE, _MALI_UK_FREE_BIG_BLOCK, void *) +#define MALI_IOC_MEM_INIT _IOR (MALI_IOC_MEMORY_BASE, _MALI_UK_INIT_MEM, _mali_uk_init_mem_s *) +#define MALI_IOC_MEM_TERM _IOW (MALI_IOC_MEMORY_BASE, _MALI_UK_TERM_MEM, _mali_uk_term_mem_s *) +#define MALI_IOC_MEM_MAP_EXT _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_MAP_EXT_MEM, _mali_uk_map_external_mem_s *) +#define MALI_IOC_MEM_UNMAP_EXT _IOW (MALI_IOC_MEMORY_BASE, _MALI_UK_UNMAP_EXT_MEM, _mali_uk_unmap_external_mem_s *) +#define MALI_IOC_MEM_QUERY_MMU_PAGE_TABLE_DUMP_SIZE _IOR (MALI_IOC_MEMORY_BASE, _MALI_UK_QUERY_MMU_PAGE_TABLE_DUMP_SIZE, _mali_uk_query_mmu_page_table_dump_size_s *) +#define MALI_IOC_MEM_DUMP_MMU_PAGE_TABLE _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_DUMP_MMU_PAGE_TABLE, _mali_uk_dump_mmu_page_table_s *) +#define MALI_IOC_MEM_ATTACH_UMP _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_ATTACH_UMP_MEM, _mali_uk_attach_ump_mem_s *) +#define MALI_IOC_MEM_RELEASE_UMP _IOW(MALI_IOC_MEMORY_BASE, _MALI_UK_RELEASE_UMP_MEM, _mali_uk_release_ump_mem_s *) +#define MALI_IOC_PP_START_JOB _IOWR(MALI_IOC_PP_BASE, _MALI_UK_PP_START_JOB, _mali_uk_pp_start_job_s *) +#define MALI_IOC_PP_NUMBER_OF_CORES_GET _IOR (MALI_IOC_PP_BASE, _MALI_UK_GET_PP_NUMBER_OF_CORES, _mali_uk_get_pp_number_of_cores_s *) +#define MALI_IOC_PP_CORE_VERSION_GET _IOR (MALI_IOC_PP_BASE, _MALI_UK_GET_PP_CORE_VERSION, _mali_uk_get_pp_core_version_s * ) +#define MALI_IOC_PP_DISABLE_WB _IOW (MALI_IOC_PP_BASE, _MALI_UK_PP_DISABLE_WB, _mali_uk_pp_disable_wb_s * ) +#define MALI_IOC_GP2_START_JOB _IOWR(MALI_IOC_GP_BASE, _MALI_UK_GP_START_JOB, _mali_uk_gp_start_job_s *) +#define MALI_IOC_GP2_NUMBER_OF_CORES_GET _IOR (MALI_IOC_GP_BASE, _MALI_UK_GET_GP_NUMBER_OF_CORES, _mali_uk_get_gp_number_of_cores_s *) +#define MALI_IOC_GP2_CORE_VERSION_GET _IOR (MALI_IOC_GP_BASE, _MALI_UK_GET_GP_CORE_VERSION, _mali_uk_get_gp_core_version_s *) +#define MALI_IOC_GP2_SUSPEND_RESPONSE _IOW (MALI_IOC_GP_BASE, _MALI_UK_GP_SUSPEND_RESPONSE,_mali_uk_gp_suspend_response_s *) +#define MALI_IOC_PROFILING_START _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_START, _mali_uk_profiling_start_s *) +#define MALI_IOC_PROFILING_ADD_EVENT _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_ADD_EVENT, _mali_uk_profiling_add_event_s*) +#define MALI_IOC_PROFILING_STOP _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_STOP, _mali_uk_profiling_stop_s *) +#define MALI_IOC_PROFILING_GET_EVENT _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_GET_EVENT, _mali_uk_profiling_get_event_s *) +#define MALI_IOC_PROFILING_CLEAR _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_CLEAR, _mali_uk_profiling_clear_s *) +#define MALI_IOC_PROFILING_GET_CONFIG _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_GET_CONFIG, _mali_uk_get_user_settings_s *) +#define MALI_IOC_PROFILING_REPORT_SW_COUNTERS _IOW (MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_REPORT_SW_COUNTERS, _mali_uk_sw_counters_report_s *) +#define MALI_IOC_VSYNC_EVENT_REPORT _IOW (MALI_IOC_VSYNC_BASE, _MALI_UK_VSYNC_EVENT_REPORT, _mali_uk_vsync_event_report_s *) + +#ifdef __cplusplus +} +#endif + +#endif /* __MALI_UTGARD_IOCTL_H__ */ diff --git a/drivers/media/video/samsung/mali/include/linux/mali/mali_utgard_profiling_events.h b/drivers/media/video/samsung/mali/include/linux/mali/mali_utgard_profiling_events.h new file mode 100644 index 0000000..129526f --- /dev/null +++ b/drivers/media/video/samsung/mali/include/linux/mali/mali_utgard_profiling_events.h @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _MALI_UTGARD_PROFILING_EVENTS_H_ +#define _MALI_UTGARD_PROFILING_EVENTS_H_ + +/* + * The event ID is a 32 bit value consisting of different fields + * reserved, 4 bits, for future use + * event type, 4 bits, cinstr_profiling_event_type_t + * event channel, 8 bits, the source of the event. + * event data, 16 bit field, data depending on event type + */ + +/** + * Specifies what kind of event this is + */ +typedef enum +{ + MALI_PROFILING_EVENT_TYPE_SINGLE = 0 << 24, + MALI_PROFILING_EVENT_TYPE_START = 1 << 24, + MALI_PROFILING_EVENT_TYPE_STOP = 2 << 24, + MALI_PROFILING_EVENT_TYPE_SUSPEND = 3 << 24, + MALI_PROFILING_EVENT_TYPE_RESUME = 4 << 24, +} cinstr_profiling_event_type_t; + + +/** + * Secifies the channel/source of the event + */ +typedef enum +{ + MALI_PROFILING_EVENT_CHANNEL_SOFTWARE = 0 << 16, + MALI_PROFILING_EVENT_CHANNEL_GP0 = 1 << 16, + MALI_PROFILING_EVENT_CHANNEL_PP0 = 5 << 16, + MALI_PROFILING_EVENT_CHANNEL_PP1 = 6 << 16, + MALI_PROFILING_EVENT_CHANNEL_PP2 = 7 << 16, + MALI_PROFILING_EVENT_CHANNEL_PP3 = 8 << 16, + MALI_PROFILING_EVENT_CHANNEL_PP4 = 9 << 16, + MALI_PROFILING_EVENT_CHANNEL_PP5 = 10 << 16, + MALI_PROFILING_EVENT_CHANNEL_PP6 = 11 << 16, + MALI_PROFILING_EVENT_CHANNEL_PP7 = 12 << 16, + MALI_PROFILING_EVENT_CHANNEL_GPU = 21 << 16, +} cinstr_profiling_event_channel_t; + + +#define MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(num) (((MALI_PROFILING_EVENT_CHANNEL_GP0 >> 16) + (num)) << 16) +#define MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(num) (((MALI_PROFILING_EVENT_CHANNEL_PP0 >> 16) + (num)) << 16) + +/** + * These events are applicable when the type MALI_PROFILING_EVENT_TYPE_SINGLE is used from software channel + */ +typedef enum +{ + MALI_PROFILING_EVENT_REASON_SINGLE_SW_NONE = 0, + MALI_PROFILING_EVENT_REASON_SINGLE_SW_EGL_NEW_FRAME = 1, + MALI_PROFILING_EVENT_REASON_SINGLE_SW_FLUSH = 2, + MALI_PROFILING_EVENT_REASON_SINGLE_SW_EGL_SWAP_BUFFERS = 3, + MALI_PROFILING_EVENT_REASON_SINGLE_SW_FB_EVENT = 4, + MALI_PROFILING_EVENT_REASON_SINGLE_SW_ENTER_API_FUNC = 10, + MALI_PROFILING_EVENT_REASON_SINGLE_SW_LEAVE_API_FUNC = 11, + MALI_PROFILING_EVENT_REASON_SINGLE_SW_UMP_TRY_LOCK = 53, + MALI_PROFILING_EVENT_REASON_SINGLE_SW_UMP_LOCK = 54, + MALI_PROFILING_EVENT_REASON_SINGLE_SW_UMP_UNLOCK = 55, +} cinstr_profiling_event_reason_single_sw_t; + +/** + * These events are applicable when the type MALI_PROFILING_EVENT_TYPE_START/STOP is used from software channel + */ +typedef enum +{ + MALI_PROFILING_EVENT_REASON_START_STOP_SW_NONE = 0, + MALI_PROFILING_EVENT_REASON_START_STOP_MALI = 1, +} cinstr_profiling_event_reason_start_stop_sw_t; + +/** + * These events are applicable when the type MALI_PROFILING_EVENT_TYPE_SUSPEND/RESUME is used from software channel + */ +typedef enum +{ + MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_NONE = 0, + MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_PIPELINE_FULL = 1, + MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_VSYNC = 26, + MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_FB_IFRAME_WAIT = 27, + MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_FB_IFRAME_SYNC = 28, + MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_VG_WAIT_FILTER_CLEANUP = 29, + MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_VG_WAIT_TEXTURE = 30, + MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_GLES_WAIT_MIPLEVEL = 31, + MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_GLES_WAIT_READPIXELS = 32, + MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_EGL_WAIT_SWAP_IMMEDIATE= 33, + MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_ICS_QUEUE_BUFFER = 34, + MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_ICS_DEQUEUE_BUFFER = 35, +} cinstr_profiling_event_reason_suspend_resume_sw_t; + +/** + * These events are applicable when the type MALI_PROFILING_EVENT_TYPE_SINGLE is used from a HW channel (GPx+PPx) + */ +typedef enum +{ + MALI_PROFILING_EVENT_REASON_SINGLE_HW_NONE = 0, + MALI_PROFILING_EVENT_REASON_SINGLE_HW_INTERRUPT = 1, + MALI_PROFILING_EVENT_REASON_SINGLE_HW_FLUSH = 2, +} cinstr_profiling_event_reason_single_hw_t; + +/** + * These events are applicable when the type MALI_PROFILING_EVENT_TYPE_SINGLE is used from the GPU channel + */ +typedef enum +{ + MALI_PROFILING_EVENT_REASON_SINGLE_GPU_NONE = 0, + MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE = 1, +} cinstr_profiling_event_reason_single_gpu_t; + +#endif /*_MALI_UTGARD_PROFILING_EVENTS_H_*/ diff --git a/drivers/media/video/samsung/mali/common/mali_uk_types.h b/drivers/media/video/samsung/mali/include/linux/mali/mali_utgard_uk_types.h index e114fa8..512b1e2 100644 --- a/drivers/media/video/samsung/mali/common/mali_uk_types.h +++ b/drivers/media/video/samsung/mali/include/linux/mali/mali_utgard_uk_types.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -13,15 +13,8 @@ * Defines the types and constants used in the user-kernel interface */ -#ifndef __MALI_UK_TYPES_H__ -#define __MALI_UK_TYPES_H__ - -/* - * NOTE: Because this file can be included from user-side and kernel-side, - * it is up to the includee to ensure certain typedefs (e.g. u32) are already - * defined when #including this. - */ -#include "regs/mali_200_regs.h" +#ifndef __MALI_UTGARD_UK_TYPES_H__ +#define __MALI_UTGARD_UK_TYPES_H__ #ifdef __cplusplus extern "C" @@ -75,6 +68,8 @@ typedef enum _MALI_UK_WAIT_FOR_NOTIFICATION, /**< _mali_ukk_wait_for_notification() */ _MALI_UK_GET_API_VERSION, /**< _mali_ukk_get_api_version() */ _MALI_UK_POST_NOTIFICATION, /**< _mali_ukk_post_notification() */ + _MALI_UK_GET_USER_SETTING, /**< _mali_ukk_get_user_setting() *//**< [out] */ + _MALI_UK_GET_USER_SETTINGS, /**< _mali_ukk_get_user_settings() *//**< [out] */ /** Memory functions */ @@ -95,21 +90,19 @@ typedef enum /** Common functions for each core */ _MALI_UK_START_JOB = 0, /**< Start a Fragment/Vertex Processor Job on a core */ - _MALI_UK_ABORT_JOB, /**< Abort a job */ _MALI_UK_GET_NUMBER_OF_CORES, /**< Get the number of Fragment/Vertex Processor cores */ _MALI_UK_GET_CORE_VERSION, /**< Get the Fragment/Vertex Processor version compatible with all cores */ /** Fragment Processor Functions */ _MALI_UK_PP_START_JOB = _MALI_UK_START_JOB, /**< _mali_ukk_pp_start_job() */ - _MALI_UK_PP_ABORT_JOB = _MALI_UK_ABORT_JOB, /**< _mali_ukk_pp_abort_job() */ _MALI_UK_GET_PP_NUMBER_OF_CORES = _MALI_UK_GET_NUMBER_OF_CORES, /**< _mali_ukk_get_pp_number_of_cores() */ _MALI_UK_GET_PP_CORE_VERSION = _MALI_UK_GET_CORE_VERSION, /**< _mali_ukk_get_pp_core_version() */ + _MALI_UK_PP_DISABLE_WB, /**< _mali_ukk_pp_job_disable_wb() */ /** Vertex Processor Functions */ _MALI_UK_GP_START_JOB = _MALI_UK_START_JOB, /**< _mali_ukk_gp_start_job() */ - _MALI_UK_GP_ABORT_JOB = _MALI_UK_ABORT_JOB, /**< _mali_ukk_gp_abort_job() */ _MALI_UK_GET_GP_NUMBER_OF_CORES = _MALI_UK_GET_NUMBER_OF_CORES, /**< _mali_ukk_get_gp_number_of_cores() */ _MALI_UK_GET_GP_CORE_VERSION = _MALI_UK_GET_CORE_VERSION, /**< _mali_ukk_get_gp_core_version() */ _MALI_UK_GP_SUSPEND_RESPONSE, /**< _mali_ukk_gp_suspend_response() */ @@ -122,12 +115,7 @@ typedef enum _MALI_UK_PROFILING_GET_EVENT, /**< __mali_uku_profiling_get_event() */ _MALI_UK_PROFILING_CLEAR, /**< __mali_uku_profiling_clear() */ _MALI_UK_PROFILING_GET_CONFIG, /**< __mali_uku_profiling_get_config() */ - _MALI_UK_TRANSFER_SW_COUNTERS, - -#if USING_MALI_PMM - /** Power Management Module Functions */ - _MALI_UK_PMM_EVENT_MESSAGE = 0, /**< Raise an event message */ -#endif + _MALI_UK_PROFILING_REPORT_SW_COUNTERS,/**< __mali_uku_profiling_report_sw_counters() */ /** VSYNC reporting fuctions */ _MALI_UK_VSYNC_EVENT_REPORT = 0, /**< _mali_ukk_vsync_event_report() */ @@ -370,18 +358,9 @@ typedef struct typedef enum { _MALI_UK_START_JOB_STARTED, /**< Job started */ - _MALI_UK_START_JOB_STARTED_LOW_PRI_JOB_RETURNED, /**< Job started and bumped a lower priority job that was pending execution */ _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE /**< Job could not be started at this time. Try starting the job again */ } _mali_uk_start_job_status; -/** @brief Status indicating the result of starting a Vertex or Fragment processor job */ -typedef enum -{ - MALI_UK_START_JOB_FLAG_DEFAULT = 0, /**< Default behaviour; Flush L2 caches before start, no following jobs */ - MALI_UK_START_JOB_FLAG_NO_FLUSH = 1, /**< No need to flush L2 caches before start */ - MALI_UK_START_JOB_FLAG_MORE_JOBS_FOLLOW = 2, /**< More related jobs follows, try to schedule them as soon as possible after this job */ -} _mali_uk_start_job_flags; - /** @brief Status indicating the result of the execution of a Vertex or Fragment processor job */ typedef enum @@ -421,10 +400,7 @@ typedef enum * When @c _mali_ukk_gp_start_job() returns @c _MALI_OSK_ERR_OK, status contains the * result of the request (see \ref _mali_uk_start_job_status). If the job could * not get started (@c _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE) it should be - * tried again. If the job had a higher priority than the one currently pending - * execution (@c _MALI_UK_START_JOB_STARTED_LOW_PRI_JOB_RETURNED), it will bump - * the lower priority job and returns the address of the @c mali_gp_job_info - * for that job in @c returned_user_job_ptr. That job should get requeued. + * tried again. * * After the job has started, @c _mali_wait_for_notification() will be notified * that the job finished or got suspended. It may get suspended due to @@ -461,25 +437,16 @@ typedef struct void *ctx; /**< [in,out] user-kernel context (trashed on output) */ u32 user_job_ptr; /**< [in] identifier for the job in user space, a @c mali_gp_job_info* */ u32 priority; /**< [in] job priority. A lower number means higher priority */ - u32 watchdog_msecs; /**< [in] maximum allowed runtime in milliseconds. The job gets killed if it runs longer than this. A value of 0 selects the default used by the device driver. */ u32 frame_registers[MALIGP2_NUM_REGS_FRAME]; /**< [in] core specific registers associated with this job */ u32 perf_counter_flag; /**< [in] bitmask indicating which performance counters to enable, see \ref _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE and related macro definitions */ u32 perf_counter_src0; /**< [in] source id for performance counter 0 (see ARM DDI0415A, Table 3-60) */ u32 perf_counter_src1; /**< [in] source id for performance counter 1 (see ARM DDI0415A, Table 3-60) */ - u32 returned_user_job_ptr; /**< [out] identifier for the returned job in user space, a @c mali_gp_job_info* */ - _mali_uk_start_job_status status; /**< [out] indicates job start status (success, previous job returned, requeue) */ - u32 abort_id; /**< [in] abort id of this job, used to identify this job for later abort requests */ - u32 perf_counter_l2_src0; /**< [in] soruce id for Mali-400 MP L2 cache performance counter 0 */ - u32 perf_counter_l2_src1; /**< [in] source id for Mali-400 MP L2 cache performance counter 1 */ - u32 frame_builder_id; /**< [in] id of the originating frame builder */ - u32 flush_id; /**< [in] flush id within the originating frame builder */ + u32 frame_builder_id; /**< [in] id of the originating frame builder */ + u32 flush_id; /**< [in] flush id within the originating frame builder */ } _mali_uk_gp_start_job_s; #define _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE (1<<0) /**< Enable performance counter SRC0 for a job */ #define _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE (1<<1) /**< Enable performance counter SRC1 for a job */ -#define _MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE (1<<2) /**< Enable performance counter L2_SRC0 for a job */ -#define _MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE (1<<3) /**< Enable performance counter L2_SRC1 for a job */ -#define _MALI_PERFORMANCE_COUNTER_FLAG_L2_RESET (1<<4) /**< Enable performance counter L2_RESET for a job */ /** @} */ /* end group _mali_uk_gpstartjob_s */ @@ -487,20 +454,9 @@ typedef struct { u32 user_job_ptr; /**< [out] identifier for the job in user space */ _mali_uk_job_status status; /**< [out] status of finished job */ - u32 irq_status; /**< [out] value of the GP interrupt rawstat register (see ARM DDI0415A) */ - u32 status_reg_on_stop; /**< [out] value of the GP control register */ - u32 vscl_stop_addr; /**< [out] value of the GP VLSCL start register */ - u32 plbcl_stop_addr; /**< [out] value of the GP PLBCL start register */ u32 heap_current_addr; /**< [out] value of the GP PLB PL heap start address register */ - u32 perf_counter_src0; /**< [out] source id for performance counter 0 (see ARM DDI0415A, Table 3-60) */ - u32 perf_counter_src1; /**< [out] source id for performance counter 1 (see ARM DDI0415A, Table 3-60) */ u32 perf_counter0; /**< [out] value of perfomance counter 0 (see ARM DDI0415A) */ u32 perf_counter1; /**< [out] value of perfomance counter 1 (see ARM DDI0415A) */ - u32 render_time; /**< [out] number of microseconds it took for the job to render */ - u32 perf_counter_l2_src0; /**< [out] soruce id for Mali-400 MP L2 cache performance counter 0 */ - u32 perf_counter_l2_src1; /**< [out] soruce id for Mali-400 MP L2 cache performance counter 1 */ - u32 perf_counter_l2_val0; /**< [out] Value of the Mali-400 MP L2 cache performance counter 0 */ - u32 perf_counter_l2_val1; /**< [out] Value of the Mali-400 MP L2 cache performance counter 1 */ } _mali_uk_gp_job_finished_s; typedef enum _maligp_job_suspended_reason @@ -521,6 +477,12 @@ typedef struct /** @defgroup _mali_uk_pp U/K Fragment Processor * @{ */ +#define _MALI_PP_MAX_SUB_JOBS 8 + +#define _MALI_PP_MAX_FRAME_REGISTERS ((0x058/4)+1) + +#define _MALI_PP_MAX_WB_REGISTERS ((0x02C/4)+1) + /** @defgroup _mali_uk_ppstartjob_s Fragment Processor Start Job * @{ */ @@ -546,10 +508,7 @@ typedef struct * When _mali_ukk_pp_start_job() returns @c _MALI_OSK_ERR_OK, @c status contains the * result of the request (see \ref _mali_uk_start_job_status). If the job could * not get started (@c _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE) it should be - * tried again. If the job had a higher priority than the one currently pending - * execution (@c _MALI_UK_START_JOB_STARTED_LOW_PRI_JOB_RETURNED), it will bump - * the lower priority job and returns the address of the @c mali_pp_job - * for that job in @c returned_user_job_ptr. That job should get requeued. + * tried again. * * After the job has started, _mali_wait_for_notification() will be notified * when the job finished. The notification will contain a @@ -573,43 +532,48 @@ typedef struct void *ctx; /**< [in,out] user-kernel context (trashed on output) */ u32 user_job_ptr; /**< [in] identifier for the job in user space */ u32 priority; /**< [in] job priority. A lower number means higher priority */ - u32 watchdog_msecs; /**< [in] maximum allowed runtime in milliseconds. The job gets killed if it runs longer than this. A value of 0 selects the default used by the device driver. */ - u32 frame_registers[MALI200_NUM_REGS_FRAME]; /**< [in] core specific registers associated with this job, see ARM DDI0415A */ - u32 wb0_registers[MALI200_NUM_REGS_WBx]; - u32 wb1_registers[MALI200_NUM_REGS_WBx]; - u32 wb2_registers[MALI200_NUM_REGS_WBx]; + u32 frame_registers[_MALI_PP_MAX_FRAME_REGISTERS]; /**< [in] core specific registers associated with first sub job, see ARM DDI0415A */ + u32 frame_registers_addr_frame[_MALI_PP_MAX_SUB_JOBS - 1]; /**< [in] ADDR_FRAME registers for sub job 1-7 */ + u32 frame_registers_addr_stack[_MALI_PP_MAX_SUB_JOBS - 1]; /**< [in] ADDR_STACK registers for sub job 1-7 */ + u32 wb0_registers[_MALI_PP_MAX_WB_REGISTERS]; + u32 wb1_registers[_MALI_PP_MAX_WB_REGISTERS]; + u32 wb2_registers[_MALI_PP_MAX_WB_REGISTERS]; + u32 num_cores; /**< [in] Number of cores to set up (valid range: 1-4) */ u32 perf_counter_flag; /**< [in] bitmask indicating which performance counters to enable, see \ref _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE and related macro definitions */ u32 perf_counter_src0; /**< [in] source id for performance counter 0 (see ARM DDI0415A, Table 3-60) */ u32 perf_counter_src1; /**< [in] source id for performance counter 1 (see ARM DDI0415A, Table 3-60) */ - u32 returned_user_job_ptr; /**< [out] identifier for the returned job in user space */ - _mali_uk_start_job_status status; /**< [out] indicates job start status (success, previous job returned, requeue) */ - u32 abort_id; /**< [in] abort id of this job, used to identify this job for later abort requests */ - u32 perf_counter_l2_src0; /**< [in] soruce id for Mali-400 MP L2 cache performance counter 0 */ - u32 perf_counter_l2_src1; /**< [in] source id for Mali-400 MP L2 cache performance counter 1 */ - u32 frame_builder_id; /**< [in] id of the originating frame builder */ - u32 flush_id; /**< [in] flush id within the originating frame builder */ - _mali_uk_start_job_flags flags; /**< [in] Flags for job, see _mali_uk_start_job_flags for more information */ + u32 frame_builder_id; /**< [in] id of the originating frame builder */ + u32 flush_id; /**< [in] flush id within the originating frame builder */ } _mali_uk_pp_start_job_s; /** @} */ /* end group _mali_uk_ppstartjob_s */ typedef struct { - u32 user_job_ptr; /**< [out] identifier for the job in user space */ - _mali_uk_job_status status; /**< [out] status of finished job */ - u32 irq_status; /**< [out] value of interrupt rawstat register (see ARM DDI0415A) */ - u32 last_tile_list_addr; /**< [out] value of renderer list register (see ARM DDI0415A); necessary to restart a stopped job */ - u32 perf_counter_src0; /**< [out] source id for performance counter 0 (see ARM DDI0415A, Table 3-60) */ - u32 perf_counter_src1; /**< [out] source id for performance counter 1 (see ARM DDI0415A, Table 3-60) */ - u32 perf_counter0; /**< [out] value of perfomance counter 0 (see ARM DDI0415A) */ - u32 perf_counter1; /**< [out] value of perfomance counter 1 (see ARM DDI0415A) */ - u32 render_time; /**< [out] number of microseconds it took for the job to render */ - u32 perf_counter_l2_src0; /**< [out] soruce id for Mali-400 MP L2 cache performance counter 0 */ - u32 perf_counter_l2_src1; /**< [out] soruce id for Mali-400 MP L2 cache performance counter 1 */ - u32 perf_counter_l2_val0; /**< [out] Value of the Mali-400 MP L2 cache performance counter 0 */ - u32 perf_counter_l2_val1; /**< [out] Value of the Mali-400 MP L2 cache performance counter 1 */ - u32 perf_counter_l2_val0_raw; /**< [out] Raw value of the Mali-400 MP L2 cache performance counter 0 */ - u32 perf_counter_l2_val1_raw; /**< [out] Raw value of the Mali-400 MP L2 cache performance counter 1 */ + u32 user_job_ptr; /**< [out] identifier for the job in user space */ + _mali_uk_job_status status; /**< [out] status of finished job */ + u32 perf_counter0[_MALI_PP_MAX_SUB_JOBS]; /**< [out] value of perfomance counter 0 (see ARM DDI0415A), one for each sub job */ + u32 perf_counter1[_MALI_PP_MAX_SUB_JOBS]; /**< [out] value of perfomance counter 1 (see ARM DDI0415A), one for each sub job */ } _mali_uk_pp_job_finished_s; + +/** + * Flags to indicate write-back units + */ +typedef enum +{ + _MALI_UK_PP_JOB_WB0 = 1, + _MALI_UK_PP_JOB_WB1 = 2, + _MALI_UK_PP_JOB_WB2 = 4, +} _mali_uk_pp_job_wbx_flag; + +typedef struct +{ + void *ctx; /**< [in,out] user-kernel context (trashed on output) */ + u32 fb_id; /**< [in] Frame builder ID of job to disable WB units for */ + u32 flush_id; /**< [in] Flush ID of job to disable WB units for */ + _mali_uk_pp_job_wbx_flag wbx; /**< [in] write-back units to disable */ +} _mali_uk_pp_disable_wb_s; + + /** @} */ /* end group _mali_uk_pp */ @@ -635,6 +599,7 @@ typedef enum _MALI_NOTIFICATION_CORE_SHUTDOWN_IN_PROGRESS = (_MALI_UK_CORE_SUBSYSTEM << 16) | 0x20, _MALI_NOTIFICATION_APPLICATION_QUIT = (_MALI_UK_CORE_SUBSYSTEM << 16) | 0x40, + _MALI_NOTIFICATION_SETTINGS_CHANGED = (_MALI_UK_CORE_SUBSYSTEM << 16) | 0x80, /** Fragment Processor notifications */ @@ -644,6 +609,7 @@ typedef enum _MALI_NOTIFICATION_GP_FINISHED = (_MALI_UK_GP_SUBSYSTEM << 16) | 0x10, _MALI_NOTIFICATION_GP_STALLED = (_MALI_UK_GP_SUBSYSTEM << 16) | 0x20, + } _mali_uk_notification_type; /** to assist in splitting up 32-bit notification value in subsystem and id value */ @@ -653,6 +619,51 @@ typedef enum #define _MALI_NOTIFICATION_ID_SHIFT 0 +/** @brief Enumeration of possible settings which match mali_setting_t in user space + * + * + */ +typedef enum +{ + _MALI_UK_USER_SETTING_SW_EVENTS_ENABLE = 0, + _MALI_UK_USER_SETTING_COLORBUFFER_CAPTURE_ENABLED, + _MALI_UK_USER_SETTING_DEPTHBUFFER_CAPTURE_ENABLED, + _MALI_UK_USER_SETTING_STENCILBUFFER_CAPTURE_ENABLED, + _MALI_UK_USER_SETTING_PER_TILE_COUNTERS_CAPTURE_ENABLED, + _MALI_UK_USER_SETTING_BUFFER_CAPTURE_COMPOSITOR, + _MALI_UK_USER_SETTING_BUFFER_CAPTURE_WINDOW, + _MALI_UK_USER_SETTING_BUFFER_CAPTURE_OTHER, + _MALI_UK_USER_SETTING_BUFFER_CAPTURE_N_FRAMES, + _MALI_UK_USER_SETTING_BUFFER_CAPTURE_RESIZE_FACTOR, + _MALI_UK_USER_SETTING_SW_COUNTER_ENABLED, + _MALI_UK_USER_SETTING_MAX, +} _mali_uk_user_setting_t; + +/* See mali_user_settings_db.c */ +extern const char *_mali_uk_user_setting_descriptions[]; +#define _MALI_UK_USER_SETTING_DESCRIPTIONS \ +{ \ + "sw_events_enable", \ + "colorbuffer_capture_enable", \ + "depthbuffer_capture_enable", \ + "stencilbuffer_capture_enable", \ + "per_tile_counters_enable", \ + "buffer_capture_compositor", \ + "buffer_capture_window", \ + "buffer_capture_other", \ + "buffer_capture_n_frames", \ + "buffer_capture_resize_factor", \ + "sw_counters_enable", \ +}; + +/** @brief struct to hold the value to a particular setting as seen in the kernel space + */ +typedef struct +{ + _mali_uk_user_setting_t setting; + u32 value; +} _mali_uk_settings_changed_s; + /** @brief Arguments for _mali_ukk_wait_for_notification() * * On successful return from _mali_ukk_wait_for_notification(), the members of @@ -698,14 +709,15 @@ typedef enum */ typedef struct { - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ + void *ctx; /**< [in,out] user-kernel context (trashed on output) */ _mali_uk_notification_type type; /**< [out] Type of notification available */ - union - { - _mali_uk_gp_job_suspended_s gp_job_suspended;/**< [out] Notification data for _MALI_NOTIFICATION_GP_STALLED notification type */ - _mali_uk_gp_job_finished_s gp_job_finished; /**< [out] Notification data for _MALI_NOTIFICATION_GP_FINISHED notification type */ - _mali_uk_pp_job_finished_s pp_job_finished; /**< [out] Notification data for _MALI_NOTIFICATION_PP_FINISHED notification type */ - } data; + union + { + _mali_uk_gp_job_suspended_s gp_job_suspended;/**< [out] Notification data for _MALI_NOTIFICATION_GP_STALLED notification type */ + _mali_uk_gp_job_finished_s gp_job_finished; /**< [out] Notification data for _MALI_NOTIFICATION_GP_FINISHED notification type */ + _mali_uk_pp_job_finished_s pp_job_finished; /**< [out] Notification data for _MALI_NOTIFICATION_PP_FINISHED notification type */ + _mali_uk_settings_changed_s setting_changed;/**< [out] Notification data for _MALI_NOTIFICAATION_SETTINGS_CHANGED notification type */ + } data; } _mali_uk_wait_for_notification_s; /** @brief Arguments for _mali_ukk_post_notification() @@ -718,6 +730,7 @@ typedef struct void *ctx; /**< [in,out] user-kernel context (trashed on output) */ _mali_uk_notification_type type; /**< [in] Type of notification to post */ } _mali_uk_post_notification_s; + /** @} */ /* end group _mali_uk_waitfornotification_s */ /** @defgroup _mali_uk_getapiversion_s Get API Version @@ -748,7 +761,7 @@ typedef struct * The 16bit integer is stored twice in a 32bit integer * For example, for version 1 the value would be 0x00010001 */ -#define _MALI_API_VERSION 10 +#define _MALI_API_VERSION 14 #define _MALI_UK_API_VERSION _MAKE_VERSION_ID(_MALI_API_VERSION) /** @@ -780,6 +793,31 @@ typedef struct } _mali_uk_get_api_version_s; /** @} */ /* end group _mali_uk_getapiversion_s */ +/** @defgroup _mali_uk_get_user_settings_s Get user space settings */ + +/** @brief struct to keep the matching values of the user space settings within certain context + * + * Each member of the settings array corresponds to a matching setting in the user space and its value is the value + * of that particular setting. + * + * All settings are given reference to the context pointed to by the ctx pointer. + * + */ +typedef struct +{ + void *ctx; /**< [in,out] user-kernel context (trashed on output) */ + u32 settings[_MALI_UK_USER_SETTING_MAX]; /**< [out] The values for all settings */ +} _mali_uk_get_user_settings_s; + +/** @brief struct to hold the value of a particular setting from the user space within a given context + */ +typedef struct +{ + void *ctx; /**< [in,out] user-kernel context (trashed on output) */ + _mali_uk_user_setting_t setting; /**< [in] setting to get */ + u32 value; /**< [out] value of setting */ +} _mali_uk_get_user_setting_s; + /** @} */ /* end group _mali_uk_core */ @@ -800,47 +838,6 @@ typedef struct void *ctx; /**< [in,out] user-kernel context (trashed on output) */ } _mali_uk_term_mem_s; -/** @brief Arguments for _mali_ukk_get_big_block() - * - * - type_id should be set to the value of the identifier member of one of the - * _mali_mem_info structures returned through _mali_ukk_get_system_info() - * - ukk_private must be zero when calling from user-side. On Kernel-side, the - * OS implementation of the U/K interface can use it to communicate data to the - * OS implementation of the OSK layer. Specifically, ukk_private will be placed - * into the ukk_private member of the _mali_uk_mem_mmap_s structure. See - * _mali_ukk_mem_mmap() for more details. - * - minimum_size_requested will be updated if it is too small - * - block_size will always be >= minimum_size_requested, because the underlying - * allocation mechanism may only be able to divide up memory regions in certain - * ways. To avoid wasting memory, block_size should always be taken into account - * rather than assuming minimum_size_requested was really allocated. - * - to free the memory, the returned cookie member must be stored, and used to - * refer to it. - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 type_id; /**< [in] the type id of the memory bank to allocate memory from */ - u32 minimum_size_requested; /**< [in,out] minimum size of the allocation */ - u32 ukk_private; /**< [in] Kernel-side private word inserted by certain U/K interface implementations. Caller must set to Zero. */ - u32 mali_address; /**< [out] address of the allocation in mali address space */ - void *cpuptr; /**< [out] address of the allocation in the current process address space */ - u32 block_size; /**< [out] size of the block that got allocated */ - u32 flags; /**< [out] flags associated with the allocated block, of type _mali_bus_usage */ - u32 cookie; /**< [out] identifier for the allocated block in kernel space */ -} _mali_uk_get_big_block_s; - -/** @brief Arguments for _mali_ukk_free_big_block() - * - * All that is required is that the cookie member must be set to the value of - * the cookie member returned through _mali_ukk_get_big_block() - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 cookie; /**< [in] identifier for mapped memory object in kernel space */ -} _mali_uk_free_big_block_s; - /** @note Mali-MMU only */ typedef struct { @@ -959,12 +956,6 @@ typedef struct _mali_core_version version; /**< [out] version returned from core, see \ref _mali_core_version */ } _mali_uk_get_pp_core_version_s; -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 abort_id; /**< [in] ID of job(s) to abort */ -} _mali_uk_pp_abort_job_s; - /** @} */ /* end group _mali_uk_pp */ @@ -997,12 +988,6 @@ typedef struct typedef struct { - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 abort_id; /**< [in] ID of job(s) to abort */ -} _mali_uk_gp_abort_job_s; - -typedef struct -{ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ u32 limit; /**< [in,out] The desired limit for number of events to record on input, actual limit on output */ } _mali_uk_profiling_start_s; @@ -1031,24 +1016,9 @@ typedef struct typedef struct { - void *ctx; - - u32 id; - s64 value; -} _mali_uk_sw_counters_s; - -typedef struct -{ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ } _mali_uk_profiling_clear_s; -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 enable_events; /**< [out]Â 1 if user space process should generate events, 0 if not */ -} _mali_uk_profiling_get_config_s; - - /** @} */ /* end group _mali_uk_gp */ @@ -1111,35 +1081,6 @@ typedef struct } _mali_uk_mem_munmap_s; /** @} */ /* end group _mali_uk_memory */ -#if USING_MALI_PMM - -/** @defgroup _mali_uk_pmm U/K Power Management Module - * @{ */ - -/** @brief Power management event message identifiers. - * - * U/K events start after id 200, and can range up to 999 - * Adding new events will require updates to the PMM mali_pmm_event_id type - */ -#define _MALI_PMM_EVENT_UK_EXAMPLE 201 - -/** @brief Generic PMM message data type, that will be dependent on the event msg - */ -typedef u32 mali_pmm_message_data; - - -/** @brief Arguments to _mali_ukk_pmm_event_message() - */ -typedef struct -{ - void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - u32 id; /**< [in] event id */ - mali_pmm_message_data data; /**< [in] specific data associated with the event */ -} _mali_uk_pmm_message_s; - -/** @} */ /* end group _mali_uk_pmm */ -#endif /* USING_MALI_PMM */ - /** @defgroup _mali_uk_vsync U/K VSYNC Wait Reporting Module * @{ */ @@ -1165,6 +1106,22 @@ typedef struct /** @} */ /* end group _mali_uk_vsync */ +/** @defgroup _mali_uk_sw_counters_report U/K Software Counter Reporting + * @{ */ + +/** @brief Software counter values + * + * Values recorded for each of the software counters during a single renderpass. + */ +typedef struct +{ + void *ctx; /**< [in,out] user-kernel context (trashed on output) */ + u32* counters; /**< [in] The array of counter values */ + u32 num_counters; /**< [in] The number of elements in counters array */ +} _mali_uk_sw_counters_report_s; + +/** @} */ /* end group _mali_uk_sw_counters_report */ + /** @} */ /* end group u_k_api */ /** @} */ /* end group uddapi */ @@ -1173,4 +1130,4 @@ typedef struct } #endif -#endif /* __MALI_UK_TYPES_H__ */ +#endif /* __MALI_UTGARD_UK_TYPES_H__ */ diff --git a/drivers/media/video/samsung/mali/linux/mali_device_pause_resume.c b/drivers/media/video/samsung/mali/linux/mali_device_pause_resume.c deleted file mode 100644 index 04f57d9..0000000 --- a/drivers/media/video/samsung/mali/linux/mali_device_pause_resume.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** - * @file mali_device_pause_resume.c - * Implementation of the Mali pause/resume functionality - */ -#if USING_MALI_PMM -#include <linux/version.h> -#include <linux/sched.h> -#include <linux/module.h> -#include "mali_osk.h" -#include "mali_kernel_common.h" -#include "mali_platform.h" -#include "mali_linux_pm.h" -#include "mali_device_pause_resume.h" -#include "mali_pmm.h" -#include "mali_kernel_license.h" -#ifdef CONFIG_PM -#if MALI_LICENSE_IS_GPL - -/* Mali Pause Resume APIs */ -int mali_dev_pause() -{ - int err = 0; - _mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW); - if ((mali_dvfs_device_state == _MALI_DEVICE_SUSPEND) - || (mali_device_state == _MALI_DEVICE_SUSPEND) ) - { - err = -EPERM; - } - if ((mali_dvfs_device_state == _MALI_DEVICE_RESUME) && (!err)) - { - mali_device_suspend(MALI_PMM_EVENT_DVFS_PAUSE, &dvfs_pm_thread); - mali_dvfs_device_state = _MALI_DEVICE_SUSPEND; - } - _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW); - return err; -} - -EXPORT_SYMBOL(mali_dev_pause); - -int mali_dev_resume() -{ - int err = 0; - _mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW); - if ((mali_dvfs_device_state == _MALI_DEVICE_RESUME) - || (mali_device_state == _MALI_DEVICE_SUSPEND) ) - { - err = -EPERM; - } - if (!err) - { - mali_device_resume(MALI_PMM_EVENT_DVFS_RESUME, &dvfs_pm_thread); - mali_dvfs_device_state = _MALI_DEVICE_RESUME; - } - _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW); - return err; -} - -EXPORT_SYMBOL(mali_dev_resume); - -#endif /* MALI_LICENSE_IS_GPL */ -#endif /* CONFIG_PM */ -#endif /* USING_MALI_PMM */ diff --git a/drivers/media/video/samsung/mali/linux/mali_kernel_ioctl.h b/drivers/media/video/samsung/mali/linux/mali_kernel_ioctl.h index 7e3a216..6fc59a7 100644 --- a/drivers/media/video/samsung/mali/linux/mali_kernel_ioctl.h +++ b/drivers/media/video/samsung/mali/linux/mali_kernel_ioctl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -44,8 +44,10 @@ extern "C" #define MALI_IOC_WAIT_FOR_NOTIFICATION _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_WAIT_FOR_NOTIFICATION, _mali_uk_wait_for_notification_s *) #define MALI_IOC_GET_API_VERSION _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_GET_API_VERSION, _mali_uk_get_api_version_s *) #define MALI_IOC_POST_NOTIFICATION _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_POST_NOTIFICATION, _mali_uk_post_notification_s *) -#define MALI_IOC_MEM_GET_BIG_BLOCK _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_GET_BIG_BLOCK, _mali_uk_get_big_block_s *) -#define MALI_IOC_MEM_FREE_BIG_BLOCK _IOW (MALI_IOC_MEMORY_BASE, _MALI_UK_FREE_BIG_BLOCK, _mali_uk_free_big_block_s *) +#define MALI_IOC_GET_USER_SETTING _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_GET_USER_SETTING, _mali_uk_get_user_setting_s *) +#define MALI_IOC_GET_USER_SETTINGS _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_GET_USER_SETTINGS, _mali_uk_get_user_settings_s *) +#define MALI_IOC_MEM_GET_BIG_BLOCK _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_GET_BIG_BLOCK, void *) +#define MALI_IOC_MEM_FREE_BIG_BLOCK _IOW (MALI_IOC_MEMORY_BASE, _MALI_UK_FREE_BIG_BLOCK, void *) #define MALI_IOC_MEM_INIT _IOR (MALI_IOC_MEMORY_BASE, _MALI_UK_INIT_MEM, _mali_uk_init_mem_s *) #define MALI_IOC_MEM_TERM _IOW (MALI_IOC_MEMORY_BASE, _MALI_UK_TERM_MEM, _mali_uk_term_mem_s *) #define MALI_IOC_MEM_MAP_EXT _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_MAP_EXT_MEM, _mali_uk_map_external_mem_s *) @@ -57,9 +59,7 @@ extern "C" #define MALI_IOC_PP_START_JOB _IOWR(MALI_IOC_PP_BASE, _MALI_UK_PP_START_JOB, _mali_uk_pp_start_job_s *) #define MALI_IOC_PP_NUMBER_OF_CORES_GET _IOR (MALI_IOC_PP_BASE, _MALI_UK_GET_PP_NUMBER_OF_CORES, _mali_uk_get_pp_number_of_cores_s *) #define MALI_IOC_PP_CORE_VERSION_GET _IOR (MALI_IOC_PP_BASE, _MALI_UK_GET_PP_CORE_VERSION, _mali_uk_get_pp_core_version_s * ) -#define MALI_IOC_PP_ABORT_JOB _IOW (MALI_IOC_PP_BASE, _MALI_UK_PP_ABORT_JOB, _mali_uk_pp_abort_job_s * ) #define MALI_IOC_GP2_START_JOB _IOWR(MALI_IOC_GP_BASE, _MALI_UK_GP_START_JOB, _mali_uk_gp_start_job_s *) -#define MALI_IOC_GP2_ABORT_JOB _IOWR(MALI_IOC_GP_BASE, _MALI_UK_GP_ABORT_JOB, _mali_uk_gp_abort_job_s *) #define MALI_IOC_GP2_NUMBER_OF_CORES_GET _IOR (MALI_IOC_GP_BASE, _MALI_UK_GET_GP_NUMBER_OF_CORES, _mali_uk_get_gp_number_of_cores_s *) #define MALI_IOC_GP2_CORE_VERSION_GET _IOR (MALI_IOC_GP_BASE, _MALI_UK_GET_GP_CORE_VERSION, _mali_uk_get_gp_core_version_s *) #define MALI_IOC_GP2_SUSPEND_RESPONSE _IOW (MALI_IOC_GP_BASE, _MALI_UK_GP_SUSPEND_RESPONSE,_mali_uk_gp_suspend_response_s *) @@ -68,8 +68,7 @@ extern "C" #define MALI_IOC_PROFILING_STOP _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_STOP, _mali_uk_profiling_stop_s *) #define MALI_IOC_PROFILING_GET_EVENT _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_GET_EVENT, _mali_uk_profiling_get_event_s *) #define MALI_IOC_PROFILING_CLEAR _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_CLEAR, _mali_uk_profiling_clear_s *) -#define MALI_IOC_TRANSFER_SW_COUNTERS _IOW (MALI_IOC_PROFILING_BASE, _MALI_UK_TRANSFER_SW_COUNTERS, _mali_uk_sw_counters_s *) -#define MALI_IOC_PROFILING_GET_CONFIG _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_GET_CONFIG, _mali_uk_profiling_get_config_s *) +#define MALI_IOC_PROFILING_GET_CONFIG _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_GET_CONFIG, _mali_uk_get_user_settings_s *) #define MALI_IOC_VSYNC_EVENT_REPORT _IOW (MALI_IOC_VSYNC_BASE, _MALI_UK_VSYNC_EVENT_REPORT, _mali_uk_vsync_event_report_s *) #ifdef __cplusplus diff --git a/drivers/media/video/samsung/mali/linux/mali_kernel_linux.c b/drivers/media/video/samsung/mali/linux/mali_kernel_linux.c index 05762ca..3de368e 100644 --- a/drivers/media/video/samsung/mali/linux/mali_kernel_linux.c +++ b/drivers/media/video/samsung/mali/linux/mali_kernel_linux.c @@ -1,5 +1,5 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. +/** + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -15,31 +15,31 @@ #include <linux/module.h> /* kernel module definitions */ #include <linux/fs.h> /* file system operations */ #include <linux/cdev.h> /* character device definitions */ -#include <linux/mm.h> /* memory mananger definitions */ -#include <linux/device.h> - -/* the mali kernel subsystem types */ -#include "mali_kernel_subsystem.h" - -/* A memory subsystem always exists, so no need to conditionally include it */ +#include <linux/mm.h> /* memory mananger definitions */ +#include <linux/mali/mali_utgard_ioctl.h> #include "mali_kernel_common.h" -#include "mali_kernel_session_manager.h" +#include "mali_session.h" #include "mali_kernel_core.h" - #include "mali_osk.h" #include "mali_kernel_linux.h" #include "mali_ukk.h" -#include "mali_kernel_ioctl.h" #include "mali_ukk_wrappers.h" #include "mali_kernel_pm.h" -#include "mali_linux_pm.h" - #include "mali_kernel_sysfs.h" - -/* */ +#include "mali_platform.h" #include "mali_kernel_license.h" -#include "mali_platform.h" +/* Streamline support for the Mali driver */ +#if defined(CONFIG_TRACEPOINTS) && MALI_TIMELINE_PROFILING_ENABLED +/* Ask Linux to create the tracepoints */ +#define CREATE_TRACE_POINTS +#include "mali_linux_trace.h" +#endif /* CONFIG_TRACEPOINTS */ + +static _mali_osk_errcode_t initialize_kernel_device(void); +static int initialize_sysfs(void); +static void terminate_kernel_device(void); + /* from the __malidrv_build_info.c file that is generated during build */ extern const char *__malidrv_build_info(void); @@ -58,23 +58,15 @@ int mali_major = 0; module_param(mali_major, int, S_IRUGO); /* r--r--r-- */ MODULE_PARM_DESC(mali_major, "Device major number"); -int mali_benchmark = 0; -module_param(mali_benchmark, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); /* rw-rw-r-- */ -MODULE_PARM_DESC(mali_benchmark, "Bypass Mali hardware when non-zero"); - -extern int mali_hang_check_interval; module_param(mali_hang_check_interval, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); MODULE_PARM_DESC(mali_hang_check_interval, "Interval at which to check for progress after the hw watchdog has been triggered"); -extern int mali_max_job_runtime; module_param(mali_max_job_runtime, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); MODULE_PARM_DESC(mali_max_job_runtime, "Maximum allowed job runtime in msecs.\nJobs will be killed after this no matter what"); -#if defined(USING_MALI400_L2_CACHE) extern int mali_l2_max_reads; module_param(mali_l2_max_reads, int, S_IRUSR | S_IRGRP | S_IROTH); MODULE_PARM_DESC(mali_l2_max_reads, "Maximum reads for Mali L2 cache"); -#endif #if MALI_TIMELINE_PROFILING_ENABLED extern int mali_boot_profiling; @@ -82,6 +74,10 @@ module_param(mali_boot_profiling, int, S_IRUSR | S_IRGRP | S_IROTH); MODULE_PARM_DESC(mali_boot_profiling, "Start profiling as a part of Mali driver initialization"); #endif +/* Export symbols from common code: mali_user_settings.c */ +#include "mali_user_settings_db.h" +EXPORT_SYMBOL(mali_set_user_setting); +EXPORT_SYMBOL(mali_get_user_setting); #if MALI_DVFS_ENABLED extern int mali_dvfs_control; module_param(mali_dvfs_control, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP| S_IROTH); /* rw-rw-r-- */ @@ -154,7 +150,6 @@ MODULE_PARM_DESC(step3_vol, "Mali Current step3_vol"); #endif #endif #endif -#endif extern int mali_gpu_clk; module_param(mali_gpu_clk, int, S_IRUSR | S_IRGRP | S_IROTH); /* r--r--r-- */ @@ -167,7 +162,8 @@ MODULE_PARM_DESC(mali_gpu_vol, "Mali Current Voltage"); extern int gpu_power_state; module_param(gpu_power_state, int, S_IRUSR | S_IRGRP | S_IROTH); /* r--r--r-- */ MODULE_PARM_DESC(gpu_power_state, "Mali Power State"); -extern _mali_device_power_states mali_dvfs_device_state; +#endif + static char mali_dev_name[] = "mali"; /* should be const, but the functions we call requires non-cost */ @@ -202,53 +198,74 @@ struct file_operations mali_fops = int mali_driver_init(void) { - int err; -#if USING_MALI_PMM -#if MALI_LICENSE_IS_GPL -#ifdef CONFIG_PM - err = _mali_dev_platform_register(); - if (err) - { - return err; - } -#endif -#endif -#endif - err = mali_kernel_constructor(); - if (_MALI_OSK_ERR_OK != err) - { -#if USING_MALI_PMM -#if MALI_LICENSE_IS_GPL -#ifdef CONFIG_PM - _mali_dev_platform_unregister(); -#endif -#endif -#endif - MALI_PRINT(("Failed to initialize driver (error %d)\n", err)); - return -EFAULT; - } + int ret = 0; - /* print build options */ - MALI_DEBUG_PRINT(2, ("%s\n", __malidrv_build_info())); + MALI_DEBUG_PRINT(2, ("\n")); + MALI_DEBUG_PRINT(2, ("Inserting Mali v%d device driver. \n",_MALI_API_VERSION)); + MALI_DEBUG_PRINT(2, ("Compiled: %s, time: %s.\n", __DATE__, __TIME__)); + MALI_DEBUG_PRINT(2, ("Driver revision: %s\n", SVN_REV_STRING)); - return 0; + ret = _mali_dev_platform_register(); + if (0 != ret) goto platform_register_failed; + ret = map_errcode(initialize_kernel_device()); + if (0 != ret) goto initialize_kernel_device_failed; + + ret = map_errcode(mali_platform_init()); + if (0 != ret) goto platform_init_failed; + + mali_osk_low_level_mem_init(); + + ret = map_errcode(mali_initialize_subsystems()); + if (0 != ret) goto initialize_subsystems_failed; + + ret = initialize_sysfs(); + if (0 != ret) goto initialize_sysfs_failed; + + MALI_PRINT(("Mali device driver loaded\n")); + + return 0; /* Success */ + + /* Error handling */ +initialize_sysfs_failed: + mali_terminate_subsystems(); +initialize_subsystems_failed: + mali_osk_low_level_mem_term(); + mali_platform_deinit(); +platform_init_failed: + terminate_kernel_device(); +initialize_kernel_device_failed: + _mali_dev_platform_unregister(); +platform_register_failed: + return ret; } void mali_driver_exit(void) { - mali_kernel_destructor(); + MALI_DEBUG_PRINT(2, ("\n")); + MALI_DEBUG_PRINT(2, ("Unloading Mali v%d device driver.\n",_MALI_API_VERSION)); -#if USING_MALI_PMM -#if MALI_LICENSE_IS_GPL -#ifdef CONFIG_PM + /* No need to terminate sysfs, this will be done automatically along with device termination */ + + mali_terminate_subsystems(); + + mali_osk_low_level_mem_term(); + + mali_platform_deinit(); + + terminate_kernel_device(); _mali_dev_platform_unregister(); + +#if MALI_LICENSE_IS_GPL + /* @@@@ clean up the work queues! This should not be terminated here, since it isn't inited in the function above! */ + flush_workqueue(mali_wq); + destroy_workqueue(mali_wq); + mali_wq = NULL; #endif -#endif -#endif + + MALI_PRINT(("Mali device driver unloaded\n")); } -/* called from _mali_osk_init */ -int initialize_kernel_device(void) +static int initialize_kernel_device(void) { int err; dev_t dev = 0; @@ -284,28 +301,25 @@ int initialize_kernel_device(void) goto init_cdev_err; } - err = mali_sysfs_register(&device, dev, mali_dev_name); - if (err) - { - goto init_sysfs_err; - } - /* Success! */ return 0; -init_sysfs_err: - cdev_del(&device.cdev); init_cdev_err: unregister_chrdev_region(dev, 1/*count*/); init_chrdev_err: return err; } -/* called from _mali_osk_term */ -void terminate_kernel_device(void) +static int initialize_sysfs(void) { dev_t dev = MKDEV(mali_major, 0); - + return mali_sysfs_register(&device, dev, mali_dev_name); +} + +static void terminate_kernel_device(void) +{ + dev_t dev = MKDEV(mali_major, 0); + mali_sysfs_unregister(&device, dev, mali_dev_name); /* unregister char device */ @@ -421,12 +435,6 @@ static int mali_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return -ENOTTY; } - if (_MALI_DEVICE_SHUTDOWN == mali_dvfs_device_state) - { - MALI_DEBUG_PRINT(7, ("system is shutdown \n")); - return 0; - } - switch(cmd) { case MALI_IOC_GET_SYSTEM_INFO_SIZE: @@ -449,6 +457,10 @@ static int mali_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, err = post_notification_wrapper(session_data, (_mali_uk_post_notification_s __user *)arg); break; + case MALI_IOC_GET_USER_SETTINGS: + err = get_user_settings_wrapper(session_data, (_mali_uk_get_user_settings_s __user *)arg); + break; + #if MALI_TIMELINE_PROFILING_ENABLED case MALI_IOC_PROFILING_START: err = profiling_start_wrapper(session_data, (_mali_uk_profiling_start_s __user *)arg); @@ -471,8 +483,26 @@ static int mali_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, break; case MALI_IOC_PROFILING_GET_CONFIG: - err = profiling_get_config_wrapper(session_data, (_mali_uk_profiling_get_config_s __user *)arg); + /* Deprecated: still compatible with get_user_settings */ + err = get_user_settings_wrapper(session_data, (_mali_uk_get_user_settings_s __user *)arg); + break; + + case MALI_IOC_PROFILING_REPORT_SW_COUNTERS: + err = profiling_report_sw_counters_wrapper(session_data, (_mali_uk_sw_counters_report_s __user *)arg); + break; +#else + + case MALI_IOC_PROFILING_START: /* FALL-THROUGH */ + case MALI_IOC_PROFILING_ADD_EVENT: /* FALL-THROUGH */ + case MALI_IOC_PROFILING_STOP: /* FALL-THROUGH */ + case MALI_IOC_PROFILING_GET_EVENT: /* FALL-THROUGH */ + case MALI_IOC_PROFILING_CLEAR: /* FALL-THROUGH */ + case MALI_IOC_PROFILING_GET_CONFIG: /* FALL-THROUGH */ + case MALI_IOC_PROFILING_REPORT_SW_COUNTERS: /* FALL-THROUGH */ + MALI_DEBUG_PRINT(2, ("Profiling not supported\n")); + err = -ENOTTY; break; + #endif case MALI_IOC_MEM_INIT: @@ -499,14 +529,6 @@ static int mali_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, err = mem_dump_mmu_page_table_wrapper(session_data, (_mali_uk_dump_mmu_page_table_s __user *)arg); break; - case MALI_IOC_MEM_GET_BIG_BLOCK: - err = mem_get_big_block_wrapper(filp, (_mali_uk_get_big_block_s __user *)arg); - break; - - case MALI_IOC_MEM_FREE_BIG_BLOCK: - err = mem_free_big_block_wrapper(session_data, (_mali_uk_free_big_block_s __user *)arg); - break; - #if MALI_USE_UNIFIED_MEMORY_PROVIDER != 0 case MALI_IOC_MEM_ATTACH_UMP: @@ -530,10 +552,6 @@ static int mali_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, err = pp_start_job_wrapper(session_data, (_mali_uk_pp_start_job_s __user *)arg); break; - case MALI_IOC_PP_ABORT_JOB: - err = pp_abort_job_wrapper(session_data, (_mali_uk_pp_abort_job_s __user *)arg); - break; - case MALI_IOC_PP_NUMBER_OF_CORES_GET: err = pp_get_number_of_cores_wrapper(session_data, (_mali_uk_get_pp_number_of_cores_s __user *)arg); break; @@ -542,12 +560,12 @@ static int mali_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, err = pp_get_core_version_wrapper(session_data, (_mali_uk_get_pp_core_version_s __user *)arg); break; - case MALI_IOC_GP2_START_JOB: - err = gp_start_job_wrapper(session_data, (_mali_uk_gp_start_job_s __user *)arg); + case MALI_IOC_PP_DISABLE_WB: + err = pp_disable_wb_wrapper(session_data, (_mali_uk_pp_disable_wb_s __user *)arg); break; - case MALI_IOC_GP2_ABORT_JOB: - err = gp_abort_job_wrapper(session_data, (_mali_uk_gp_abort_job_s __user *)arg); + case MALI_IOC_GP2_START_JOB: + err = gp_start_job_wrapper(session_data, (_mali_uk_gp_start_job_s __user *)arg); break; case MALI_IOC_GP2_NUMBER_OF_CORES_GET: @@ -565,10 +583,11 @@ static int mali_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, case MALI_IOC_VSYNC_EVENT_REPORT: err = vsync_event_report_wrapper(session_data, (_mali_uk_vsync_event_report_s __user *)arg); break; -#if MALI_TRACEPOINTS_ENABLED - case MALI_IOC_TRANSFER_SW_COUNTERS: - err = transfer_sw_counters_wrapper(session_data, (_mali_uk_sw_counters_s __user *)arg); -#endif + + case MALI_IOC_MEM_GET_BIG_BLOCK: /* Fallthrough */ + case MALI_IOC_MEM_FREE_BIG_BLOCK: + MALI_PRINT_ERROR(("Non-MMU mode is no longer supported.\n")); + err = -ENOTTY; break; default: @@ -586,9 +605,3 @@ module_exit(mali_driver_exit); MODULE_LICENSE(MALI_KERNEL_LINUX_LICENSE); MODULE_AUTHOR("ARM Ltd."); MODULE_VERSION(SVN_REV_STRING); - -#if MALI_TRACEPOINTS_ENABLED -/* Create the trace points (otherwise we just get code to call a tracepoint) */ -#define CREATE_TRACE_POINTS -#include "mali_linux_trace.h" -#endif diff --git a/drivers/media/video/samsung/mali/linux/mali_kernel_linux.h b/drivers/media/video/samsung/mali/linux/mali_kernel_linux.h index 9c7668c..22dc9a4 100644 --- a/drivers/media/video/samsung/mali/linux/mali_kernel_linux.h +++ b/drivers/media/video/samsung/mali/linux/mali_kernel_linux.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -28,8 +28,10 @@ struct mali_dev #endif }; -_mali_osk_errcode_t initialize_kernel_device(void); -void terminate_kernel_device(void); +#if MALI_LICENSE_IS_GPL +/* Defined in mali_osk_irq.h */ +extern struct workqueue_struct * mali_wq; +#endif void mali_osk_low_level_mem_init(void); void mali_osk_low_level_mem_term(void); diff --git a/drivers/media/video/samsung/mali/linux/mali_kernel_pm.c b/drivers/media/video/samsung/mali/linux/mali_kernel_pm.c index f06ea4b..1d861f5 100644 --- a/drivers/media/video/samsung/mali/linux/mali_kernel_pm.c +++ b/drivers/media/video/samsung/mali/linux/mali_kernel_pm.c @@ -1,5 +1,5 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. +/** + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -10,615 +10,211 @@ /** * @file mali_kernel_pm.c - * Implementation of the Linux Power Management for Mali GPU kernel driver + * Linux Power Management integration */ -#if USING_MALI_PMM #include <linux/sched.h> - -#ifdef CONFIG_PM_RUNTIME -#include <linux/pm_runtime.h> -#endif /* CONFIG_PM_RUNTIME */ - #include <linux/platform_device.h> #include <linux/version.h> #include <asm/current.h> #include <linux/suspend.h> - -#include <plat/cpu.h> -#include <plat/pd.h> -#include <plat/devs.h> - -#include "mali_platform.h" +#include <linux/module.h> +#ifdef CONFIG_PM_RUNTIME +#include <linux/pm_runtime.h> +#endif #include "mali_osk.h" #include "mali_uk_types.h" -#include "mali_pmm.h" -#include "mali_ukk.h" #include "mali_kernel_common.h" #include "mali_kernel_license.h" -#include "mali_kernel_pm.h" -#include "mali_device_pause_resume.h" #include "mali_linux_pm.h" +#include "mali_pm.h" +#include "mali_platform.h" -#ifdef MALI_REBOOTNOTIFIER -_mali_osk_atomic_t mali_shutdown_state; -#include <linux/reboot.h> +#if ! MALI_LICENSE_IS_GPL +#undef CONFIG_PM_RUNTIME #endif -#if MALI_GPU_UTILIZATION -#include "mali_kernel_utilization.h" -#endif /* MALI_GPU_UTILIZATION */ - -#if MALI_POWER_MGMT_TEST_SUITE -#ifdef CONFIG_PM -#include "mali_linux_pm_testsuite.h" -#include "mali_platform_pmu_internal_testing.h" -unsigned int pwr_mgmt_status_reg = 0; -#endif /* CONFIG_PM */ -#endif /* MALI_POWER_MGMT_TEST_SUITE */ - -static int is_os_pmm_thread_waiting = 0; - -/* kernel should be configured with power management support */ -#ifdef CONFIG_PM - -/* License should be GPL */ -#if MALI_LICENSE_IS_GPL - -/* Linux kernel major version */ -#define LINUX_KERNEL_MAJOR_VERSION 2 - -/* Linux kernel minor version */ -#define LINUX_KERNEL_MINOR_VERSION 6 - -/* Linux kernel development version */ -#define LINUX_KERNEL_DEVELOPMENT_VERSION 29 - -#ifdef CONFIG_PM_DEBUG -static const char* const mali_states[_MALI_MAX_DEBUG_OPERATIONS] = { - [_MALI_DEVICE_SUSPEND] = "suspend", - [_MALI_DEVICE_RESUME] = "resume", - [_MALI_DVFS_PAUSE_EVENT] = "dvfs_pause", - [_MALI_DVFS_RESUME_EVENT] = "dvfs_resume", -}; - -#endif /* CONFIG_PM_DEBUG */ - #if MALI_PMM_RUNTIME_JOB_CONTROL_ON extern void set_mali_parent_power_domain(struct platform_device* dev); #endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */ +static int mali_probe(struct platform_device *pdev); +static int mali_remove(struct platform_device *pdev); #ifdef CONFIG_PM_RUNTIME -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON -static int mali_pwr_suspend_notifier(struct notifier_block *nb,unsigned long event,void* dummy); - -static struct notifier_block mali_pwr_notif_block = { - .notifier_call = mali_pwr_suspend_notifier -}; -#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */ -#endif /* CONFIG_PM_RUNTIME */ - -/* Power management thread pointer */ -struct task_struct *pm_thread; - -/* dvfs power management thread */ -struct task_struct *dvfs_pm_thread; - -/* is wake up needed */ -short is_wake_up_needed = 0; -int timeout_fired = 2; -unsigned int is_mali_pmm_testsuite_enabled = 0; - -_mali_device_power_states mali_device_state = _MALI_DEVICE_RESUME; -_mali_device_power_states mali_dvfs_device_state = _MALI_DEVICE_RESUME; -_mali_osk_lock_t *lock; - -#if MALI_POWER_MGMT_TEST_SUITE - -const char* const mali_pmm_recording_events[_MALI_DEVICE_MAX_PMM_EVENTS] = { - [_MALI_DEVICE_PMM_TIMEOUT_EVENT] = "timeout", - [_MALI_DEVICE_PMM_JOB_SCHEDULING_EVENTS] = "job_scheduling", - [_MALI_DEVICE_PMM_REGISTERED_CORES] = "cores", - -}; - -unsigned int mali_timeout_event_recording_on = 0; -unsigned int mali_job_scheduling_events_recording_on = 0; -unsigned int is_mali_pmu_present = 0; -#endif /* MALI_POWER_MGMT_TEST_SUITE */ - -/* Function prototypes */ -static int mali_pm_probe(struct platform_device *pdev); -static int mali_pm_remove(struct platform_device *pdev); -static void mali_pm_shutdown(struct platform_device *pdev); - -/* Mali device suspend function */ -static int mali_pm_suspend(struct device *dev); - -/* Mali device resume function */ -static int mali_pm_resume(struct device *dev); - -/* Run time suspend and resume functions */ -#ifdef CONFIG_PM_RUNTIME -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON -static int mali_device_runtime_suspend(struct device *dev); -static int mali_device_runtime_resume(struct device *dev); -#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */ -#endif /* CONFIG_PM_RUNTIME */ - -/* OS suspend and resume callbacks */ -#if !MALI_PMM_RUNTIME_JOB_CONTROL_ON -#ifndef CONFIG_PM_RUNTIME -#if (LINUX_VERSION_CODE < KERNEL_VERSION(LINUX_KERNEL_MAJOR_VERSION,LINUX_KERNEL_MINOR_VERSION,LINUX_KERNEL_DEVELOPMENT_VERSION)) -static int mali_pm_os_suspend(struct platform_device *pdev, pm_message_t state); -#else -static int mali_pm_os_suspend(struct device *dev); +static int mali_runtime_suspend(struct device *dev); +static int mali_runtime_resume(struct device *dev); #endif -#if (LINUX_VERSION_CODE < KERNEL_VERSION(LINUX_KERNEL_MAJOR_VERSION,LINUX_KERNEL_MINOR_VERSION,LINUX_KERNEL_DEVELOPMENT_VERSION)) -static int mali_pm_os_resume(struct platform_device *pdev); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)) +static int mali_os_suspend(struct platform_device *pdev, pm_message_t state); +static int mali_os_resume(struct platform_device *pdev); #else -static int mali_pm_os_resume(struct device *dev); +static int mali_os_suspend(struct device *dev); +static int mali_os_resume(struct device *dev); #endif -#endif /* CONFIG_PM_RUNTIME */ -#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */ - -/* OS Hibernation suspend callback */ -static int mali_pm_os_suspend_on_hibernation(struct device *dev); - -/* OS Hibernation resume callback */ -static int mali_pm_os_resume_on_hibernation(struct device *dev); - -static void _mali_release_pm(struct device* device); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(LINUX_KERNEL_MAJOR_VERSION,LINUX_KERNEL_MINOR_VERSION,LINUX_KERNEL_DEVELOPMENT_VERSION)) -static const struct dev_pm_ops mali_dev_pm_ops = { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) +static const struct dev_pm_ops mali_dev_pm_ops = +{ #ifdef CONFIG_PM_RUNTIME -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON - .runtime_suspend = mali_device_runtime_suspend, - .runtime_resume = mali_device_runtime_resume, -#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */ -#endif /* CONFIG_PM_RUNTIME */ - -#ifndef CONFIG_PM_RUNTIME -#if !MALI_PMM_RUNTIME_JOB_CONTROL_ON - .suspend = mali_pm_os_suspend, - .resume = mali_pm_os_resume, -#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */ -#endif /* CONFIG_PM_RUNTIME */ - .freeze = mali_pm_os_suspend_on_hibernation, - .poweroff = mali_pm_os_suspend_on_hibernation, - .thaw = mali_pm_os_resume_on_hibernation, - .restore = mali_pm_os_resume_on_hibernation, -}; + .runtime_suspend = mali_runtime_suspend, + .runtime_resume = mali_runtime_resume, + .runtime_idle = NULL, +#else + .suspend = mali_os_suspend, + .resume = mali_os_resume, #endif -#if (LINUX_VERSION_CODE < KERNEL_VERSION(LINUX_KERNEL_MAJOR_VERSION,LINUX_KERNEL_MINOR_VERSION,LINUX_KERNEL_DEVELOPMENT_VERSION)) -struct pm_ext_ops mali_pm_operations = { - .base = { - .freeze = mali_pm_os_suspend_on_hibernation, - .thaw = mali_pm_os_resume_on_hibernation, - .poweroff = mali_pm_os_resume_on_hibernation, - .restore = mali_pm_os_resume_on_hibernation, + .freeze = mali_os_suspend, + .poweroff = mali_os_suspend, + .thaw = mali_os_resume, + .restore = mali_os_resume, +}; +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)) +struct pm_ext_ops mali_ext_pm_operations = +{ + .base = + { + .freeze = mali_os_suspend, + .thaw = mali_os_resume, + .poweroff = mali_os_suspend, + .restore = mali_os_resume, }, }; #endif -static struct platform_driver mali_plat_driver = { - .probe = mali_pm_probe, - .remove = mali_pm_remove, - .shutdown = mali_pm_shutdown, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(LINUX_KERNEL_MAJOR_VERSION,LINUX_KERNEL_MINOR_VERSION,LINUX_KERNEL_DEVELOPMENT_VERSION)) -#ifndef CONFIG_PM_RUNTIME -#if !MALI_PMM_RUNTIME_JOB_CONTROL_ON - .suspend = mali_pm_os_suspend, - .resume = mali_pm_os_resume, -#endif /* CONFIG_PM_RUNTIME */ -#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */ - .pm = &mali_pm_operations, + +static struct platform_driver mali_plat_driver = +{ + .probe = mali_probe, + .remove = mali_remove, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)) + .suspend = mali_os_suspend, + .resume = mali_os_resume, + .pm = &mali_ext_pm_operations, #endif - .driver = { + .driver = + { .name = "mali_dev", .owner = THIS_MODULE, +#if MALI_LICENSE_IS_GPL .bus = &platform_bus_type, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(LINUX_KERNEL_MAJOR_VERSION,LINUX_KERNEL_MINOR_VERSION,LINUX_KERNEL_DEVELOPMENT_VERSION)) +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) .pm = &mali_dev_pm_ops, #endif - }, + }, }; -/* Mali GPU platform device */ -struct platform_device mali_gpu_device = { - .name = "mali_dev", - .id = 0, - .dev.release = _mali_release_pm +#ifdef CONFIG_PM_RUNTIME +static int mali_pwr_suspend_notifier(struct notifier_block *nb,unsigned long event,void* dummy); + +static struct notifier_block mali_pwr_notif_block = +{ + .notifier_call = mali_pwr_suspend_notifier }; +#endif /** This function is called when platform device is unregistered. This function * is necessary when the platform device is unregistered. */ static void _mali_release_pm(struct device *device) { - MALI_DEBUG_PRINT(4, ("OSPMM: MALI Platform device removed\n" )); } - -#if MALI_POWER_MGMT_TEST_SUITE -void mali_is_pmu_present(void) +struct platform_device mali_gpu_device = { - int temp = 0; - temp = pmu_get_power_up_down_info(); - if (4095 == temp) - { - is_mali_pmu_present = 0; - } - else - { - is_mali_pmu_present = 1; - } -} -#endif /* MALI_POWER_MGMT_TEST_SUITE */ -#endif /* MALI_LICENSE_IS_GPL */ - -#if MALI_LICENSE_IS_GPL - -static int mali_wait_for_power_management_policy_event(void) -{ - int err = 0; - for (; ;) - { - set_current_state(TASK_INTERRUPTIBLE); - if (signal_pending(current)) - { - err = -EINTR; - break; - } - if (is_wake_up_needed == 1) - { - break; - } - schedule(); - } - __set_current_state(TASK_RUNNING); - is_wake_up_needed =0; - return err; -} + .name = "mali_dev", + .id = 0, + .dev.release = _mali_release_pm +}; -/** This function is invoked when mali device is suspended - */ -int mali_device_suspend(unsigned int event_id, struct task_struct **pwr_mgmt_thread) +/** This function is called when the device is probed */ +static int mali_probe(struct platform_device *pdev) { - int err = 0; - _mali_uk_pmm_message_s event = { - NULL, - event_id, - timeout_fired}; - *pwr_mgmt_thread = current; - MALI_DEBUG_PRINT(4, ("OSPMM: MALI device is being suspended\n" )); - _mali_ukk_pmm_event_message(&event); - is_os_pmm_thread_waiting = 1; - err = mali_wait_for_power_management_policy_event(); - is_os_pmm_thread_waiting = 0; - return err; + return 0; } -/** This function is called when Operating system wants to power down - * the mali GPU device. - */ -static int mali_pm_suspend(struct device *dev) +static int mali_remove(struct platform_device *pdev) { - int err = 0; - _mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW); - if ((mali_device_state == _MALI_DEVICE_SUSPEND)) - { - _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW); - return err; - } -#if MALI_DVFS_ENABLED - mali_utilization_suspend(); -#endif - err = mali_device_suspend(MALI_PMM_EVENT_OS_POWER_DOWN, &pm_thread); - mali_device_state = _MALI_DEVICE_SUSPEND; - _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW); - return err; -} - -#ifndef CONFIG_PM_RUNTIME -#if !MALI_PMM_RUNTIME_JOB_CONTROL_ON -#if (LINUX_VERSION_CODE < KERNEL_VERSION(LINUX_KERNEL_MAJOR_VERSION,LINUX_KERNEL_MINOR_VERSION,LINUX_KERNEL_DEVELOPMENT_VERSION)) -static int mali_pm_os_suspend(struct platform_device *pdev, pm_message_t state) -#else -static int mali_pm_os_suspend(struct device *dev) +#ifdef CONFIG_PM_RUNTIME + pm_runtime_disable(&pdev->dev); #endif -{ - int err = 0; - err = mali_pm_suspend(NULL); - return err; + return 0; } -#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */ -#endif /* CONFIG_PM_RUNTIME */ #ifdef CONFIG_PM_RUNTIME -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON static int mali_pwr_suspend_notifier(struct notifier_block *nb,unsigned long event,void* dummy) { - int err = 0; switch (event) { case PM_SUSPEND_PREPARE: - err = mali_pm_suspend(NULL); - break; - + MALI_DEBUG_PRINT(2, ("mali_pwr_suspend_notifier(PM_SUSPEND_PREPARE) called\n")); + mali_pm_os_suspend(); + break; case PM_POST_SUSPEND: - err = mali_pm_resume(NULL); - break; + MALI_DEBUG_PRINT(2, ("mali_pwr_suspend_notifier(PM_SUSPEND_PREPARE) called\n")); + mali_pm_os_resume(); + break; default: - break; + break; } return 0; } -#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */ -#endif /* CONFIG_PM_RUNTIME */ - -/** This function is called when mali GPU device is to be resumed. - */ -int mali_device_resume(unsigned int event_id, struct task_struct **pwr_mgmt_thread) -{ - int err = 0; - _mali_uk_pmm_message_s event = { - NULL, - event_id, - timeout_fired}; - *pwr_mgmt_thread = current; - MALI_DEBUG_PRINT(4, ("OSPMM: MALI device is being resumed\n" )); - _mali_ukk_pmm_event_message(&event); - MALI_DEBUG_PRINT(4, ("OSPMM: MALI Power up event is scheduled\n" )); - is_os_pmm_thread_waiting = 1; - err = mali_wait_for_power_management_policy_event(); - is_os_pmm_thread_waiting = 0; - return err; -} - -/** This function is called when mali GPU device is to be resumed - */ -static int mali_pm_resume(struct device *dev) -{ - int err = 0; - - _mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW); - -#ifdef CONFIG_REGULATOR - mali_regulator_enable(); -#endif - - if (mali_device_state == _MALI_DEVICE_RESUME) - { - _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW); - return err; - } - err = mali_device_resume(MALI_PMM_EVENT_OS_POWER_UP, &pm_thread); - mali_device_state = _MALI_DEVICE_RESUME; - mali_dvfs_device_state = _MALI_DEVICE_RESUME; - _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW); - return err; -} - -#ifndef CONFIG_PM_RUNTIME -#if !MALI_PMM_RUNTIME_JOB_CONTROL_ON -#if (LINUX_VERSION_CODE < KERNEL_VERSION(LINUX_KERNEL_MAJOR_VERSION,LINUX_KERNEL_MINOR_VERSION,LINUX_KERNEL_DEVELOPMENT_VERSION)) -static int mali_pm_os_resume(struct platform_device *pdev) -#else -static int mali_pm_os_resume(struct device *dev) #endif -{ - int err = 0; - err = mali_pm_resume(NULL); - return err; -} -#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */ -#endif /* CONFIG_PM_RUNTIME */ - -static int mali_pm_os_suspend_on_hibernation(struct device *dev) -{ - int err = 0; - err = mali_pm_suspend(NULL); - return err; -} -static int mali_pm_os_resume_on_hibernation(struct device *dev) -{ - int err = 0; - err = mali_pm_resume(NULL); - return err; -} #ifdef CONFIG_PM_RUNTIME -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON -/** This function is called when runtime suspend of mali device is required. - */ -static int mali_device_runtime_suspend(struct device *dev) -{ - MALI_DEBUG_PRINT(4, ("PMMDEBUG: Mali device Run time suspended \n" )); - return 0; -} -/** This function is called when runtime resume of mali device is required. - */ -static int mali_device_runtime_resume(struct device *dev) +static int mali_runtime_suspend(struct device *dev) { - MALI_DEBUG_PRINT(4, ("PMMDEBUG: Mali device Run time Resumed \n" )); - return 0; + MALI_DEBUG_PRINT(3, ("mali_runtime_suspend() called\n")); + mali_pm_runtime_suspend(); + return 0; /* all ok */ } -#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */ -#endif /* CONFIG_PM_RUNTIME */ -#ifdef CONFIG_PM_DEBUG - -/** This function is used for debugging purposes when the user want to see - * which power management operations are supported for - * mali device. - */ -static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf) +static int mali_runtime_resume(struct device *dev) { - char *str = buf; -#if !MALI_POWER_MGMT_TEST_SUITE - int pm_counter = 0; - for (pm_counter = 0; pm_counter<_MALI_MAX_DEBUG_OPERATIONS; pm_counter++) - { - str += sprintf(str, "%s ", mali_states[pm_counter]); - } -#else - str += sprintf(str, "%d ",pwr_mgmt_status_reg); -#endif - if (str != buf) - { - *(str-1) = '\n'; - } - return (str-buf); + MALI_DEBUG_PRINT(3, ("mali_runtime_resume() called\n")); + mali_pm_runtime_resume(); + return 0; /* all ok */ } -/** This function is called when user wants to suspend the mali GPU device in order - * to simulate the power up and power down events. - */ -static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - int err = 0; - -#if MALI_POWER_MGMT_TEST_SUITE - int test_flag_dvfs = 0; - pwr_mgmt_status_reg = 0; - mali_is_pmu_present(); - #endif - if (!strncmp(buf,mali_states[_MALI_DEVICE_SUSPEND],strlen(mali_states[_MALI_DEVICE_SUSPEND]))) - { - MALI_DEBUG_PRINT(4, ("PMMDEBUG: MALI suspend Power operation is scheduled\n" )); - err = mali_pm_suspend(NULL); - } -#if MALI_POWER_MGMT_TEST_SUITE - else if (!strncmp(buf,mali_pmm_recording_events[_MALI_DEVICE_PMM_REGISTERED_CORES],strlen(mali_pmm_recording_events[_MALI_DEVICE_PMM_REGISTERED_CORES]))) - { - MALI_DEBUG_PRINT(4, ("PMMDEBUG: MALI Device get number of registerd cores\n" )); - pwr_mgmt_status_reg = _mali_pmm_cores_list(); - return count; - } - else if (!strncmp(buf,mali_pmm_recording_events[_MALI_DEVICE_PMM_TIMEOUT_EVENT],strlen(mali_pmm_recording_events[_MALI_DEVICE_PMM_TIMEOUT_EVENT]))) - { - MALI_DEBUG_PRINT(4, ("PMMDEBUG: MALI timeout event recording is enabled\n" )); - mali_timeout_event_recording_on = 1; - } - else if (!strncmp(buf,mali_pmm_recording_events[_MALI_DEVICE_PMM_JOB_SCHEDULING_EVENTS],strlen(mali_pmm_recording_events[_MALI_DEVICE_PMM_JOB_SCHEDULING_EVENTS]))) - { - MALI_DEBUG_PRINT(4, ("PMMDEBUG: MALI Job scheduling events recording is enabled\n" )); - mali_job_scheduling_events_recording_on = 1; - } -#endif /* MALI_POWER_MGMT_TEST_SUITE */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)) - else if (!strncmp(buf,mali_states[_MALI_DEVICE_RESUME],strlen(mali_states[_MALI_DEVICE_RESUME]))) - { - MALI_DEBUG_PRINT(4, ("PMMDEBUG: MALI Resume Power operation is scheduled\n" )); - err = mali_pm_resume(NULL); - } - else if (!strncmp(buf,mali_states[_MALI_DVFS_PAUSE_EVENT],strlen(mali_states[_MALI_DVFS_PAUSE_EVENT]))) - { - MALI_DEBUG_PRINT(4, ("PMMDEBUG: MALI DVFS Pause Power operation is scheduled\n" )); - err = mali_dev_pause(); -#if MALI_POWER_MGMT_TEST_SUITE - test_flag_dvfs = 1; -#endif /* MALI_POWER_MGMT_TEST_SUITE */ - } - else if (!strncmp(buf,mali_states[_MALI_DVFS_RESUME_EVENT],strlen(mali_states[_MALI_DVFS_RESUME_EVENT]))) - { - MALI_DEBUG_PRINT(4, ("PMMDEBUG: MALI DVFS Resume Power operation is scheduled\n" )); - err = mali_dev_resume(); -#if MALI_POWER_MGMT_TEST_SUITE - test_flag_dvfs = 1; -#endif /* MALI_POWER_MGMT_TEST_SUITE */ - } - else - { - MALI_DEBUG_PRINT(4, ("PMMDEBUG: Invalid Power Mode Operation selected\n" )); - } -#if MALI_POWER_MGMT_TEST_SUITE - if (test_flag_dvfs == 1) - { - if (err) - { - pwr_mgmt_status_reg = 2; - } - else - { - pwr_mgmt_status_reg = 1; - } - } - else - { - if (1 == is_mali_pmu_present) - { - pwr_mgmt_status_reg = pmu_get_power_up_down_info(); - } - } -#endif /* MALI_POWER_MGMT_TEST_SUITE */ - return count; -} - -/* Device attribute file */ -static DEVICE_ATTR(file, 0644, show_file, store_file); -#endif /* CONFIG_PM_DEBUG */ - -static int mali_pm_remove(struct platform_device *pdev) +static int mali_os_suspend(struct platform_device *pdev, pm_message_t state) { -#ifdef CONFIG_PM_DEBUG - device_remove_file(&mali_gpu_device.dev, &dev_attr_file); -#endif /* CONFIG_PM_DEBUG */ -#ifdef CONFIG_PM_RUNTIME -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON - pm_runtime_disable(&pdev->dev); -#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */ -#endif /* CONFIG_PM_RUNTIME */ - return 0; + MALI_DEBUG_PRINT(3, ("mali_os_suspend(old) called\n")); + mali_pm_os_suspend(); + return 0; /* all ok */ } -int mali_pd_enable(void) +static int mali_os_resume(struct platform_device *pdev) { - return exynos_pd_enable(&exynos4_device_pd[PD_G3D].dev); + MALI_DEBUG_PRINT(3, ("mali_os_resume(old) called\n")); + mali_pm_os_resume(); + return 0; /* all ok */ } -static void mali_pm_shutdown(struct platform_device *pdev) -{ - MALI_PRINT(("Mali shutdown!!\n")); - mali_dvfs_device_state =_MALI_DEVICE_SHUTDOWN; - exynos_pd_enable(&exynos4_device_pd[PD_G3D].dev); - return; -} +#else -/** This function is called when the device is probed */ -static int mali_pm_probe(struct platform_device *pdev) +static int mali_os_suspend(struct device *dev) { -#ifdef CONFIG_PM_DEBUG - int err; - err = device_create_file(&mali_gpu_device.dev, &dev_attr_file); - if (err) - { - MALI_DEBUG_PRINT(4, ("PMMDEBUG: Error in creating device file\n" )); - } -#endif /* CONFIG_PM_DEBUG */ - return 0; + MALI_DEBUG_PRINT(3, ("mali_os_suspend(new) called\n")); + mali_pm_os_suspend(); + return 0; /* all ok */ } -#ifdef MALI_REBOOTNOTIFIER -static int mali_reboot_notify(struct notifier_block *this, - unsigned long code, void *unused) + +static int mali_os_resume(struct device *dev) { - _mali_osk_atomic_inc_return(&mali_shutdown_state); - mali_dvfs_device_state = _MALI_DEVICE_SHUTDOWN; - MALI_PRINT(("REBOOT Notifier for mali\n")); - return NOTIFY_DONE; + MALI_DEBUG_PRINT(3, ("mali_os_resume(new) called\n")); + mali_pm_os_resume(); + return 0; /* all ok */ } -static struct notifier_block mali_reboot_notifier = { - .notifier_call = mali_reboot_notify, -}; + #endif /** This function is called when Mali GPU device is initialized @@ -626,50 +222,34 @@ static struct notifier_block mali_reboot_notifier = { int _mali_dev_platform_register(void) { int err; -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON + +#ifdef CONFIG_PM_RUNTIME set_mali_parent_power_domain((void *)&mali_gpu_device); #endif #ifdef CONFIG_PM_RUNTIME -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON err = register_pm_notifier(&mali_pwr_notif_block); if (err) { return err; } -#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */ -#endif /* CONFIG_PM_RUNTIME */ - -#ifdef MALI_REBOOTNOTIFIER - _mali_osk_atomic_init(&mali_shutdown_state, 0); - err = register_reboot_notifier(&mali_reboot_notifier); - if (err) { - MALI_PRINT(("Failed to setup reboot notifier\n")); - return err; - } #endif +#if MALI_LICENSE_IS_GPL err = platform_device_register(&mali_gpu_device); - lock = _mali_osk_lock_init((_mali_osk_lock_flags_t)( _MALI_OSK_LOCKFLAG_READERWRITER | _MALI_OSK_LOCKFLAG_ORDERED), 0, 0); if (!err) { err = platform_driver_register(&mali_plat_driver); if (err) { - _mali_osk_lock_term(lock); #ifdef CONFIG_PM_RUNTIME -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON unregister_pm_notifier(&mali_pwr_notif_block); -#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */ -#endif /* CONFIG_PM_RUNTIME */ - -#ifdef MALI_REBOOTNOTIFIER - unregister_reboot_notifier(&mali_reboot_notifier); #endif - platform_device_unregister(&mali_gpu_device); } } +#endif + return err; } @@ -677,33 +257,12 @@ int _mali_dev_platform_register(void) */ void _mali_dev_platform_unregister(void) { - _mali_osk_lock_term(lock); - #ifdef CONFIG_PM_RUNTIME -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON unregister_pm_notifier(&mali_pwr_notif_block); -#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */ -#endif /* CONFIG_PM_RUNTIME */ - -#ifdef MALI_REBOOTNOTIFIER - unregister_reboot_notifier(&mali_reboot_notifier); #endif + +#if MALI_LICENSE_IS_GPL platform_driver_unregister(&mali_plat_driver); platform_device_unregister(&mali_gpu_device); +#endif } - -int mali_get_ospmm_thread_state(void) -{ - return is_os_pmm_thread_waiting; -} - -#endif /* MALI_LICENSE_IS_GPL */ -#endif /* CONFIG_PM */ - -#if MALI_STATE_TRACKING -u32 mali_pmm_dump_os_thread_state( char *buf, u32 size ) -{ - return snprintf(buf, size, "OSPMM: OS PMM thread is waiting: %s\n", is_os_pmm_thread_waiting ? "true" : "false"); -} -#endif /* MALI_STATE_TRACKING */ -#endif /* USING_MALI_PMM */ diff --git a/drivers/media/video/samsung/mali/linux/mali_kernel_pm.h b/drivers/media/video/samsung/mali/linux/mali_kernel_pm.h index 1c44439..6ef7270 100644 --- a/drivers/media/video/samsung/mali/linux/mali_kernel_pm.h +++ b/drivers/media/video/samsung/mali/linux/mali_kernel_pm.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010, 2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -11,10 +11,7 @@ #ifndef __MALI_KERNEL_PM_H__ #define __MALI_KERNEL_PM_H__ -#ifdef USING_MALI_PMM int _mali_dev_platform_register(void); void _mali_dev_platform_unregister(void); -#endif /* USING_MALI_PMM */ -int mali_pd_enable(void); #endif /* __MALI_KERNEL_PM_H__ */ diff --git a/drivers/media/video/samsung/mali/linux/mali_kernel_sysfs.c b/drivers/media/video/samsung/mali/linux/mali_kernel_sysfs.c index 6dcf052..64853d7 100644 --- a/drivers/media/video/samsung/mali/linux/mali_kernel_sysfs.c +++ b/drivers/media/video/samsung/mali/linux/mali_kernel_sysfs.c @@ -1,5 +1,5 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. +/** + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -14,9 +14,14 @@ * Implementation of some sysfs data exports */ +#include <linux/kernel.h> #include <linux/fs.h> #include <linux/device.h> +#include <linux/version.h> +#include <linux/module.h> +#include <linux/slab.h> #include "mali_kernel_license.h" +#include "mali_kernel_common.h" #include "mali_kernel_linux.h" #include "mali_ukk.h" @@ -25,13 +30,721 @@ #include <linux/seq_file.h> #include <linux/debugfs.h> #include <asm/uaccess.h> -#include <linux/slab.h> -#include "mali_kernel_subsystem.h" +#include <linux/module.h> #include "mali_kernel_sysfs.h" -#include "mali_kernel_profiling.h" +#if MALI_INTERNAL_TIMELINE_PROFILING_ENABLED +#include <linux/slab.h> +#include "mali_osk_profiling.h" +#endif +#include "mali_pm.h" +#include "mali_cluster.h" +#include "mali_group.h" +#include "mali_gp.h" +#include "mali_pp.h" +#include "mali_l2_cache.h" +#include "mali_hw_core.h" +#include "mali_kernel_core.h" +#include "mali_user_settings_db.h" +#include "mali_device_pause_resume.h" + +#define POWER_BUFFER_SIZE 3 static struct dentry *mali_debugfs_dir = NULL; +typedef enum +{ + _MALI_DEVICE_SUSPEND, + _MALI_DEVICE_RESUME, + _MALI_DEVICE_DVFS_PAUSE, + _MALI_DEVICE_DVFS_RESUME, + _MALI_MAX_EVENTS +} _mali_device_debug_power_events; + +static const char* const mali_power_events[_MALI_MAX_EVENTS] = { + [_MALI_DEVICE_SUSPEND] = "suspend", + [_MALI_DEVICE_RESUME] = "resume", + [_MALI_DEVICE_DVFS_PAUSE] = "dvfs_pause", + [_MALI_DEVICE_DVFS_RESUME] = "dvfs_resume", +}; + +static u32 virtual_power_status_register=0; +static char pwr_buf[POWER_BUFFER_SIZE]; + +static int open_copy_private_data(struct inode *inode, struct file *filp) +{ + filp->private_data = inode->i_private; + return 0; +} + +static ssize_t gp_gpx_counter_srcx_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *gpos, u32 src_id) +{ + char buf[64]; + int r; + u32 val; + struct mali_gp_core *gp_core = (struct mali_gp_core *)filp->private_data; + + if (0 == src_id) + { + val = mali_gp_core_get_counter_src0(gp_core); + } + else + { + val = mali_gp_core_get_counter_src1(gp_core); + } + + if (MALI_HW_CORE_NO_COUNTER == val) + { + r = sprintf(buf, "-1\n"); + } + else + { + r = sprintf(buf, "%u\n", val); + } + return simple_read_from_buffer(ubuf, cnt, gpos, buf, r); +} + +static ssize_t gp_gpx_counter_srcx_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *gpos, u32 src_id) +{ + struct mali_gp_core *gp_core = (struct mali_gp_core *)filp->private_data; + char buf[64]; + long val; + int ret; + + if (cnt >= sizeof(buf)) + { + return -EINVAL; + } + + if (copy_from_user(&buf, ubuf, cnt)) + { + return -EFAULT; + } + + buf[cnt] = 0; + + ret = strict_strtol(buf, 10, &val); + if (ret < 0) + { + return ret; + } + + if (val < 0) + { + /* any negative input will disable counter */ + val = MALI_HW_CORE_NO_COUNTER; + } + + if (0 == src_id) + { + if (MALI_TRUE != mali_gp_core_set_counter_src0(gp_core, (u32)val)) + { + return 0; + } + } + else + { + if (MALI_TRUE != mali_gp_core_set_counter_src1(gp_core, (u32)val)) + { + return 0; + } + } + + *gpos += cnt; + return cnt; +} + +static ssize_t gp_all_counter_srcx_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *gpos, u32 src_id) +{ + char buf[64]; + long val; + int ret; + u32 ci; + struct mali_cluster *cluster; + + if (cnt >= sizeof(buf)) + { + return -EINVAL; + } + + if (copy_from_user(&buf, ubuf, cnt)) + { + return -EFAULT; + } + + buf[cnt] = 0; + + ret = strict_strtol(buf, 10, &val); + if (ret < 0) + { + return ret; + } + + if (val < 0) + { + /* any negative input will disable counter */ + val = MALI_HW_CORE_NO_COUNTER; + } + + ci = 0; + cluster = mali_cluster_get_global_cluster(ci); + while (NULL != cluster) + { + u32 gi = 0; + struct mali_group *group = mali_cluster_get_group(cluster, gi); + while (NULL != group) + { + struct mali_gp_core *gp_core = mali_group_get_gp_core(group); + if (NULL != gp_core) + { + if (0 == src_id) + { + if (MALI_TRUE != mali_gp_core_set_counter_src0(gp_core, (u32)val)) + { + return 0; + } + } + else + { + if (MALI_TRUE != mali_gp_core_set_counter_src1(gp_core, (u32)val)) + { + return 0; + } + } + } + + /* try next group */ + gi++; + group = mali_cluster_get_group(cluster, gi); + } + + /* try next cluster */ + ci++; + cluster = mali_cluster_get_global_cluster(ci); + } + + *gpos += cnt; + return cnt; +} + +static ssize_t gp_gpx_counter_src0_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *gpos) +{ + return gp_gpx_counter_srcx_read(filp, ubuf, cnt, gpos, 0); +} + +static ssize_t gp_gpx_counter_src1_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *gpos) +{ + return gp_gpx_counter_srcx_read(filp, ubuf, cnt, gpos, 1); +} + +static ssize_t gp_gpx_counter_src0_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *gpos) +{ + return gp_gpx_counter_srcx_write(filp, ubuf, cnt, gpos, 0); +} + +static ssize_t gp_gpx_counter_src1_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *gpos) +{ + return gp_gpx_counter_srcx_write(filp, ubuf, cnt, gpos, 1); +} + +static ssize_t gp_all_counter_src0_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *gpos) +{ + return gp_all_counter_srcx_write(filp, ubuf, cnt, gpos, 0); +} + +static ssize_t gp_all_counter_src1_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *gpos) +{ + return gp_all_counter_srcx_write(filp, ubuf, cnt, gpos, 1); +} + +static const struct file_operations gp_gpx_counter_src0_fops = { + .owner = THIS_MODULE, + .open = open_copy_private_data, + .read = gp_gpx_counter_src0_read, + .write = gp_gpx_counter_src0_write, +}; + +static const struct file_operations gp_gpx_counter_src1_fops = { + .owner = THIS_MODULE, + .open = open_copy_private_data, + .read = gp_gpx_counter_src1_read, + .write = gp_gpx_counter_src1_write, +}; + +static const struct file_operations gp_all_counter_src0_fops = { + .owner = THIS_MODULE, + .write = gp_all_counter_src0_write, +}; + +static const struct file_operations gp_all_counter_src1_fops = { + .owner = THIS_MODULE, + .write = gp_all_counter_src1_write, +}; + +static ssize_t pp_ppx_counter_srcx_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos, u32 src_id) +{ + char buf[64]; + int r; + u32 val; + struct mali_pp_core *pp_core = (struct mali_pp_core *)filp->private_data; + + if (0 == src_id) + { + val = mali_pp_core_get_counter_src0(pp_core); + } + else + { + val = mali_pp_core_get_counter_src1(pp_core); + } + + if (MALI_HW_CORE_NO_COUNTER == val) + { + r = sprintf(buf, "-1\n"); + } + else + { + r = sprintf(buf, "%u\n", val); + } + return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); +} + +static ssize_t pp_ppx_counter_srcx_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos, u32 src_id) +{ + struct mali_pp_core *pp_core = (struct mali_pp_core *)filp->private_data; + char buf[64]; + long val; + int ret; + + if (cnt >= sizeof(buf)) + { + return -EINVAL; + } + + if (copy_from_user(&buf, ubuf, cnt)) + { + return -EFAULT; + } + + buf[cnt] = 0; + + ret = strict_strtol(buf, 10, &val); + if (ret < 0) + { + return ret; + } + + if (val < 0) + { + /* any negative input will disable counter */ + val = MALI_HW_CORE_NO_COUNTER; + } + + if (0 == src_id) + { + if (MALI_TRUE != mali_pp_core_set_counter_src0(pp_core, (u32)val)) + { + return 0; + } + } + else + { + if (MALI_TRUE != mali_pp_core_set_counter_src1(pp_core, (u32)val)) + { + return 0; + } + } + + *ppos += cnt; + return cnt; +} + +static ssize_t pp_all_counter_srcx_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos, u32 src_id) +{ + char buf[64]; + long val; + int ret; + u32 ci; + struct mali_cluster *cluster; + + if (cnt >= sizeof(buf)) + { + return -EINVAL; + } + + if (copy_from_user(&buf, ubuf, cnt)) + { + return -EFAULT; + } + + buf[cnt] = 0; + + ret = strict_strtol(buf, 10, &val); + if (ret < 0) + { + return ret; + } + + if (val < 0) + { + /* any negative input will disable counter */ + val = MALI_HW_CORE_NO_COUNTER; + } + + ci = 0; + cluster = mali_cluster_get_global_cluster(ci); + while (NULL != cluster) + { + u32 gi = 0; + struct mali_group *group = mali_cluster_get_group(cluster, gi); + while (NULL != group) + { + struct mali_pp_core *pp_core = mali_group_get_pp_core(group); + if (NULL != pp_core) + { + if (0 == src_id) + { + if (MALI_TRUE != mali_pp_core_set_counter_src0(pp_core, (u32)val)) + { + return 0; + } + } + else + { + if (MALI_TRUE != mali_pp_core_set_counter_src1(pp_core, (u32)val)) + { + return 0; + } + } + } + + /* try next group */ + gi++; + group = mali_cluster_get_group(cluster, gi); + } + + /* try next cluster */ + ci++; + cluster = mali_cluster_get_global_cluster(ci); + } + + *ppos += cnt; + return cnt; +} + +static ssize_t pp_ppx_counter_src0_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) +{ + return pp_ppx_counter_srcx_read(filp, ubuf, cnt, ppos, 0); +} + +static ssize_t pp_ppx_counter_src1_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) +{ + return pp_ppx_counter_srcx_read(filp, ubuf, cnt, ppos, 1); +} + +static ssize_t pp_ppx_counter_src0_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + return pp_ppx_counter_srcx_write(filp, ubuf, cnt, ppos, 0); +} + +static ssize_t pp_ppx_counter_src1_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + return pp_ppx_counter_srcx_write(filp, ubuf, cnt, ppos, 1); +} + +static ssize_t pp_all_counter_src0_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + return pp_all_counter_srcx_write(filp, ubuf, cnt, ppos, 0); +} + +static ssize_t pp_all_counter_src1_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + return pp_all_counter_srcx_write(filp, ubuf, cnt, ppos, 1); +} + +static const struct file_operations pp_ppx_counter_src0_fops = { + .owner = THIS_MODULE, + .open = open_copy_private_data, + .read = pp_ppx_counter_src0_read, + .write = pp_ppx_counter_src0_write, +}; + +static const struct file_operations pp_ppx_counter_src1_fops = { + .owner = THIS_MODULE, + .open = open_copy_private_data, + .read = pp_ppx_counter_src1_read, + .write = pp_ppx_counter_src1_write, +}; + +static const struct file_operations pp_all_counter_src0_fops = { + .owner = THIS_MODULE, + .write = pp_all_counter_src0_write, +}; + +static const struct file_operations pp_all_counter_src1_fops = { + .owner = THIS_MODULE, + .write = pp_all_counter_src1_write, +}; + + + + + + +static ssize_t l2_l2x_counter_srcx_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos, u32 src_id) +{ + char buf[64]; + int r; + u32 val; + struct mali_l2_cache_core *l2_core = (struct mali_l2_cache_core *)filp->private_data; + + if (0 == src_id) + { + val = mali_l2_cache_core_get_counter_src0(l2_core); + } + else + { + val = mali_l2_cache_core_get_counter_src1(l2_core); + } + + if (MALI_HW_CORE_NO_COUNTER == val) + { + r = sprintf(buf, "-1\n"); + } + else + { + r = sprintf(buf, "%u\n", val); + } + return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); +} + +static ssize_t l2_l2x_counter_srcx_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos, u32 src_id) +{ + struct mali_l2_cache_core *l2_core = (struct mali_l2_cache_core *)filp->private_data; + char buf[64]; + long val; + int ret; + + if (cnt >= sizeof(buf)) + { + return -EINVAL; + } + + if (copy_from_user(&buf, ubuf, cnt)) + { + return -EFAULT; + } + + buf[cnt] = 0; + + ret = strict_strtol(buf, 10, &val); + if (ret < 0) + { + return ret; + } + + if (val < 0) + { + /* any negative input will disable counter */ + val = MALI_HW_CORE_NO_COUNTER; + } + + if (0 == src_id) + { + if (MALI_TRUE != mali_l2_cache_core_set_counter_src0(l2_core, (u32)val)) + { + return 0; + } + } + else + { + if (MALI_TRUE != mali_l2_cache_core_set_counter_src1(l2_core, (u32)val)) + { + return 0; + } + } + + *ppos += cnt; + return cnt; +} + +static ssize_t l2_all_counter_srcx_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos, u32 src_id) +{ + char buf[64]; + long val; + int ret; + u32 l2_id; + struct mali_l2_cache_core *l2_cache; + + if (cnt >= sizeof(buf)) + { + return -EINVAL; + } + + if (copy_from_user(&buf, ubuf, cnt)) + { + return -EFAULT; + } + + buf[cnt] = 0; + + ret = strict_strtol(buf, 10, &val); + if (ret < 0) + { + return ret; + } + + if (val < 0) + { + /* any negative input will disable counter */ + val = MALI_HW_CORE_NO_COUNTER; + } + + l2_id = 0; + l2_cache = mali_l2_cache_core_get_glob_l2_core(l2_id); + while (NULL != l2_cache) + { + if (0 == src_id) + { + if (MALI_TRUE != mali_l2_cache_core_set_counter_src0(l2_cache, (u32)val)) + { + return 0; + } + } + else + { + if (MALI_TRUE != mali_l2_cache_core_set_counter_src1(l2_cache, (u32)val)) + { + return 0; + } + } + + /* try next L2 */ + l2_id++; + l2_cache = mali_l2_cache_core_get_glob_l2_core(l2_id); + } + + *ppos += cnt; + return cnt; +} + +static ssize_t l2_l2x_counter_src0_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) +{ + return l2_l2x_counter_srcx_read(filp, ubuf, cnt, ppos, 0); +} + +static ssize_t l2_l2x_counter_src1_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) +{ + return l2_l2x_counter_srcx_read(filp, ubuf, cnt, ppos, 1); +} + +static ssize_t l2_l2x_counter_src0_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + return l2_l2x_counter_srcx_write(filp, ubuf, cnt, ppos, 0); +} + +static ssize_t l2_l2x_counter_src1_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + return l2_l2x_counter_srcx_write(filp, ubuf, cnt, ppos, 1); +} + +static ssize_t l2_all_counter_src0_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + return l2_all_counter_srcx_write(filp, ubuf, cnt, ppos, 0); +} + +static ssize_t l2_all_counter_src1_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + return l2_all_counter_srcx_write(filp, ubuf, cnt, ppos, 1); +} + +static const struct file_operations l2_l2x_counter_src0_fops = { + .owner = THIS_MODULE, + .open = open_copy_private_data, + .read = l2_l2x_counter_src0_read, + .write = l2_l2x_counter_src0_write, +}; + +static const struct file_operations l2_l2x_counter_src1_fops = { + .owner = THIS_MODULE, + .open = open_copy_private_data, + .read = l2_l2x_counter_src1_read, + .write = l2_l2x_counter_src1_write, +}; + +static const struct file_operations l2_all_counter_src0_fops = { + .owner = THIS_MODULE, + .write = l2_all_counter_src0_write, +}; + +static const struct file_operations l2_all_counter_src1_fops = { + .owner = THIS_MODULE, + .write = l2_all_counter_src1_write, +}; + +static ssize_t power_events_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) +{ + + memset(pwr_buf,0,POWER_BUFFER_SIZE); + virtual_power_status_register = 0; + if (!strncmp(ubuf,mali_power_events[_MALI_DEVICE_SUSPEND],strlen(mali_power_events[_MALI_DEVICE_SUSPEND]))) + { + mali_pm_os_suspend(); + /* @@@@ assuming currently suspend is successful later on to tune as per previous*/ + virtual_power_status_register =1; + + } + else if (!strncmp(ubuf,mali_power_events[_MALI_DEVICE_RESUME],strlen(mali_power_events[_MALI_DEVICE_RESUME]))) + { + mali_pm_os_resume(); + + /* @@@@ assuming currently resume is successful later on to tune as per previous */ + virtual_power_status_register = 1; + } + else if (!strncmp(ubuf,mali_power_events[_MALI_DEVICE_DVFS_PAUSE],strlen(mali_power_events[_MALI_DEVICE_DVFS_PAUSE]))) + { + mali_bool power_on; + mali_dev_pause(&power_on); + if (!power_on) + { + virtual_power_status_register = 2; + mali_dev_resume(); + } + else + { + /* @@@@ assuming currently resume is successful later on to tune as per previous */ + virtual_power_status_register =1; + } + } + else if (!strncmp(ubuf,mali_power_events[_MALI_DEVICE_DVFS_RESUME],strlen(mali_power_events[_MALI_DEVICE_DVFS_RESUME]))) + { + mali_dev_resume(); + /* @@@@ assuming currently resume is successful later on to tune as per previous */ + virtual_power_status_register = 1; + + } + *ppos += cnt; + sprintf(pwr_buf, "%d",virtual_power_status_register); + return cnt; +} + +static ssize_t power_events_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) +{ + return simple_read_from_buffer(ubuf, cnt, ppos, pwr_buf, POWER_BUFFER_SIZE); +} + +static loff_t power_events_seek(struct file *file, loff_t offset, int orig) +{ + file->f_pos = offset; + return 0; +} + +static const struct file_operations power_events_fops = { + .owner = THIS_MODULE, + .read = power_events_read, + .write = power_events_write, + .llseek = power_events_seek, +}; + + #if MALI_STATE_TRACKING static int mali_seq_internal_state_show(struct seq_file *seq_file, void *v) { @@ -72,13 +785,13 @@ static const struct file_operations mali_seq_internal_state_fops = { #endif /* MALI_STATE_TRACKING */ -#if MALI_TIMELINE_PROFILING_ENABLED +#if MALI_INTERNAL_TIMELINE_PROFILING_ENABLED static ssize_t profiling_record_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { char buf[64]; int r; - r = sprintf(buf, "%u\n", _mali_profiling_is_recording() ? 1 : 0); + r = sprintf(buf, "%u\n", _mali_osk_profiling_is_recording() ? 1 : 0); return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); } @@ -111,16 +824,16 @@ static ssize_t profiling_record_write(struct file *filp, const char __user *ubuf u32 limit = MALI_PROFILING_MAX_BUFFER_ENTRIES; /* This can be made configurable at a later stage if we need to */ /* check if we are already recording */ - if (MALI_TRUE == _mali_profiling_is_recording()) + if (MALI_TRUE == _mali_osk_profiling_is_recording()) { MALI_DEBUG_PRINT(3, ("Recording of profiling events already in progress\n")); return -EFAULT; } /* check if we need to clear out an old recording first */ - if (MALI_TRUE == _mali_profiling_have_recording()) + if (MALI_TRUE == _mali_osk_profiling_have_recording()) { - if (_MALI_OSK_ERR_OK != _mali_profiling_clear()) + if (_MALI_OSK_ERR_OK != _mali_osk_profiling_clear()) { MALI_DEBUG_PRINT(3, ("Failed to clear existing recording of profiling events\n")); return -EFAULT; @@ -128,7 +841,7 @@ static ssize_t profiling_record_write(struct file *filp, const char __user *ubuf } /* start recording profiling data */ - if (_MALI_OSK_ERR_OK != _mali_profiling_start(&limit)) + if (_MALI_OSK_ERR_OK != _mali_osk_profiling_start(&limit)) { MALI_DEBUG_PRINT(3, ("Failed to start recording of profiling events\n")); return -EFAULT; @@ -140,7 +853,7 @@ static ssize_t profiling_record_write(struct file *filp, const char __user *ubuf { /* stop recording profiling data */ u32 count = 0; - if (_MALI_OSK_ERR_OK != _mali_profiling_stop(&count)) + if (_MALI_OSK_ERR_OK != _mali_osk_profiling_stop(&count)) { MALI_DEBUG_PRINT(2, ("Failed to stop recording of profiling events\n")); return -EFAULT; @@ -164,7 +877,7 @@ static void *profiling_events_start(struct seq_file *s, loff_t *pos) loff_t *spos; /* check if we have data avaiable */ - if (MALI_TRUE != _mali_profiling_have_recording()) + if (MALI_TRUE != _mali_osk_profiling_have_recording()) { return NULL; } @@ -184,13 +897,13 @@ static void *profiling_events_next(struct seq_file *s, void *v, loff_t *pos) loff_t *spos = v; /* check if we have data avaiable */ - if (MALI_TRUE != _mali_profiling_have_recording()) + if (MALI_TRUE != _mali_osk_profiling_have_recording()) { return NULL; } /* check if the next entry actually is avaiable */ - if (_mali_profiling_get_count() <= (u32)(*spos + 1)) + if (_mali_osk_profiling_get_count() <= (u32)(*spos + 1)) { return NULL; } @@ -215,7 +928,7 @@ static int profiling_events_show(struct seq_file *seq_file, void *v) index = (u32)*spos; /* Retrieve all events */ - if (_MALI_OSK_ERR_OK == _mali_profiling_get_event(index, ×tamp, &event_id, data)) + if (_MALI_OSK_ERR_OK == _mali_osk_profiling_get_event(index, ×tamp, &event_id, data)) { seq_printf(seq_file, "%llu %u %u %u %u %u %u\n", timestamp, event_id, data[0], data[1], data[2], data[3], data[4]); return 0; @@ -243,68 +956,89 @@ static const struct file_operations profiling_events_fops = { .llseek = seq_lseek, .release = seq_release, }; +#endif -static ssize_t profiling_proc_default_enable_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) +static ssize_t memory_used_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { char buf[64]; - int r; + size_t r; + u32 mem = _mali_ukk_report_memory_usage(); - r = sprintf(buf, "%u\n", _mali_profiling_get_default_enable_state() ? 1 : 0); + r = snprintf(buf, 64, "%u\n", mem); return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); } -static ssize_t profiling_proc_default_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) +static const struct file_operations memory_usage_fops = { + .owner = THIS_MODULE, + .read = memory_used_read, +}; + + +static ssize_t user_settings_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) { - char buf[64]; unsigned long val; int ret; + _mali_uk_user_setting_t setting; + char buf[32]; - if (cnt >= sizeof(buf)) - { - return -EINVAL; - } - - if (copy_from_user(&buf, ubuf, cnt)) + cnt = min(cnt, sizeof(buf) - 1); + if (copy_from_user(buf, ubuf, cnt)) { return -EFAULT; } - - buf[cnt] = 0; + buf[cnt] = '\0'; ret = strict_strtoul(buf, 10, &val); - if (ret < 0) + if (0 != ret) { return ret; } - _mali_profiling_set_default_enable_state(val != 0 ? MALI_TRUE : MALI_FALSE); + /* Update setting */ + setting = (_mali_uk_user_setting_t)(filp->private_data); + mali_set_user_setting(setting, val); *ppos += cnt; return cnt; } -static const struct file_operations profiling_proc_default_enable_fops = { - .owner = THIS_MODULE, - .read = profiling_proc_default_enable_read, - .write = profiling_proc_default_enable_write, -}; -#endif - -static ssize_t memory_used_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) +static ssize_t user_settings_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { char buf[64]; size_t r; - u32 mem = _mali_ukk_report_memory_usage(); + u32 value; + _mali_uk_user_setting_t setting; - r = snprintf(buf, 64, "%u\n", mem); + setting = (_mali_uk_user_setting_t)(filp->private_data); + value = mali_get_user_setting(setting); + + r = snprintf(buf, 64, "%u\n", value); return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); } -static const struct file_operations memory_usage_fops = { +static const struct file_operations user_settings_fops = { .owner = THIS_MODULE, - .read = memory_used_read, + .open = open_copy_private_data, + .read = user_settings_read, + .write = user_settings_write, }; +static int mali_sysfs_user_settings_register(void) +{ + struct dentry *mali_user_settings_dir = debugfs_create_dir("userspace_settings", mali_debugfs_dir); + + if (mali_user_settings_dir != NULL) + { + int i; + for (i = 0; i < _MALI_UK_USER_SETTING_MAX; i++) + { + debugfs_create_file(_mali_uk_user_setting_descriptions[i], 0600, mali_user_settings_dir, (void*)i, &user_settings_fops); + } + } + + return 0; +} + int mali_sysfs_register(struct mali_dev *device, dev_t dev, const char *mali_dev_name) { int err = 0; @@ -334,8 +1068,151 @@ int mali_sysfs_register(struct mali_dev *device, dev_t dev, const char *mali_dev if(NULL != mali_debugfs_dir) { /* Debugfs directory created successfully; create files now */ -#if MALI_TIMELINE_PROFILING_ENABLED - struct dentry *mali_profiling_dir = debugfs_create_dir("profiling", mali_debugfs_dir); + struct dentry *mali_power_dir; + struct dentry *mali_gp_dir; + struct dentry *mali_pp_dir; + struct dentry *mali_l2_dir; +#if MALI_INTERNAL_TIMELINE_PROFILING_ENABLED + struct dentry *mali_profiling_dir; +#endif + + mali_power_dir = debugfs_create_dir("power", mali_debugfs_dir); + if (mali_power_dir != NULL) + { + debugfs_create_file("power_events", 0400, mali_power_dir, NULL, &power_events_fops); + } + + mali_gp_dir = debugfs_create_dir("gp", mali_debugfs_dir); + if (mali_gp_dir != NULL) + { + struct dentry *mali_gp_all_dir; + u32 ci; + struct mali_cluster *cluster; + + mali_gp_all_dir = debugfs_create_dir("all", mali_gp_dir); + if (mali_gp_all_dir != NULL) + { + debugfs_create_file("counter_src0", 0400, mali_gp_all_dir, NULL, &gp_all_counter_src0_fops); + debugfs_create_file("counter_src1", 0400, mali_gp_all_dir, NULL, &gp_all_counter_src1_fops); + } + + ci = 0; + cluster = mali_cluster_get_global_cluster(ci); + while (NULL != cluster) + { + u32 gi = 0; + struct mali_group *group = mali_cluster_get_group(cluster, gi); + while (NULL != group) + { + struct mali_gp_core *gp_core = mali_group_get_gp_core(group); + if (NULL != gp_core) + { + struct dentry *mali_gp_gpx_dir; + mali_gp_gpx_dir = debugfs_create_dir("gp0", mali_gp_dir); + if (NULL != mali_gp_gpx_dir) + { + debugfs_create_file("counter_src0", 0600, mali_gp_gpx_dir, gp_core, &gp_gpx_counter_src0_fops); + debugfs_create_file("counter_src1", 0600, mali_gp_gpx_dir, gp_core, &gp_gpx_counter_src1_fops); + } + break; /* no need to look for any other GP cores */ + } + + /* try next group */ + gi++; + group = mali_cluster_get_group(cluster, gi); + } + + /* try next cluster */ + ci++; + cluster = mali_cluster_get_global_cluster(ci); + } + } + + mali_pp_dir = debugfs_create_dir("pp", mali_debugfs_dir); + if (mali_pp_dir != NULL) + { + struct dentry *mali_pp_all_dir; + u32 ci; + struct mali_cluster *cluster; + + mali_pp_all_dir = debugfs_create_dir("all", mali_pp_dir); + if (mali_pp_all_dir != NULL) + { + debugfs_create_file("counter_src0", 0400, mali_pp_all_dir, NULL, &pp_all_counter_src0_fops); + debugfs_create_file("counter_src1", 0400, mali_pp_all_dir, NULL, &pp_all_counter_src1_fops); + } + + ci = 0; + cluster = mali_cluster_get_global_cluster(ci); + while (NULL != cluster) + { + u32 gi = 0; + struct mali_group *group = mali_cluster_get_group(cluster, gi); + while (NULL != group) + { + struct mali_pp_core *pp_core = mali_group_get_pp_core(group); + if (NULL != pp_core) + { + char buf[16]; + struct dentry *mali_pp_ppx_dir; + _mali_osk_snprintf(buf, sizeof(buf), "pp%u", mali_pp_core_get_id(pp_core)); + mali_pp_ppx_dir = debugfs_create_dir(buf, mali_pp_dir); + if (NULL != mali_pp_ppx_dir) + { + debugfs_create_file("counter_src0", 0600, mali_pp_ppx_dir, pp_core, &pp_ppx_counter_src0_fops); + debugfs_create_file("counter_src1", 0600, mali_pp_ppx_dir, pp_core, &pp_ppx_counter_src1_fops); + } + } + + /* try next group */ + gi++; + group = mali_cluster_get_group(cluster, gi); + } + + /* try next cluster */ + ci++; + cluster = mali_cluster_get_global_cluster(ci); + } + } + + mali_l2_dir = debugfs_create_dir("l2", mali_debugfs_dir); + if (mali_l2_dir != NULL) + { + struct dentry *mali_l2_all_dir; + u32 l2_id; + struct mali_l2_cache_core *l2_cache; + + mali_l2_all_dir = debugfs_create_dir("all", mali_l2_dir); + if (mali_l2_all_dir != NULL) + { + debugfs_create_file("counter_src0", 0400, mali_l2_all_dir, NULL, &l2_all_counter_src0_fops); + debugfs_create_file("counter_src1", 0400, mali_l2_all_dir, NULL, &l2_all_counter_src1_fops); + } + + l2_id = 0; + l2_cache = mali_l2_cache_core_get_glob_l2_core(l2_id); + while (NULL != l2_cache) + { + char buf[16]; + struct dentry *mali_l2_l2x_dir; + _mali_osk_snprintf(buf, sizeof(buf), "l2%u", l2_id); + mali_l2_l2x_dir = debugfs_create_dir(buf, mali_l2_dir); + if (NULL != mali_l2_l2x_dir) + { + debugfs_create_file("counter_src0", 0600, mali_l2_l2x_dir, l2_cache, &l2_l2x_counter_src0_fops); + debugfs_create_file("counter_src1", 0600, mali_l2_l2x_dir, l2_cache, &l2_l2x_counter_src1_fops); + } + + /* try next L2 */ + l2_id++; + l2_cache = mali_l2_cache_core_get_glob_l2_core(l2_id); + } + } + + debugfs_create_file("memory_usage", 0400, mali_debugfs_dir, NULL, &memory_usage_fops); + +#if MALI_INTERNAL_TIMELINE_PROFILING_ENABLED + mali_profiling_dir = debugfs_create_dir("profiling", mali_debugfs_dir); if (mali_profiling_dir != NULL) { struct dentry *mali_profiling_proc_dir = debugfs_create_dir("proc", mali_profiling_dir); @@ -344,7 +1221,7 @@ int mali_sysfs_register(struct mali_dev *device, dev_t dev, const char *mali_dev struct dentry *mali_profiling_proc_default_dir = debugfs_create_dir("default", mali_profiling_proc_dir); if (mali_profiling_proc_default_dir != NULL) { - debugfs_create_file("enable", 0600, mali_profiling_proc_default_dir, NULL, &profiling_proc_default_enable_fops); + debugfs_create_file("enable", 0600, mali_profiling_proc_default_dir, (void*)_MALI_UK_USER_SETTING_SW_EVENTS_ENABLE, &user_settings_fops); } } debugfs_create_file("record", 0600, mali_profiling_dir, NULL, &profiling_record_fops); @@ -356,7 +1233,11 @@ int mali_sysfs_register(struct mali_dev *device, dev_t dev, const char *mali_dev debugfs_create_file("state_dump", 0400, mali_debugfs_dir, NULL, &mali_seq_internal_state_fops); #endif - debugfs_create_file("memory_usage", 0400, mali_debugfs_dir, NULL, &memory_usage_fops); + if (mali_sysfs_user_settings_register()) + { + /* Failed to create the debugfs entries for the user settings DB. */ + MALI_DEBUG_PRINT(2, ("Failed to create user setting debugfs files. Ignoring...\n")); + } } } @@ -385,7 +1266,7 @@ int mali_sysfs_unregister(struct mali_dev *device, dev_t dev, const char *mali_d #else -/* Dummy implementations for when the sysfs API isn't available. */ +/* Dummy implementations for non-GPL */ int mali_sysfs_register(struct mali_dev *device, dev_t dev, const char *mali_dev_name) { diff --git a/drivers/media/video/samsung/mali/linux/mali_kernel_sysfs.h b/drivers/media/video/samsung/mali/linux/mali_kernel_sysfs.h index f68b4e1..d79a886 100644 --- a/drivers/media/video/samsung/mali/linux/mali_kernel_sysfs.h +++ b/drivers/media/video/samsung/mali/linux/mali_kernel_sysfs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2011 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. diff --git a/drivers/media/video/samsung/mali/linux/mali_linux_pm.h b/drivers/media/video/samsung/mali/linux/mali_linux_pm.h index a8c0c52..10f633e 100644 --- a/drivers/media/video/samsung/mali/linux/mali_linux_pm.h +++ b/drivers/media/video/samsung/mali/linux/mali_linux_pm.h @@ -1,5 +1,6 @@ + /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -11,8 +12,6 @@ #ifndef __MALI_LINUX_PM_H__ #define __MALI_LINUX_PM_H__ -#if USING_MALI_PMM - #ifdef CONFIG_PM /* Number of power states supported for making power up and down */ typedef enum @@ -20,7 +19,6 @@ typedef enum _MALI_DEVICE_SUSPEND, /* Suspend */ _MALI_DEVICE_RESUME, /* Resume */ _MALI_DEVICE_MAX_POWER_STATES, /* Maximum power states */ - _MALI_DEVICE_SHUTDOWN, /* Power off states*/ } _mali_device_power_states; /* Number of DVFS events */ @@ -49,5 +47,4 @@ int mali_device_resume(u32 event_id, struct task_struct **pwr_mgmt_thread); int mali_get_ospmm_thread_state(void); #endif /* CONFIG_PM */ -#endif /* USING_MALI_PMM */ #endif /* __MALI_LINUX_PM_H___ */ diff --git a/drivers/media/video/samsung/mali/linux/mali_linux_pm_testsuite.h b/drivers/media/video/samsung/mali/linux/mali_linux_pm_testsuite.h index 7b1bff9..7d811bd 100644 --- a/drivers/media/video/samsung/mali/linux/mali_linux_pm_testsuite.h +++ b/drivers/media/video/samsung/mali/linux/mali_linux_pm_testsuite.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -10,9 +10,7 @@ #ifndef __MALI_LINUX_PM_TESTSUITE_H__ #define __MALI_LINUX_PM_TESTSUITE_H__ -#if USING_MALI_PMM -#if MALI_POWER_MGMT_TEST_SUITE -#ifdef CONFIG_PM +#if MALI_POWER_MGMT_TEST_SUITE && defined(CONFIG_PM) typedef enum { @@ -29,9 +27,6 @@ extern unsigned int pwr_mgmt_status_reg; extern unsigned int is_mali_pmm_testsuite_enabled; extern unsigned int is_mali_pmu_present; -#endif /* CONFIG_PM */ -#endif /* MALI_POWER_MGMT_TEST_SUITE */ -#endif /* USING_MALI_PMM */ -#endif /* __MALI_LINUX_PM_TESTSUITE_H__ */ - +#endif /* MALI_POWER_MGMT_TEST_SUITE && defined(CONFIG_PM) */ +#endif /* __MALI_LINUX_PM_TESTSUITE_H__ */ diff --git a/drivers/media/video/samsung/mali/linux/mali_linux_trace.h b/drivers/media/video/samsung/mali/linux/mali_linux_trace.h index 3ce1e50..09afcb3 100644 --- a/drivers/media/video/samsung/mali/linux/mali_linux_trace.h +++ b/drivers/media/video/samsung/mali/linux/mali_linux_trace.h @@ -1,93 +1,125 @@ -#if !defined(_TRACE_MALI_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_MALI_H +/* + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#if !defined (MALI_LINUX_TRACE_H) || defined (TRACE_HEADER_MULTI_READ) +#define MALI_LINUX_TRACE_H +#include <linux/types.h> #include <linux/stringify.h> #include <linux/tracepoint.h> -#undef TRACE_SYSTEM +#undef TRACE_SYSTEM #define TRACE_SYSTEM mali -#define TRACE_SYSTEM_STRING __stringify(TRACE_SYSTEM) +#define TRACE_SYSTEM_STRING __stringfy(TRACE_SYSTEM) + +#define TRACE_INCLUDE_PATH . #define TRACE_INCLUDE_FILE mali_linux_trace /** - * mali_timeline_event - called from the central collection point (_mali_profiling_add_event) - * @event_id: ORed together bitfields representing a type of event - * In the future we might add - * @timestamp - * @data[5] - this currently includes thread and process id's - we should have EGLConfig or similar too + * Define the tracepoint used to communicate the status of a GPU. Called + * when a GPU turns on or turns off. + * + * @param event_id The type of the event. This parameter is a bitfield + * encoding the type of the event. * - * Just make a record of the event_id, we'll decode it elsewhere + * @param d0 First data parameter. + * @param d1 Second data parameter. + * @param d2 Third data parameter. + * @param d3 Fourth data parameter. + * @param d4 Fifth data parameter. */ TRACE_EVENT(mali_timeline_event, - TP_PROTO(unsigned int event_id), + TP_PROTO(unsigned int event_id, unsigned int d0, unsigned int d1, + unsigned int d2, unsigned int d3, unsigned int d4), - TP_ARGS(event_id), + TP_ARGS(event_id, d0, d1, d2, d3, d4), - TP_STRUCT__entry( - __field( int, event_id ) - ), + TP_STRUCT__entry( + __field(unsigned int, event_id) + __field(unsigned int, d0) + __field(unsigned int, d1) + __field(unsigned int, d2) + __field(unsigned int, d3) + __field(unsigned int, d4) + ), - TP_fast_assign( - __entry->event_id = event_id; - ), + TP_fast_assign( + __entry->event_id = event_id; + __entry->d0 = d0; + __entry->d1 = d1; + __entry->d2 = d2; + __entry->d3 = d3; + __entry->d4 = d4; + ), - TP_printk("event=%d", __entry->event_id) + TP_printk("event=%d", __entry->event_id) ); /** - * mali_hw_counter - called from the ???? - * @event_id: event being counted - * In the future we might add - * @timestamp ?? + * Define a tracepoint used to regsiter the value of a hardware counter. + * Hardware counters belonging to the vertex or fragment processor are + * reported via this tracepoint each frame, whilst L2 cache hardware + * counters are reported continuously. * - * Just make a record of the event_id and value + * @param counter_id The counter ID. + * @param value The value of the counter. */ -TRACE_EVENT(mali_hw_counter, +TRACE_EVENT(mali_hw_counter, - TP_PROTO(unsigned int event_id, unsigned int value), + TP_PROTO(unsigned int counter_id, unsigned int value), - TP_ARGS(event_id, value), + TP_ARGS(counter_id, value), - TP_STRUCT__entry( - __field( int, event_id ) - __field( int, value ) - ), + TP_STRUCT__entry( + __field(unsigned int, counter_id) + __field(unsigned int, value) + ), - TP_fast_assign( - __entry->event_id = event_id; - ), + TP_fast_assign( + __entry->counter_id = counter_id; + ), - TP_printk("event %d = %d", __entry->event_id, __entry->value) + TP_printk("event %d = %d", __entry->counter_id, __entry->value) ); /** - * mali_sw_counter - * @event_id: counter id + * Define a tracepoint used to send a bundle of software counters. + * + * @param counters The bundle of counters. */ -TRACE_EVENT(mali_sw_counter, +TRACE_EVENT(mali_sw_counters, - TP_PROTO(unsigned int event_id, signed long long value), + TP_PROTO(pid_t pid, pid_t tid, void * surface_id, unsigned int * counters), - TP_ARGS(event_id, value), + TP_ARGS(pid, tid, surface_id, counters), TP_STRUCT__entry( - __field( int, event_id ) - __field( long long, value ) + __field(pid_t, pid) + __field(pid_t, tid) + __field(void *, surface_id) + __field(unsigned int *, counters) ), TP_fast_assign( - __entry->event_id = event_id; + __entry->pid = pid; + __entry->tid = tid; + __entry->surface_id = surface_id; + __entry->counters = counters; ), - TP_printk("event %d = %lld", __entry->event_id, __entry->value) + TP_printk("counters were %s", __entry->counters == NULL? "NULL" : "not NULL") ); -#endif /* _TRACE_MALI_H */ - -#undef TRACE_INCLUDE_PATH -#undef linux -#define TRACE_INCLUDE_PATH . +#endif /* MALI_LINUX_TRACE_H */ -/* This part must be outside protection */ +/* This part must exist outside the header guard. */ #include <trace/define_trace.h> + diff --git a/drivers/media/video/samsung/mali/linux/mali_osk_indir_mmap.h b/drivers/media/video/samsung/mali/linux/mali_osk_indir_mmap.h index 41cb462..f87739b 100644 --- a/drivers/media/video/samsung/mali/linux/mali_osk_indir_mmap.h +++ b/drivers/media/video/samsung/mali/linux/mali_osk_indir_mmap.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2011 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. diff --git a/drivers/media/video/samsung/mali/linux/mali_osk_irq.c b/drivers/media/video/samsung/mali/linux/mali_osk_irq.c index c597b9e..ddfe564 100644 --- a/drivers/media/video/samsung/mali/linux/mali_osk_irq.c +++ b/drivers/media/video/samsung/mali/linux/mali_osk_irq.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -15,11 +15,12 @@ #include <linux/slab.h> /* For memory allocation */ #include <linux/workqueue.h> +#include <linux/version.h> #include "mali_osk.h" -#include "mali_kernel_core.h" #include "mali_kernel_common.h" #include "mali_kernel_license.h" +#include "mali_kernel_linux.h" #include "linux/interrupt.h" typedef struct _mali_osk_irq_t_struct @@ -31,7 +32,10 @@ typedef struct _mali_osk_irq_t_struct struct work_struct work_queue_irq_handle; /* Workqueue for the bottom half of the IRQ-handling. This job is activated when this core gets an IRQ.*/ } mali_osk_irq_object_t; -static struct workqueue_struct *mali_irq_wq=NULL; +#if MALI_LICENSE_IS_GPL +static struct workqueue_struct *pmm_wq = NULL; +struct workqueue_struct *mali_wq = NULL; +#endif typedef void (*workqueue_func_t)(void *); typedef irqreturn_t (*irq_handler_func_t)(int, void *, struct pt_regs *); @@ -58,6 +62,23 @@ _mali_osk_irq_t *_mali_osk_irq_init( u32 irqnum, _mali_osk_irq_uhandler_t uhandl irq_object = kmalloc(sizeof(mali_osk_irq_object_t), GFP_KERNEL); if (NULL == irq_object) return NULL; +#if MALI_LICENSE_IS_GPL + if (NULL == mali_wq) + { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) + mali_wq = alloc_workqueue("mali", WQ_UNBOUND, 0); +#else + mali_wq = create_workqueue("mali"); +#endif + if(NULL == mali_wq) + { + MALI_PRINT_ERROR(("Unable to create Mali workqueue\n")); + kfree(irq_object); + return NULL; + } + } +#endif + /* workqueue API changed in 2.6.20, support both versions: */ #if defined(INIT_DELAYED_WORK) /* New syntax: INIT_WORK( struct work_struct *work, void (*function)(struct work_struct *)) */ @@ -107,14 +128,14 @@ _mali_osk_irq_t *_mali_osk_irq_init( u32 irqnum, _mali_osk_irq_uhandler_t uhandl MALI_DEBUG_PRINT(2, ("Probe for irq failed\n")); } } - + irq_object->irqnum = irqnum; irq_object->uhandler = uhandler; irq_object->bhandler = bhandler; irq_object->data = data; /* Is this a real IRQ handler we need? */ - if (!mali_benchmark && irqnum != _MALI_OSK_IRQ_NUMBER_FAKE && irqnum != _MALI_OSK_IRQ_NUMBER_PMM) + if (irqnum != _MALI_OSK_IRQ_NUMBER_FAKE && irqnum != _MALI_OSK_IRQ_NUMBER_PMM) { if (-1 == irqnum) { @@ -131,10 +152,12 @@ _mali_osk_irq_t *_mali_osk_irq_init( u32 irqnum, _mali_osk_irq_uhandler_t uhandl } } - if (mali_irq_wq == NULL) +#if MALI_LICENSE_IS_GPL + if ( _MALI_OSK_IRQ_NUMBER_PMM == irqnum ) { - mali_irq_wq = create_singlethread_workqueue("mali-pmm-wq"); + pmm_wq = create_singlethread_workqueue("mali-pmm-wq"); } +#endif return irq_object; } @@ -142,29 +165,54 @@ _mali_osk_irq_t *_mali_osk_irq_init( u32 irqnum, _mali_osk_irq_uhandler_t uhandl void _mali_osk_irq_schedulework( _mali_osk_irq_t *irq ) { mali_osk_irq_object_t *irq_object = (mali_osk_irq_object_t *)irq; - queue_work_on(0, mali_irq_wq,&irq_object->work_queue_irq_handle); +#if MALI_LICENSE_IS_GPL + if ( irq_object->irqnum == _MALI_OSK_IRQ_NUMBER_PMM ) + { + queue_work( pmm_wq,&irq_object->work_queue_irq_handle ); + } + else + { + queue_work(mali_wq, &irq_object->work_queue_irq_handle); + } +#else + schedule_work(&irq_object->work_queue_irq_handle); +#endif } void _mali_osk_flush_workqueue( _mali_osk_irq_t *irq ) { - flush_workqueue(mali_irq_wq ); +#if MALI_LICENSE_IS_GPL + if (NULL != irq) + { + mali_osk_irq_object_t *irq_object = (mali_osk_irq_object_t *)irq; + if(irq_object->irqnum == _MALI_OSK_IRQ_NUMBER_PMM ) + { + flush_workqueue(pmm_wq); + } + else + { + flush_workqueue(mali_wq); + } + } + else + { + flush_workqueue(mali_wq); + } +#endif } void _mali_osk_irq_term( _mali_osk_irq_t *irq ) { mali_osk_irq_object_t *irq_object = (mali_osk_irq_object_t *)irq; - if(mali_irq_wq != NULL) - { - flush_workqueue(mali_irq_wq); - destroy_workqueue(mali_irq_wq); - mali_irq_wq = NULL; - } - - if (!mali_benchmark) +#if MALI_LICENSE_IS_GPL + if(irq_object->irqnum == _MALI_OSK_IRQ_NUMBER_PMM ) { - free_irq(irq_object->irqnum, irq_object); + flush_workqueue(pmm_wq); + destroy_workqueue(pmm_wq); } +#endif + free_irq(irq_object->irqnum, irq_object); kfree(irq_object); flush_scheduled_work(); } diff --git a/drivers/media/video/samsung/mali/linux/mali_osk_locks.c b/drivers/media/video/samsung/mali/linux/mali_osk_locks.c index aad6fc6..0297c77 100644 --- a/drivers/media/video/samsung/mali/linux/mali_osk_locks.c +++ b/drivers/media/video/samsung/mali/linux/mali_osk_locks.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -51,7 +51,7 @@ typedef enum struct _mali_osk_lock_t_struct { _mali_osk_internal_locktype type; - unsigned long flags; + unsigned long flags; union { spinlock_t spinlock; @@ -61,6 +61,15 @@ struct _mali_osk_lock_t_struct MALI_DEBUG_CODE( /** original flags for debug checking */ _mali_osk_lock_flags_t orig_flags; + + /* id of the thread currently holding this lock, 0 if no + * threads hold it. */ + u32 owner; + /* number of owners this lock currently has (can be > 1 if + * taken in R/O mode. */ + u32 nOwners; + /* what mode the lock was taken in */ + _mali_osk_lock_mode_t mode; ); /* MALI_DEBUG_CODE */ }; @@ -71,11 +80,11 @@ _mali_osk_lock_t *_mali_osk_lock_init( _mali_osk_lock_flags_t flags, u32 initial /* Validate parameters: */ /* Flags acceptable */ MALI_DEBUG_ASSERT( 0 == ( flags & ~(_MALI_OSK_LOCKFLAG_SPINLOCK - | _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ - | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE - | _MALI_OSK_LOCKFLAG_READERWRITER - | _MALI_OSK_LOCKFLAG_ORDERED - | _MALI_OSK_LOCKFLAG_ONELOCK )) ); + | _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ + | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE + | _MALI_OSK_LOCKFLAG_READERWRITER + | _MALI_OSK_LOCKFLAG_ORDERED + | _MALI_OSK_LOCKFLAG_ONELOCK )) ); /* Spinlocks are always non-interruptable */ MALI_DEBUG_ASSERT( (((flags & _MALI_OSK_LOCKFLAG_SPINLOCK) || (flags & _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ)) && (flags & _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE)) || !(flags & _MALI_OSK_LOCKFLAG_SPINLOCK)); @@ -126,14 +135,35 @@ _mali_osk_lock_t *_mali_osk_lock_init( _mali_osk_lock_flags_t flags, u32 initial sema_init( &lock->obj.sema, 1 ); } - MALI_DEBUG_CODE( - /* Debug tracking of flags */ - lock->orig_flags = flags; - ); /* MALI_DEBUG_CODE */ +#ifdef DEBUG + /* Debug tracking of flags */ + lock->orig_flags = flags; + + /* Debug tracking of lock owner */ + lock->owner = 0; + lock->nOwners = 0; +#endif /* DEBUG */ return lock; } +#ifdef DEBUG +u32 _mali_osk_lock_get_owner( _mali_osk_lock_t *lock ) +{ + return lock->owner; +} + +u32 _mali_osk_lock_get_number_owners( _mali_osk_lock_t *lock ) +{ + return lock->nOwners; +} + +u32 _mali_osk_lock_get_mode( _mali_osk_lock_t *lock ) +{ + return lock->mode; +} +#endif /* DEBUG */ + _mali_osk_errcode_t _mali_osk_lock_wait( _mali_osk_lock_t *lock, _mali_osk_lock_mode_t mode) { _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; @@ -162,6 +192,7 @@ _mali_osk_errcode_t _mali_osk_lock_wait( _mali_osk_lock_t *lock, _mali_osk_lock_ case _MALI_OSK_INTERNAL_LOCKTYPE_MUTEX: if ( down_interruptible(&lock->obj.sema) ) { + MALI_PRINT_ERROR(("Can not lock mutex\n")); err = _MALI_OSK_ERR_RESTARTSYSCALL; } break; @@ -188,6 +219,31 @@ _mali_osk_errcode_t _mali_osk_lock_wait( _mali_osk_lock_t *lock, _mali_osk_lock_ break; } +#ifdef DEBUG + /* This thread is now the owner of this lock */ + if (_MALI_OSK_ERR_OK == err) + { + if (mode == _MALI_OSK_LOCKMODE_RW) + { + /*MALI_DEBUG_ASSERT(0 == lock->owner);*/ + if (0 != lock->owner) + { + printk(KERN_ERR "%d: ERROR: Lock %p already has owner %d\n", _mali_osk_get_tid(), lock, lock->owner); + dump_stack(); + } + lock->owner = _mali_osk_get_tid(); + lock->mode = mode; + ++lock->nOwners; + } + else /* mode == _MALI_OSK_LOCKMODE_RO */ + { + lock->owner |= _mali_osk_get_tid(); + lock->mode = mode; + ++lock->nOwners; + } + } +#endif + return err; } @@ -205,6 +261,37 @@ void _mali_osk_lock_signal( _mali_osk_lock_t *lock, _mali_osk_lock_mode_t mode ) MALI_DEBUG_ASSERT( _MALI_OSK_LOCKMODE_RW == mode || (_MALI_OSK_LOCKMODE_RO == mode && (_MALI_OSK_LOCKFLAG_READERWRITER & lock->orig_flags)) ); +#ifdef DEBUG + /* make sure the thread releasing the lock actually was the owner */ + if (mode == _MALI_OSK_LOCKMODE_RW) + { + /*MALI_DEBUG_ASSERT(_mali_osk_get_tid() == lock->owner);*/ + if (_mali_osk_get_tid() != lock->owner) + { + printk(KERN_ERR "%d: ERROR: Lock %p owner was %d\n", _mali_osk_get_tid(), lock, lock->owner); + dump_stack(); + } + /* This lock now has no owner */ + lock->owner = 0; + --lock->nOwners; + } + else /* mode == _MALI_OSK_LOCKMODE_RO */ + { + if ((_mali_osk_get_tid() & lock->owner) != _mali_osk_get_tid()) + { + printk(KERN_ERR "%d: ERROR: Not an owner of %p lock.\n", _mali_osk_get_tid(), lock); + dump_stack(); + } + + /* if this is the last thread holding this lock in R/O mode, set owner + * back to 0 */ + if (0 == --lock->nOwners) + { + lock->owner = 0; + } + } +#endif /* DEBUG */ + switch ( lock->type ) { case _MALI_OSK_INTERNAL_LOCKTYPE_SPIN: diff --git a/drivers/media/video/samsung/mali/linux/mali_osk_low_level_mem.c b/drivers/media/video/samsung/mali/linux/mali_osk_low_level_mem.c index c0aecb8..5767912 100644 --- a/drivers/media/video/samsung/mali/linux/mali_osk_low_level_mem.c +++ b/drivers/media/video/samsung/mali/linux/mali_osk_low_level_mem.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -76,12 +76,7 @@ static void _allocation_list_item_release(AllocationList * item); /* Variable declarations */ -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36) -spinlock_t allocation_list_spinlock = SPIN_LOCK_UNLOCKED; -#else -DEFINE_SPINLOCK(allocation_list_spinlock); -#endif - +static DEFINE_SPINLOCK(allocation_list_spinlock); static AllocationList * pre_allocated_memory = (AllocationList*) NULL ; static int pre_allocated_memory_size_current = 0; #ifdef MALI_OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB @@ -124,9 +119,9 @@ static u32 _kernel_page_allocate(void) { struct page *new_page; u32 linux_phys_addr; - + new_page = alloc_page(GFP_HIGHUSER | __GFP_ZERO | __GFP_REPEAT | __GFP_NOWARN | __GFP_COLD); - + if ( NULL == new_page ) { return 0; @@ -145,7 +140,7 @@ static void _kernel_page_release(u32 physical_address) #if 1 dma_unmap_page(NULL, physical_address, PAGE_SIZE, DMA_BIDIRECTIONAL); #endif - + unmap_page = pfn_to_page( physical_address >> PAGE_SHIFT ); MALI_DEBUG_ASSERT_POINTER( unmap_page ); __free_page( unmap_page ); @@ -155,19 +150,19 @@ static AllocationList * _allocation_list_item_get(void) { AllocationList *item = NULL; unsigned long flags; - + spin_lock_irqsave(&allocation_list_spinlock,flags); if ( pre_allocated_memory ) { item = pre_allocated_memory; pre_allocated_memory = pre_allocated_memory->next; pre_allocated_memory_size_current -= PAGE_SIZE; - + spin_unlock_irqrestore(&allocation_list_spinlock,flags); return item; } spin_unlock_irqrestore(&allocation_list_spinlock,flags); - + item = _mali_osk_malloc( sizeof(AllocationList) ); if ( NULL == item) { @@ -197,7 +192,7 @@ static void _allocation_list_item_release(AllocationList * item) return; } spin_unlock_irqrestore(&allocation_list_spinlock,flags); - + _kernel_page_release(item->physaddr); _mali_osk_free( item ); } @@ -244,7 +239,6 @@ static void mali_kernel_memory_vma_close(struct vm_area_struct * vma) _mali_uk_mem_munmap_s args = {0, }; mali_memory_allocation * descriptor; mali_vma_usage_tracker * vma_usage_tracker; - MappingInfo *mappingInfo; MALI_DEBUG_PRINT(3, ("Close called on vma %p\n", vma)); vma_usage_tracker = (mali_vma_usage_tracker*)vma->vm_private_data; @@ -254,11 +248,6 @@ static void mali_kernel_memory_vma_close(struct vm_area_struct * vma) vma_usage_tracker->references--; - descriptor = (mali_memory_allocation *)vma_usage_tracker->cookie; - - mappingInfo = (MappingInfo *)descriptor->process_addr_mapping_info; - mappingInfo->vma = vma; - if (0 != vma_usage_tracker->references) { MALI_DEBUG_PRINT(3, ("Ignoring this close, %d references still exists\n", vma_usage_tracker->references)); @@ -268,6 +257,8 @@ static void mali_kernel_memory_vma_close(struct vm_area_struct * vma) /** @note args->context unused, initialized to 0. * Instead, we use the memory_session from the cookie */ + descriptor = (mali_memory_allocation *)vma_usage_tracker->cookie; + args.cookie = (u32)descriptor; args.mapping = descriptor->mapping; args.size = descriptor->size; diff --git a/drivers/media/video/samsung/mali/linux/mali_osk_mali.c b/drivers/media/video/samsung/mali/linux/mali_osk_mali.c index ab571c1..3def446 100644 --- a/drivers/media/video/samsung/mali/linux/mali_osk_mali.c +++ b/drivers/media/video/samsung/mali/linux/mali_osk_mali.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -18,27 +18,10 @@ #include "mali_kernel_common.h" /* MALI_xxx macros */ #include "mali_osk.h" /* kernel side OS functions */ #include "mali_uk_types.h" -#include "mali_kernel_linux.h" /* exports initialize/terminate_kernel_device() definition of mali_osk_low_level_mem_init() and term */ +#include "mali_kernel_linux.h" #include <mach/irqs.h> #include "arch/config.h" /* contains the configuration of the arch we are compiling for */ -/* is called from mali_kernel_constructor in common code */ -_mali_osk_errcode_t _mali_osk_init( void ) -{ - if (0 != initialize_kernel_device()) MALI_ERROR(_MALI_OSK_ERR_FAULT); - - mali_osk_low_level_mem_init(); - - MALI_SUCCESS; -} - -/* is called from mali_kernel_deconstructor in common code */ -void _mali_osk_term( void ) -{ - mali_osk_low_level_mem_term(); - terminate_kernel_device(); -} - _mali_osk_errcode_t _mali_osk_resources_init( _mali_osk_resource_t **arch_config, u32 *num_resources ) { *num_resources = sizeof(arch_configuration) / sizeof(arch_configuration[0]); diff --git a/drivers/media/video/samsung/mali/linux/mali_osk_memory.c b/drivers/media/video/samsung/mali/linux/mali_osk_memory.c index 871505a..7bb470f 100644 --- a/drivers/media/video/samsung/mali/linux/mali_osk_memory.c +++ b/drivers/media/video/samsung/mali/linux/mali_osk_memory.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2011 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. diff --git a/drivers/media/video/samsung/mali/linux/mali_osk_misc.c b/drivers/media/video/samsung/mali/linux/mali_osk_misc.c index e37e8c0..ad486db 100644 --- a/drivers/media/video/samsung/mali/linux/mali_osk_misc.c +++ b/drivers/media/video/samsung/mali/linux/mali_osk_misc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -33,7 +33,7 @@ u32 _mali_osk_snprintf( char *buf, u32 size, const char *fmt, ... ) va_list args; va_start(args, fmt); - res = vsnprintf(buf, (size_t)size, fmt, args); + res = vscnprintf(buf, (size_t)size, fmt, args); va_end(args); return res; @@ -42,6 +42,7 @@ u32 _mali_osk_snprintf( char *buf, u32 size, const char *fmt, ... ) void _mali_osk_abort(void) { /* make a simple fault by dereferencing a NULL pointer */ + dump_stack(); *(int *)0 = 0; } diff --git a/drivers/media/video/samsung/mali/linux/mali_osk_notification.c b/drivers/media/video/samsung/mali/linux/mali_osk_notification.c index eef839f..c14c0d5 100644 --- a/drivers/media/video/samsung/mali/linux/mali_osk_notification.c +++ b/drivers/media/video/samsung/mali/linux/mali_osk_notification.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -15,8 +15,6 @@ #include "mali_osk.h" #include "mali_kernel_common.h" -#include "mali_pmm.h" -#include "mali_pmm_state.h" /* needed to detect kernel version specific code */ #include <linux/version.h> @@ -67,12 +65,8 @@ _mali_osk_notification_t *_mali_osk_notification_create( u32 type, u32 size ) /* OPT Recycling of notification objects */ _mali_osk_notification_wrapper_t *notification; - if (MALI_PMM_NOTIFICATION_TYPE == type) { - if (size != sizeof(mali_pmm_message_t)) - return NULL; - } - - notification = (_mali_osk_notification_wrapper_t *)kmalloc( sizeof(_mali_osk_notification_wrapper_t) + size, GFP_KERNEL ); + notification = (_mali_osk_notification_wrapper_t *)kmalloc( sizeof(_mali_osk_notification_wrapper_t) + size, + GFP_KERNEL | __GFP_HIGH | __GFP_REPEAT); if (NULL == notification) { MALI_DEBUG_PRINT(1, ("Failed to create a notification object\n")); @@ -92,7 +86,6 @@ _mali_osk_notification_t *_mali_osk_notification_create( u32 type, u32 size ) } /* set up the non-allocating fields */ - notification->data.magic_code = 0x31415926; notification->data.notification_type = type; notification->data.result_buffer_size = size; @@ -107,8 +100,6 @@ void _mali_osk_notification_delete( _mali_osk_notification_t *object ) notification = container_of( object, _mali_osk_notification_wrapper_t, data ); - /* Remove from the list */ - list_del(¬ification->list); /* Free the container */ kfree(notification); } @@ -169,15 +160,7 @@ _mali_osk_errcode_t _mali_osk_notification_queue_dequeue( _mali_osk_notification wrapper_object = list_entry(queue->head.next, _mali_osk_notification_wrapper_t, list); *result = &(wrapper_object->data); list_del_init(&wrapper_object->list); - - if (wrapper_object->data.magic_code != 0x31415926) { - MALI_PRINT(("SEC WARNING : list entry magic_code not match : %x\n", wrapper_object->data.magic_code)); - MALI_PRINT(("SEC WARNING : list entry notification type : %x\n", wrapper_object->data.notification_type)); - MALI_PRINT(("SEC WARNING : list entry result buffer size : %x\n", wrapper_object->data.result_buffer_size)); - MALI_PRINT(("SEC WARNING : list entry result buffer : %x\n", wrapper_object->data.result_buffer)); - } else { - ret = _MALI_OSK_ERR_OK; - } + ret = _MALI_OSK_ERR_OK; } up(&queue->mutex); diff --git a/drivers/media/video/samsung/mali/linux/mali_osk_pm.c b/drivers/media/video/samsung/mali/linux/mali_osk_pm.c index 2438cbc..20fb7b4 100644 --- a/drivers/media/video/samsung/mali/linux/mali_osk_pm.c +++ b/drivers/media/video/samsung/mali/linux/mali_osk_pm.c @@ -1,5 +1,5 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. +/** + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -18,193 +18,67 @@ #ifdef CONFIG_PM_RUNTIME #include <linux/pm_runtime.h> #endif /* CONFIG_PM_RUNTIME */ - #include <linux/platform_device.h> - #include "mali_platform.h" #include "mali_osk.h" #include "mali_uk_types.h" -#include "mali_pmm.h" #include "mali_kernel_common.h" #include "mali_kernel_license.h" #include "mali_linux_pm.h" -#include "mali_linux_pm_testsuite.h" - -#if MALI_LICENSE_IS_GPL -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON -#ifdef CONFIG_PM_RUNTIME -static int is_runtime =0; -#endif /* CONFIG_PM_RUNTIME */ -#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */ -#endif /* MALI_LICENSE_IS_GPL */ - -#if MALI_POWER_MGMT_TEST_SUITE - -#ifdef CONFIG_PM -unsigned int mali_pmm_events_triggered_mask = 0; -#endif /* CONFIG_PM */ - -void _mali_osk_pmm_policy_events_notifications(mali_pmm_event_id mali_pmm_event) -{ -#if MALI_LICENSE_IS_GPL -#ifdef CONFIG_PM - - switch (mali_pmm_event) - { - case MALI_PMM_EVENT_JOB_QUEUED: - if (mali_job_scheduling_events_recording_on == 1) - { - mali_pmm_events_triggered_mask |= (1<<0); - } - break; - - case MALI_PMM_EVENT_JOB_SCHEDULED: - if (mali_job_scheduling_events_recording_on == 1) - { - mali_pmm_events_triggered_mask |= (1<<1); - } - break; - - case MALI_PMM_EVENT_JOB_FINISHED: - if (mali_job_scheduling_events_recording_on == 1) - { - mali_pmm_events_triggered_mask |= (1<<2); - mali_job_scheduling_events_recording_on = 0; - pwr_mgmt_status_reg = mali_pmm_events_triggered_mask; - } - break; - - case MALI_PMM_EVENT_TIMEOUT: - if (mali_timeout_event_recording_on == 1) - { - pwr_mgmt_status_reg = (1<<3); - mali_timeout_event_recording_on = 0; - } - break; - - default: +#include "mali_kernel_license.h" - break; +#if ! MALI_LICENSE_IS_GPL +#undef CONFIG_PM_RUNTIME +#endif - } -#endif /* CONFIG_PM */ +extern struct platform_device mali_gpu_device; -#endif /* MALI_LICENSE_IS_GPL */ -} -#endif /* MALI_POWER_MGMT_TEST_SUITE */ - -/** This function is called when the Mali device has completed power up - * operation. - */ -void _mali_osk_pmm_power_up_done(mali_pmm_message_data data) -{ -#if MALI_LICENSE_IS_GPL -#ifdef CONFIG_PM - is_wake_up_needed = 1; - wake_up_process(pm_thread); - MALI_DEBUG_PRINT(4, ("OSPMM: MALI OSK Power up Done\n" )); - return; -#endif /* CONFIG_PM */ -#endif /* MALI_LICENSE_IS_GPL */ -} +#ifdef CONFIG_PM_RUNTIME +static mali_bool have_runtime_reference = MALI_FALSE; +#endif -/** This function is called when the Mali device has completed power down - * operation. - */ -void _mali_osk_pmm_power_down_done(mali_pmm_message_data data) +void _mali_osk_pm_dev_enable(void) { -#if MALI_LICENSE_IS_GPL -#ifdef CONFIG_PM - is_wake_up_needed = 1; -#if MALI_POWER_MGMT_TEST_SUITE - if (is_mali_pmu_present == 0) - { - pwr_mgmt_status_reg = _mali_pmm_cores_list(); - } -#endif /* MALI_POWER_MGMT_TEST_SUITE */ - wake_up_process(pm_thread); - MALI_DEBUG_PRINT(4, ("OSPMM: MALI Power down Done\n" )); - return; - -#endif /* CONFIG_PM */ -#endif /* MALI_LICENSE_IS_GPL */ +#ifdef CONFIG_PM_RUNTIME + pm_runtime_enable(&(mali_gpu_device.dev)); +#endif } -/** This function is invoked when mali device is idle. -*/ -_mali_osk_errcode_t _mali_osk_pmm_dev_idle(void) +/* NB: Function is not thread safe */ +_mali_osk_errcode_t _mali_osk_pm_dev_idle(void) { - _mali_osk_errcode_t err = 0; -#if MALI_LICENSE_IS_GPL #ifdef CONFIG_PM_RUNTIME -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON - err = pm_runtime_put_sync(&(mali_gpu_device.dev)); - if(err) + if (MALI_TRUE == have_runtime_reference) { - MALI_DEBUG_PRINT(4, ("OSPMM: Error in _mali_osk_pmm_dev_idle\n" )); + int err; + err = pm_runtime_put_sync(&(mali_gpu_device.dev)); + if (0 > err) + { + MALI_PRINT_ERROR(("OSK PM: pm_runtime_put_sync() returned error code %d\n", err)); + return _MALI_OSK_ERR_FAULT; + } + have_runtime_reference = MALI_FALSE; } -#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */ -#endif /* CONFIG_PM_RUNTIME */ -#endif /* MALI_LICENSE_IS_GPL */ - return err; +#endif + return _MALI_OSK_ERR_OK; } -/** This funtion is invoked when mali device needs to be activated. -*/ -int _mali_osk_pmm_dev_activate(void) +/* NB: Function is not thread safe */ +_mali_osk_errcode_t _mali_osk_pm_dev_activate(void) { - -#if MALI_LICENSE_IS_GPL #ifdef CONFIG_PM_RUNTIME -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON - int err = 0; - if(is_runtime == 0) + if (MALI_TRUE != have_runtime_reference) { - pm_suspend_ignore_children(&(mali_gpu_device.dev), true); - pm_runtime_enable(&(mali_gpu_device.dev)); + int err; err = pm_runtime_get_sync(&(mali_gpu_device.dev)); - is_runtime = 1; - } - else - { - err = pm_runtime_get_sync(&(mali_gpu_device.dev)); - } - if(err < 0) - { - MALI_PRINT(("OSPMM: Error in _mali_osk_pmm_dev_activate, err : %d\n",err )); - } -#endif /* MALI_PMM_RUNTIME_JOB_CONTROL_ON */ -#endif /* CONFIG_PM_RUNTIME */ -#endif /* MALI_LICENSE_IS_GPL */ - - return err; -} - -void _mali_osk_pmm_ospmm_cleanup( void ) -{ -#if MALI_LICENSE_IS_GPL -#ifdef CONFIG_PM - int thread_state; - thread_state = mali_get_ospmm_thread_state(); - if (thread_state) - { - _mali_osk_pmm_dvfs_operation_done(0); + if (0 > err) + { + MALI_PRINT_ERROR(("OSK PM: pm_runtime_get_sync() returned error code %d\n", err)); + return _MALI_OSK_ERR_FAULT; + } + have_runtime_reference = MALI_TRUE; } -#endif /* CONFIG_PM */ -#endif /* MALI_LICENSE_IS_GPL */ +#endif + return _MALI_OSK_ERR_OK; } - -void _mali_osk_pmm_dvfs_operation_done(mali_pmm_message_data data) -{ -#if MALI_LICENSE_IS_GPL -#ifdef CONFIG_PM - is_wake_up_needed = 1; - wake_up_process(dvfs_pm_thread); - MALI_DEBUG_PRINT(4, ("OSPMM: MALI OSK DVFS Operation done\n" )); - return; -#endif /* CONFIG_PM */ -#endif /* MALI_LICENSE_IS_GPL */ -} - - diff --git a/drivers/media/video/samsung/mali/linux/mali_osk_profiling.c b/drivers/media/video/samsung/mali/linux/mali_osk_profiling.c deleted file mode 100644 index 98d3937..0000000 --- a/drivers/media/video/samsung/mali/linux/mali_osk_profiling.c +++ /dev/null @@ -1,47 +0,0 @@ -#include <linux/module.h> -#include "mali_linux_trace.h" -#include "mali_osk.h" - -/* The Linux trace point for hardware activity (idle vs running) */ -void _mali_osk_profiling_add_event(u32 event_id, u32 data0) -{ - trace_mali_timeline_event(event_id); -} - -/* The Linux trace point for hardware counters */ -void _mali_osk_profiling_add_counter(u32 event_id, u32 data0) -{ - trace_mali_hw_counter(event_id, data0); -} - -/* This table stores the event to be counted by each counter - * 0xFFFFFFFF is a special value which means disable counter - */ -//TODO at the moment this table is indexed by the magic numbers -//listed in gator_events_mali.c. In future these numbers should -//be shared through the mali_linux_trace.h header -u32 counter_table[17] = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF}; - -/* Called by gator.ko to populate the table above */ -int _mali_osk_counter_event(u32 counter, u32 event) -{ - /* Remember what has been set, and that a change has occured - * When a job actually starts the code will program the registers - */ - //TODO as above these magic numbers need to be moved to a header file - if( counter >=5 && counter < 17 ) { - counter_table[counter] = event; - - return 1; - } else { - printk("mali rjc: counter out of range (%d,%d)\n", counter, event); - } - - return 0; -} -EXPORT_SYMBOL(_mali_osk_counter_event); - diff --git a/drivers/media/video/samsung/mali/linux/mali_osk_profiling_gator.c b/drivers/media/video/samsung/mali/linux/mali_osk_profiling_gator.c new file mode 100644 index 0000000..75c888d --- /dev/null +++ b/drivers/media/video/samsung/mali/linux/mali_osk_profiling_gator.c @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/module.h> + +#include "mali_kernel_common.h" +#include "mali_osk.h" +#include "mali_ukk.h" +#include "mali_uk_types.h" +#include "mali_osk_profiling.h" +#include "mali_linux_trace.h" +#include "mali_gp.h" +#include "mali_pp.h" +#include "mali_l2_cache.h" +#include "mali_user_settings_db.h" + +_mali_osk_errcode_t _mali_osk_profiling_init(mali_bool auto_start) +{ + if (MALI_TRUE == auto_start) + { + mali_set_user_setting(_MALI_UK_USER_SETTING_SW_EVENTS_ENABLE, MALI_TRUE); + } + + return _MALI_OSK_ERR_OK; +} + +void _mali_osk_profiling_term(void) +{ + /* Nothing to do */ +} + +_mali_osk_errcode_t _mali_osk_profiling_start(u32 * limit) +{ + /* Nothing to do */ + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t _mali_osk_profiling_stop(u32 *count) +{ + /* Nothing to do */ + return _MALI_OSK_ERR_OK; +} + +u32 _mali_osk_profiling_get_count(void) +{ + return 0; +} + +_mali_osk_errcode_t _mali_osk_profiling_get_event(u32 index, u64* timestamp, u32* event_id, u32 data[5]) +{ + /* Nothing to do */ + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t _mali_osk_profiling_clear(void) +{ + /* Nothing to do */ + return _MALI_OSK_ERR_OK; +} + +mali_bool _mali_osk_profiling_is_recording(void) +{ + return MALI_FALSE; +} + +mali_bool _mali_osk_profiling_have_recording(void) +{ + return MALI_FALSE; +} + +void _mali_osk_profiling_report_sw_counters(u32 *counters) +{ + trace_mali_sw_counters(_mali_osk_get_pid(), _mali_osk_get_tid(), NULL, counters); +} + + +_mali_osk_errcode_t _mali_ukk_profiling_start(_mali_uk_profiling_start_s *args) +{ + return _mali_osk_profiling_start(&args->limit); +} + +_mali_osk_errcode_t _mali_ukk_profiling_add_event(_mali_uk_profiling_add_event_s *args) +{ + /* Always add process and thread identificator in the first two data elements for events from user space */ + _mali_osk_profiling_add_event(args->event_id, _mali_osk_get_pid(), _mali_osk_get_tid(), args->data[2], args->data[3], args->data[4]); + + return _MALI_OSK_ERR_OK; +} + +_mali_osk_errcode_t _mali_ukk_profiling_stop(_mali_uk_profiling_stop_s *args) +{ + return _mali_osk_profiling_stop(&args->count); +} + +_mali_osk_errcode_t _mali_ukk_profiling_get_event(_mali_uk_profiling_get_event_s *args) +{ + return _mali_osk_profiling_get_event(args->index, &args->timestamp, &args->event_id, args->data); +} + +_mali_osk_errcode_t _mali_ukk_profiling_clear(_mali_uk_profiling_clear_s *args) +{ + return _mali_osk_profiling_clear(); +} + +_mali_osk_errcode_t _mali_ukk_sw_counters_report(_mali_uk_sw_counters_report_s *args) +{ + _mali_osk_profiling_report_sw_counters(args->counters); + return _MALI_OSK_ERR_OK; +} + +/** + * Called by gator.ko to set HW counters + * + * @param counter_id The counter ID. + * @param event_id Event ID that the counter should count (HW counter value from TRM). + * + * @return 1 on success, 0 on failure. + */ +int _mali_profiling_set_event(u32 counter_id, s32 event_id) +{ + + if (counter_id == COUNTER_VP_C0) + { + struct mali_gp_core* gp_core = mali_gp_get_global_gp_core(); + if (NULL != gp_core) + { + if (MALI_TRUE == mali_gp_core_set_counter_src0(gp_core, event_id)) + { + return 1; + } + } + } + else if (counter_id == COUNTER_VP_C1) + { + struct mali_gp_core* gp_core = mali_gp_get_global_gp_core(); + if (NULL != gp_core) + { + if (MALI_TRUE == mali_gp_core_set_counter_src1(gp_core, event_id)) + { + return 1; + } + } + } + else if (counter_id >= COUNTER_FP0_C0 && counter_id <= COUNTER_FP3_C1) + { + u32 core_id = (counter_id - COUNTER_FP0_C0) >> 1; + struct mali_pp_core* pp_core = mali_pp_get_global_pp_core(core_id); + if (NULL != pp_core) + { + u32 counter_src = (counter_id - COUNTER_FP0_C0) & 1; + if (0 == counter_src) + { + if (MALI_TRUE == mali_pp_core_set_counter_src0(pp_core, event_id)) + { + return 1; + } + } + else + { + if (MALI_TRUE == mali_pp_core_set_counter_src1(pp_core, event_id)) + { + return 1; + } + } + } + } + else if (counter_id >= COUNTER_L2_C0 && counter_id <= COUNTER_L2_C1) + { + u32 core_id = (counter_id - COUNTER_L2_C0) >> 1; + struct mali_l2_cache_core* l2_cache_core = mali_l2_cache_core_get_glob_l2_core(core_id); + if (NULL != l2_cache_core) + { + u32 counter_src = (counter_id - COUNTER_L2_C0) & 1; + if (0 == counter_src) + { + if (MALI_TRUE == mali_l2_cache_core_set_counter_src0(l2_cache_core, event_id)) + { + return 1; + } + } + else + { + if (MALI_TRUE == mali_l2_cache_core_set_counter_src1(l2_cache_core, event_id)) + { + return 1; + } + } + } + } + + return 0; +} + +/** + * Called by gator.ko to retrieve the L2 cache counter values for the first L2 cache. + * The L2 cache counters are unique in that they are polled by gator, rather than being + * transmitted via the tracepoint mechanism. + * + * @param src0 First L2 cache counter ID. + * @param val0 First L2 cache counter value. + * @param src1 Second L2 cache counter ID. + * @param val1 Second L2 cache counter value. + */ +void _mali_profiling_get_counters(u32 *src0, u32 *val0, u32 *src1, u32 *val1) +{ + struct mali_l2_cache_core *l2_cache = mali_l2_cache_core_get_glob_l2_core(0); /* @@@@ TODO: Fix hardcoded limit of maximum 1 L2 cache */ + if (NULL != l2_cache) + { + if (MALI_TRUE == mali_l2_cache_lock_power_state(l2_cache)) + { + /* It is now safe to access the L2 cache core in order to retrieve the counters */ + mali_l2_cache_core_get_counter_values(l2_cache, src0, val0, src1, val1); + /* @@@@ TODO: add error checking, if needed; src == MALI_HW_CORE_NO_COUNTER if not able to get value */ + } + mali_l2_cache_unlock_power_state(l2_cache); + } +} + +/* + * List of possible actions to be controlled by Streamline. + * The following numbers are used by gator to control the frame buffer dumping and s/w counter reporting. + * We cannot use the enums in mali_uk_types.h because they are unknown inside gator. + */ +#define FBDUMP_CONTROL_ENABLE (1) +#define FBDUMP_CONTROL_RATE (2) +#define SW_COUNTER_ENABLE (3) +#define FBDUMP_CONTROL_RESIZE_FACTOR (4) + +/** + * Called by gator to control the production of profiling information at runtime. + */ +void _mali_profiling_control(u32 action, u32 value) +{ + switch(action) + { + case FBDUMP_CONTROL_ENABLE: + mali_set_user_setting(_MALI_UK_USER_SETTING_COLORBUFFER_CAPTURE_ENABLED, (value == 0 ? MALI_FALSE : MALI_TRUE)); + break; + case FBDUMP_CONTROL_RATE: + mali_set_user_setting(_MALI_UK_USER_SETTING_BUFFER_CAPTURE_N_FRAMES, value); + break; + case SW_COUNTER_ENABLE: + mali_set_user_setting(_MALI_UK_USER_SETTING_SW_COUNTER_ENABLED, value); + break; + case FBDUMP_CONTROL_RESIZE_FACTOR: + mali_set_user_setting(_MALI_UK_USER_SETTING_BUFFER_CAPTURE_RESIZE_FACTOR, value); + break; + default: + break; /* Ignore unimplemented actions */ + } +} + +EXPORT_SYMBOL(_mali_profiling_set_event); +EXPORT_SYMBOL(_mali_profiling_get_counters); +EXPORT_SYMBOL(_mali_profiling_control); diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_profiling.c b/drivers/media/video/samsung/mali/linux/mali_osk_profiling_internal.c index ca04b5f..9a423d2 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_profiling.c +++ b/drivers/media/video/samsung/mali/linux/mali_osk_profiling_internal.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -13,8 +13,8 @@ #include "mali_osk_mali.h" #include "mali_ukk.h" #include "mali_timestamp.h" -#include "mali_kernel_profiling.h" -#include "mali_linux_trace.h" +#include "mali_osk_profiling.h" +#include "mali_user_settings_db.h" typedef struct mali_profiling_entry { @@ -39,16 +39,15 @@ static mali_profiling_entry* profile_entries = NULL; static u32 profile_entry_count = 0; static _mali_osk_atomic_t profile_insert_index; static _mali_osk_atomic_t profile_entries_written; -static mali_bool mali_profiling_default_enable = MALI_FALSE; -_mali_osk_errcode_t _mali_profiling_init(mali_bool auto_start) +_mali_osk_errcode_t _mali_osk_profiling_init(mali_bool auto_start) { profile_entries = NULL; profile_entry_count = 0; _mali_osk_atomic_init(&profile_insert_index, 0); _mali_osk_atomic_init(&profile_entries_written, 0); - lock = _mali_osk_lock_init( _MALI_OSK_LOCKFLAG_SPINLOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, 0 ); + lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_SPINLOCK | _MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_PROFILING); if (NULL == lock) { return _MALI_OSK_ERR_FAULT; @@ -59,9 +58,9 @@ _mali_osk_errcode_t _mali_profiling_init(mali_bool auto_start) if (MALI_TRUE == auto_start) { u32 limit = MALI_PROFILING_MAX_BUFFER_ENTRIES; /* Use maximum buffer size */ - - mali_profiling_default_enable = MALI_TRUE; /* save this so user space can query this on their startup */ - if (_MALI_OSK_ERR_OK != _mali_profiling_start(&limit)) + + mali_set_user_setting(_MALI_UK_USER_SETTING_SW_EVENTS_ENABLE, MALI_TRUE); + if (_MALI_OSK_ERR_OK != _mali_osk_profiling_start(&limit)) { return _MALI_OSK_ERR_FAULT; } @@ -70,7 +69,7 @@ _mali_osk_errcode_t _mali_profiling_init(mali_bool auto_start) return _MALI_OSK_ERR_OK; } -void _mali_profiling_term(void) +void _mali_osk_profiling_term(void) { prof_state = MALI_PROFILING_STATE_UNINITIALIZED; @@ -93,7 +92,7 @@ void _mali_profiling_term(void) } } -inline _mali_osk_errcode_t _mali_profiling_start(u32 * limit) +inline _mali_osk_errcode_t _mali_osk_profiling_start(u32 * limit) { _mali_osk_errcode_t ret; @@ -137,21 +136,10 @@ inline _mali_osk_errcode_t _mali_profiling_start(u32 * limit) return ret; } -inline void _mali_profiling_add_counter(u32 event_id, u32 data0) -{ -#if MALI_TRACEPOINTS_ENABLED - _mali_osk_profiling_add_counter(event_id, data0); -#endif -} - -inline _mali_osk_errcode_t _mali_profiling_add_event(u32 event_id, u32 data0, u32 data1, u32 data2, u32 data3, u32 data4) +inline void _mali_osk_profiling_add_event(u32 event_id, u32 data0, u32 data1, u32 data2, u32 data3, u32 data4) { u32 cur_index = _mali_osk_atomic_inc_return(&profile_insert_index) - 1; -#if MALI_TRACEPOINTS_ENABLED - _mali_osk_profiling_add_event(event_id, data0); -#endif - if (prof_state != MALI_PROFILING_STATE_RUNNING || cur_index >= profile_entry_count) { /* @@ -159,7 +147,7 @@ inline _mali_osk_errcode_t _mali_profiling_add_event(u32 event_id, u32 data0, u3 * Decrement index again, and early out */ _mali_osk_atomic_dec(&profile_insert_index); - return _MALI_OSK_ERR_FAULT; + return; } profile_entries[cur_index].timestamp = _mali_timestamp_get(); @@ -171,55 +159,19 @@ inline _mali_osk_errcode_t _mali_profiling_add_event(u32 event_id, u32 data0, u3 profile_entries[cur_index].data[4] = data4; _mali_osk_atomic_inc(&profile_entries_written); - - return _MALI_OSK_ERR_OK; } -#if MALI_TRACEPOINTS_ENABLED -/* - * The following code uses a bunch of magic numbers taken from the userspace - * side of the DDK; they are re-used here verbatim. They are taken from the - * file mali_instrumented_counter_types.h. - */ -#define MALI_GLES_COUNTER_OFFSET 1000 -#define MALI_VG_COUNTER_OFFSET 2000 -#define MALI_EGL_COUNTER_OFFSET 3000 -#define MALI_SHARED_COUNTER_OFFSET 4000 - -/* These offsets are derived from the gator driver; see gator_events_mali.c. */ -#define GATOR_EGL_COUNTER_OFFSET 17 -#define GATOR_GLES_COUNTER_OFFSET 18 - -_mali_osk_errcode_t _mali_ukk_transfer_sw_counters(_mali_uk_sw_counters_s *args) +inline void _mali_osk_profiling_report_hw_counter(u32 counter_id, u32 value) { - /* Convert the DDK counter ID to what gator expects */ - unsigned int gator_counter_value = 0; - - _mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW); - - if (args->id >= MALI_EGL_COUNTER_OFFSET && args->id <= MALI_SHARED_COUNTER_OFFSET) - { - gator_counter_value = (args->id - MALI_EGL_COUNTER_OFFSET) + GATOR_EGL_COUNTER_OFFSET; - } - else if (args->id >= MALI_GLES_COUNTER_OFFSET && args->id <= MALI_VG_COUNTER_OFFSET) - { - gator_counter_value = (args->id - MALI_GLES_COUNTER_OFFSET) + GATOR_GLES_COUNTER_OFFSET; - } - else - { - /* Pass it straight through; gator will ignore it anyway. */ - gator_counter_value = args->id; - } - - trace_mali_sw_counter(gator_counter_value, args->value); - - _mali_osk_lock_signal(lock, _MALI_OSK_LOCKMODE_RW); + /* Not implemented */ +} - return _MALI_OSK_ERR_OK; +void _mali_osk_profiling_report_sw_counters(u32 *counters) +{ + /* Not implemented */ } -#endif -inline _mali_osk_errcode_t _mali_profiling_stop(u32 * count) +inline _mali_osk_errcode_t _mali_osk_profiling_stop(u32 * count) { _mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW); @@ -245,7 +197,7 @@ inline _mali_osk_errcode_t _mali_profiling_stop(u32 * count) return _MALI_OSK_ERR_OK; } -inline u32 _mali_profiling_get_count(void) +inline u32 _mali_osk_profiling_get_count(void) { u32 retval = 0; @@ -259,7 +211,7 @@ inline u32 _mali_profiling_get_count(void) return retval; } -inline _mali_osk_errcode_t _mali_profiling_get_event(u32 index, u64* timestamp, u32* event_id, u32 data[5]) +inline _mali_osk_errcode_t _mali_osk_profiling_get_event(u32 index, u64* timestamp, u32* event_id, u32 data[5]) { _mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW); @@ -287,7 +239,7 @@ inline _mali_osk_errcode_t _mali_profiling_get_event(u32 index, u64* timestamp, return _MALI_OSK_ERR_OK; } -inline _mali_osk_errcode_t _mali_profiling_clear(void) +inline _mali_osk_errcode_t _mali_osk_profiling_clear(void) { _mali_osk_lock_wait(lock, _MALI_OSK_LOCKMODE_RW); @@ -311,54 +263,46 @@ inline _mali_osk_errcode_t _mali_profiling_clear(void) return _MALI_OSK_ERR_OK; } -mali_bool _mali_profiling_is_recording(void) +mali_bool _mali_osk_profiling_is_recording(void) { return prof_state == MALI_PROFILING_STATE_RUNNING ? MALI_TRUE : MALI_FALSE; } -mali_bool _mali_profiling_have_recording(void) +mali_bool _mali_osk_profiling_have_recording(void) { return prof_state == MALI_PROFILING_STATE_RETURN ? MALI_TRUE : MALI_FALSE; } -void _mali_profiling_set_default_enable_state(mali_bool enable) -{ - mali_profiling_default_enable = enable; -} - -mali_bool _mali_profiling_get_default_enable_state(void) -{ - return mali_profiling_default_enable; -} - _mali_osk_errcode_t _mali_ukk_profiling_start(_mali_uk_profiling_start_s *args) { - return _mali_profiling_start(&args->limit); + return _mali_osk_profiling_start(&args->limit); } _mali_osk_errcode_t _mali_ukk_profiling_add_event(_mali_uk_profiling_add_event_s *args) { /* Always add process and thread identificator in the first two data elements for events from user space */ - return _mali_profiling_add_event(args->event_id, _mali_osk_get_pid(), _mali_osk_get_tid(), args->data[2], args->data[3], args->data[4]); + _mali_osk_profiling_add_event(args->event_id, _mali_osk_get_pid(), _mali_osk_get_tid(), args->data[2], args->data[3], args->data[4]); + return _MALI_OSK_ERR_OK; } _mali_osk_errcode_t _mali_ukk_profiling_stop(_mali_uk_profiling_stop_s *args) { - return _mali_profiling_stop(&args->count); + return _mali_osk_profiling_stop(&args->count); } _mali_osk_errcode_t _mali_ukk_profiling_get_event(_mali_uk_profiling_get_event_s *args) { - return _mali_profiling_get_event(args->index, &args->timestamp, &args->event_id, args->data); + return _mali_osk_profiling_get_event(args->index, &args->timestamp, &args->event_id, args->data); } _mali_osk_errcode_t _mali_ukk_profiling_clear(_mali_uk_profiling_clear_s *args) { - return _mali_profiling_clear(); + return _mali_osk_profiling_clear(); } -_mali_osk_errcode_t _mali_ukk_profiling_get_config(_mali_uk_profiling_get_config_s *args) +_mali_osk_errcode_t _mali_ukk_sw_counters_report(_mali_uk_sw_counters_report_s *args) { - args->enable_events = mali_profiling_default_enable; + _mali_osk_profiling_report_sw_counters(args->counters); return _MALI_OSK_ERR_OK; } + diff --git a/drivers/media/video/samsung/mali/linux/mali_osk_specific.h b/drivers/media/video/samsung/mali/linux/mali_osk_specific.h index 6aacf17..83ee906 100644 --- a/drivers/media/video/samsung/mali/linux/mali_osk_specific.h +++ b/drivers/media/video/samsung/mali/linux/mali_osk_specific.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010, 2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -22,11 +22,109 @@ extern "C" { #endif -#define MALI_STATIC_INLINE static inline +#define MALI_STATIC_INLINE static inline #define MALI_NON_STATIC_INLINE inline #ifdef __cplusplus } #endif +/** The list of events supported by the Mali DDK. */ +typedef enum +{ + /* Vertex processor activity */ + ACTIVITY_VP = 0, + + /* Fragment processor activity */ + ACTIVITY_FP0, + ACTIVITY_FP1, + ACTIVITY_FP2, + ACTIVITY_FP3, + + /* L2 cache counters */ + COUNTER_L2_C0, + COUNTER_L2_C1, + + /* Vertex processor counters */ + COUNTER_VP_C0, + COUNTER_VP_C1, + + /* Fragment processor counters */ + COUNTER_FP0_C0, + COUNTER_FP0_C1, + COUNTER_FP1_C0, + COUNTER_FP1_C1, + COUNTER_FP2_C0, + COUNTER_FP2_C1, + COUNTER_FP3_C0, + COUNTER_FP3_C1, + + /* + * If more hardware counters are added, the _mali_osk_hw_counter_table + * below should also be updated. + */ + + /* EGL software counters */ + COUNTER_EGL_BLIT_TIME, + + /* GLES software counters */ + COUNTER_GLES_DRAW_ELEMENTS_CALLS, + COUNTER_GLES_DRAW_ELEMENTS_NUM_INDICES, + COUNTER_GLES_DRAW_ELEMENTS_NUM_TRANSFORMED, + COUNTER_GLES_DRAW_ARRAYS_CALLS, + COUNTER_GLES_DRAW_ARRAYS_NUM_TRANSFORMED, + COUNTER_GLES_DRAW_POINTS, + COUNTER_GLES_DRAW_LINES, + COUNTER_GLES_DRAW_LINE_LOOP, + COUNTER_GLES_DRAW_LINE_STRIP, + COUNTER_GLES_DRAW_TRIANGLES, + COUNTER_GLES_DRAW_TRIANGLE_STRIP, + COUNTER_GLES_DRAW_TRIANGLE_FAN, + COUNTER_GLES_NON_VBO_DATA_COPY_TIME, + COUNTER_GLES_UNIFORM_BYTES_COPIED_TO_MALI, + COUNTER_GLES_UPLOAD_TEXTURE_TIME, + COUNTER_GLES_UPLOAD_VBO_TIME, + COUNTER_GLES_NUM_FLUSHES, + COUNTER_GLES_NUM_VSHADERS_GENERATED, + COUNTER_GLES_NUM_FSHADERS_GENERATED, + COUNTER_GLES_VSHADER_GEN_TIME, + COUNTER_GLES_FSHADER_GEN_TIME, + COUNTER_GLES_INPUT_TRIANGLES, + COUNTER_GLES_VXCACHE_HIT, + COUNTER_GLES_VXCACHE_MISS, + COUNTER_GLES_VXCACHE_COLLISION, + COUNTER_GLES_CULLED_TRIANGLES, + COUNTER_GLES_CULLED_LINES, + COUNTER_GLES_BACKFACE_TRIANGLES, + COUNTER_GLES_GBCLIP_TRIANGLES, + COUNTER_GLES_GBCLIP_LINES, + COUNTER_GLES_TRIANGLES_DRAWN, + COUNTER_GLES_DRAWCALL_TIME, + COUNTER_GLES_TRIANGLES_COUNT, + COUNTER_GLES_INDEPENDENT_TRIANGLES_COUNT, + COUNTER_GLES_STRIP_TRIANGLES_COUNT, + COUNTER_GLES_FAN_TRIANGLES_COUNT, + COUNTER_GLES_LINES_COUNT, + COUNTER_GLES_INDEPENDENT_LINES_COUNT, + COUNTER_GLES_STRIP_LINES_COUNT, + COUNTER_GLES_LOOP_LINES_COUNT, + + /* Framebuffer capture pseudo-counter */ + COUNTER_FILMSTRIP, + + NUMBER_OF_EVENTS +} _mali_osk_counter_id; + +#define FIRST_ACTIVITY_EVENT ACTIVITY_VP +#define LAST_ACTIVITY_EVENT ACTIVITY_FP3 + +#define FIRST_HW_COUNTER COUNTER_L2_C0 +#define LAST_HW_COUNTER COUNTER_FP3_C1 + +#define FIRST_SW_COUNTER COUNTER_EGL_BLIT_TIME +#define LAST_SW_COUNTER COUNTER_GLES_LOOP_LINES_COUNT + +#define FIRST_SPECIAL_COUNTER COUNTER_FILMSTRIP +#define LAST_SPECIAL_COUNTER COUNTER_FILMSTRIP + #endif /* __MALI_OSK_SPECIFIC_H__ */ diff --git a/drivers/media/video/samsung/mali/linux/mali_osk_timers.c b/drivers/media/video/samsung/mali/linux/mali_osk_timers.c index 0454756..e5829a3 100644 --- a/drivers/media/video/samsung/mali/linux/mali_osk_timers.c +++ b/drivers/media/video/samsung/mali/linux/mali_osk_timers.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -34,7 +34,7 @@ _mali_osk_timer_t *_mali_osk_timer_init(void) void _mali_osk_timer_add( _mali_osk_timer_t *tim, u32 ticks_to_expire ) { - MALI_DEBUG_ASSERT_POINTER(tim); + MALI_DEBUG_ASSERT_POINTER(tim); tim->timer.expires = _mali_osk_time_tickcount() + ticks_to_expire; add_timer(&(tim->timer)); } diff --git a/drivers/media/video/samsung/mali/linux/mali_osk_wait_queue.c b/drivers/media/video/samsung/mali/linux/mali_osk_wait_queue.c new file mode 100644 index 0000000..ce0561d --- /dev/null +++ b/drivers/media/video/samsung/mali/linux/mali_osk_wait_queue.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** + * @file mali_osk_wait_queue.c + * Implemenation of the OS abstraction layer for the kernel device driver + */ + +#include <linux/wait.h> +#include <linux/slab.h> +#include <linux/sched.h> + +#include "mali_osk.h" +#include "mali_kernel_common.h" + +struct _mali_osk_wait_queue_t_struct +{ + wait_queue_head_t wait_queue; +}; + +_mali_osk_wait_queue_t* _mali_osk_wait_queue_init( void ) +{ + _mali_osk_wait_queue_t* ret = NULL; + + ret = kmalloc(sizeof(_mali_osk_wait_queue_t), GFP_KERNEL); + + if (NULL == ret) + { + return ret; + } + + init_waitqueue_head(&ret->wait_queue); + MALI_DEBUG_ASSERT(!waitqueue_active(&ret->wait_queue)); + + return ret; +} + +void _mali_osk_wait_queue_wait_event( _mali_osk_wait_queue_t *queue, mali_bool (*condition)(void) ) +{ + MALI_DEBUG_ASSERT_POINTER( queue ); + MALI_DEBUG_PRINT(6, ("Adding to wait queue %p\n", queue)); + wait_event(queue->wait_queue, condition()); +} + +void _mali_osk_wait_queue_wake_up( _mali_osk_wait_queue_t *queue ) +{ + MALI_DEBUG_ASSERT_POINTER( queue ); + + /* if queue is empty, don't attempt to wake up its elements */ + if (!waitqueue_active(&queue->wait_queue)) return; + + MALI_DEBUG_PRINT(6, ("Waking up elements in wait queue %p ....\n", queue)); + + wake_up_all(&queue->wait_queue); + + MALI_DEBUG_PRINT(6, ("... elements in wait queue %p woken up\n", queue)); +} + +void _mali_osk_wait_queue_term( _mali_osk_wait_queue_t *queue ) +{ + /* Parameter validation */ + MALI_DEBUG_ASSERT_POINTER( queue ); + + /* Linux requires no explicit termination of wait queues */ + kfree(queue); +} diff --git a/drivers/media/video/samsung/mali/linux/mali_pmu_power_up_down.c b/drivers/media/video/samsung/mali/linux/mali_pmu_power_up_down.c new file mode 100644 index 0000000..f3b0a2c --- /dev/null +++ b/drivers/media/video/samsung/mali/linux/mali_pmu_power_up_down.c @@ -0,0 +1,65 @@ +/** + * Copyright (C) 2010, 2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** + * @file mali_pmu_power_up_down.c + */ + +#include <linux/version.h> +#include <linux/sched.h> +#include <linux/module.h> +#include "mali_osk.h" +#include "mali_kernel_common.h" +#include "mali_pmu.h" +#include "linux/mali/mali_utgard.h" + +/* Mali PMU power up/down APIs */ + +int mali_pmu_powerup(void) +{ + struct mali_pmu_core *pmu = mali_pmu_get_global_pmu_core(); + + MALI_DEBUG_PRINT(5, ("Mali PMU: Power up\n")); + + if (NULL == pmu) + { + return -ENXIO; + } + + if (_MALI_OSK_ERR_OK != mali_pmu_powerup_all(pmu)) + { + return -EFAULT; + } + + return 0; +} + +EXPORT_SYMBOL(mali_pmu_powerup); + +int mali_pmu_powerdown(void) +{ + struct mali_pmu_core *pmu = mali_pmu_get_global_pmu_core(); + + MALI_DEBUG_PRINT(5, ("Mali PMU: Power down\n")); + + if (NULL == pmu) + { + return -ENXIO; + } + + if (_MALI_OSK_ERR_OK != mali_pmu_powerdown_all(pmu)) + { + return -EFAULT; + } + + return 0; +} + +EXPORT_SYMBOL(mali_pmu_powerdown); diff --git a/drivers/media/video/samsung/ump/arch-marcopolo-vega1-m400/config.h b/drivers/media/video/samsung/mali/linux/mali_profiling_events.h index 014c4bb..2639a40 100644 --- a/drivers/media/video/samsung/ump/arch-marcopolo-vega1-m400/config.h +++ b/drivers/media/video/samsung/mali/linux/mali_profiling_events.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -8,11 +8,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __ARCH_CONFIG_H__ -#define __ARCH_CONFIG_H__ +#ifndef __MALI_PROFILING_EVENTS_H__ +#define __MALI_PROFILING_EVENTS_H__ -#define ARCH_UMP_BACKEND_DEFAULT 0 -#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0x2C000000 -#define ARCH_UMP_MEMORY_SIZE_DEFAULT 0x04000000 +/* Simple wrapper in order to find the OS specific location of this file */ +#include <linux/mali/mali_utgard_profiling_events.h> -#endif /* __ARCH_CONFIG_H__ */ +#endif /* __MALI_PROFILING_EVENTS_H__ */ diff --git a/drivers/media/video/samsung/mali/linux/mali_device_pause_resume.h b/drivers/media/video/samsung/mali/linux/mali_uk_types.h index 155a3e6..b535e6c 100644 --- a/drivers/media/video/samsung/mali/linux/mali_device_pause_resume.h +++ b/drivers/media/video/samsung/mali/linux/mali_uk_types.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -8,12 +8,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __MALI_DEVICE_PAUSE_RESUME_H__ -#define __MALI_DEVICE_PAUSE_RESUME_H__ +#ifndef __MALI_UK_TYPES_H__ +#define __MALI_UK_TYPES_H__ -#if USING_MALI_PMM -int mali_dev_pause(void); -int mali_dev_resume(void); -#endif /* USING_MALI_PMM */ +#include "regs/mali_200_regs.h" -#endif /* __MALI_DEVICE_PAUSE_RESUME_H__ */ +/* Simple wrapper in order to find the OS specific location of this file */ +#include "../include/linux/mali/mali_utgard_uk_types.h" + +#endif /* __MALI_UK_TYPES_H__ */ diff --git a/drivers/media/video/samsung/mali/linux/mali_ukk_core.c b/drivers/media/video/samsung/mali/linux/mali_ukk_core.c index 59eafe2..6eb2df3 100644 --- a/drivers/media/video/samsung/mali/linux/mali_ukk_core.c +++ b/drivers/media/video/samsung/mali/linux/mali_ukk_core.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -14,7 +14,7 @@ #include "mali_ukk.h" #include "mali_osk.h" #include "mali_kernel_common.h" -#include "mali_kernel_session_manager.h" +#include "mali_session.h" #include "mali_ukk_wrappers.h" int get_api_version_wrapper(struct mali_session_data *session_data, _mali_uk_get_api_version_s __user *uargs) @@ -140,3 +140,23 @@ int post_notification_wrapper(struct mali_session_data *session_data, _mali_uk_p return 0; } + +int get_user_settings_wrapper(struct mali_session_data *session_data, _mali_uk_get_user_settings_s __user *uargs) +{ + _mali_uk_get_user_settings_s kargs; + _mali_osk_errcode_t err; + + MALI_CHECK_NON_NULL(uargs, -EINVAL); + + kargs.ctx = session_data; + err = _mali_ukk_get_user_settings(&kargs); + if (_MALI_OSK_ERR_OK != err) + { + return map_errcode(err); + } + + kargs.ctx = NULL; /* prevent kernel address to be returned to user space */ + if (0 != copy_to_user(uargs, &kargs, sizeof(_mali_uk_get_user_settings_s))) return -EFAULT; + + return 0; +} diff --git a/drivers/media/video/samsung/mali/linux/mali_ukk_gp.c b/drivers/media/video/samsung/mali/linux/mali_ukk_gp.c index 58ff1de..7070016 100644 --- a/drivers/media/video/samsung/mali/linux/mali_ukk_gp.c +++ b/drivers/media/video/samsung/mali/linux/mali_ukk_gp.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010, 2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -13,7 +13,7 @@ #include "mali_ukk.h" #include "mali_osk.h" #include "mali_kernel_common.h" -#include "mali_kernel_session_manager.h" +#include "mali_session.h" #include "mali_ukk_wrappers.h" int gp_start_job_wrapper(struct mali_session_data *session_data, _mali_uk_gp_start_job_s __user *uargs) @@ -36,6 +36,7 @@ int gp_start_job_wrapper(struct mali_session_data *session_data, _mali_uk_gp_sta if (_MALI_OSK_ERR_OK != err) return map_errcode(err); kargs.ctx = NULL; /* prevent kernel address to be returned to user space */ + if (0 != copy_to_user(uargs, &kargs, sizeof(_mali_uk_gp_start_job_s))) { /* @@ -53,22 +54,6 @@ int gp_start_job_wrapper(struct mali_session_data *session_data, _mali_uk_gp_sta return 0; } -int gp_abort_job_wrapper(struct mali_session_data *session_data, _mali_uk_gp_abort_job_s __user *uargs) -{ - _mali_uk_gp_abort_job_s kargs; - - MALI_CHECK_NON_NULL(uargs, -EINVAL); - MALI_CHECK_NON_NULL(session_data, -EINVAL); - - if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_gp_abort_job_s))) return -EFAULT; - - kargs.ctx = session_data; - _mali_ukk_gp_abort_job(&kargs); - - return 0; -} - - int gp_get_core_version_wrapper(struct mali_session_data *session_data, _mali_uk_get_gp_core_version_s __user *uargs) { _mali_uk_get_gp_core_version_s kargs; diff --git a/drivers/media/video/samsung/mali/linux/mali_ukk_mem.c b/drivers/media/video/samsung/mali/linux/mali_ukk_mem.c index 0b98e41..260f257 100644 --- a/drivers/media/video/samsung/mali/linux/mali_ukk_mem.c +++ b/drivers/media/video/samsung/mali/linux/mali_ukk_mem.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -13,7 +13,7 @@ #include "mali_ukk.h" #include "mali_osk.h" #include "mali_kernel_common.h" -#include "mali_kernel_session_manager.h" +#include "mali_session.h" #include "mali_ukk_wrappers.h" int mem_init_wrapper(struct mali_session_data *session_data, _mali_uk_init_mem_s __user *uargs) @@ -257,80 +257,3 @@ err_exit: if (kargs.buffer) _mali_osk_vfree(kargs.buffer); return rc; } - - - -int mem_get_big_block_wrapper( struct file * filp, _mali_uk_get_big_block_s __user * argument ) -{ - _mali_uk_get_big_block_s uk_args; - _mali_osk_errcode_t err_code; - - /* validate input */ - /* the session_data pointer was validated by caller */ - MALI_CHECK_NON_NULL( argument, -EINVAL); - - /* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */ - if ( 0 != copy_from_user(&uk_args, (void __user *)argument, sizeof(_mali_uk_get_big_block_s)) ) - { - return -EFAULT; - } - - /* This interface inserts something into the ukk_private word */ - uk_args.ukk_private = (u32)filp; - uk_args.ctx = filp->private_data; - err_code = _mali_ukk_get_big_block( &uk_args ); - - /* Do not leak the private word back into user space */ - uk_args.ukk_private = 0; - - if ( _MALI_OSK_ERR_OK != err_code ) - { - return map_errcode(err_code); - } - - /* From this point on, we must roll-back any failing action to preserve the - * meaning of the U/K interface (e.g. when excluded) */ - - /* transfer response back to user space */ - if ( 0 != copy_to_user(argument, &uk_args, sizeof(_mali_uk_get_big_block_s)) ) - { - /* Roll-back - the _mali_uk_get_big_block call succeeded, so all - * values in uk_args will be correct */ - _mali_uk_free_big_block_s uk_args_rollback = {0, }; - - uk_args_rollback.ctx = uk_args.ctx; - uk_args_rollback.cookie = uk_args.cookie; - err_code = _mali_ukk_free_big_block( &uk_args_rollback ); - - if ( _MALI_OSK_ERR_OK != err_code ) - { - /* error in DEBUG and RELEASE */ - MALI_PRINT_ERROR( ("Failed to rollback get_big_block: %.8X\n", (u32)err_code) ); - } - return -EFAULT; - } - - return 0; -} - -int mem_free_big_block_wrapper(struct mali_session_data *session_data, _mali_uk_free_big_block_s __user * argument) -{ - _mali_uk_free_big_block_s uk_args; - _mali_osk_errcode_t err_code; - - /* validate input */ - /* the session_data pointer was validated by caller */ - MALI_CHECK_NON_NULL( argument, -EINVAL ); - - /* get call arguments from user space. get_user returns 0 on success */ - if ( 0 != get_user(uk_args.cookie, &argument->cookie) ) - { - return -EFAULT; - } - - uk_args.ctx = session_data; - err_code = _mali_ukk_free_big_block( &uk_args ); - - /* Return the error that _mali_ukk_free_big_block produced */ - return map_errcode(err_code); -} diff --git a/drivers/media/video/samsung/mali/linux/mali_ukk_pp.c b/drivers/media/video/samsung/mali/linux/mali_ukk_pp.c index 31e2a6a..c11c61b 100644 --- a/drivers/media/video/samsung/mali/linux/mali_ukk_pp.c +++ b/drivers/media/video/samsung/mali/linux/mali_ukk_pp.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010, 2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -13,7 +13,7 @@ #include "mali_ukk.h" #include "mali_osk.h" #include "mali_kernel_common.h" -#include "mali_kernel_session_manager.h" +#include "mali_session.h" #include "mali_ukk_wrappers.h" int pp_start_job_wrapper(struct mali_session_data *session_data, _mali_uk_pp_start_job_s __user *uargs) @@ -35,36 +35,6 @@ int pp_start_job_wrapper(struct mali_session_data *session_data, _mali_uk_pp_sta err = _mali_ukk_pp_start_job(&kargs); if (_MALI_OSK_ERR_OK != err) return map_errcode(err); - if (0 != put_user(kargs.returned_user_job_ptr, &uargs->returned_user_job_ptr) || - 0 != put_user(kargs.status, &uargs->status)) - { - /* - * If this happens, then user space will not know that the job was actually started, - * and if we return a queued job, then user space will still think that one is still queued. - * This will typically lead to a deadlock in user space. - * This could however only happen if user space deliberately passes a user buffer which - * passes the access_ok(VERIFY_WRITE) check, but isn't fully writable at the time of copy_to_user(). - * The official Mali driver will never attempt to do that, and kernel space should not be affected. - * That is why we do not bother to do a complex rollback in this very very very rare case. - */ - return -EFAULT; - } - - return 0; -} - -int pp_abort_job_wrapper(struct mali_session_data *session_data, _mali_uk_pp_abort_job_s __user *uargs) -{ - _mali_uk_pp_abort_job_s kargs; - - MALI_CHECK_NON_NULL(uargs, -EINVAL); - MALI_CHECK_NON_NULL(session_data, -EINVAL); - - if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_pp_abort_job_s))) return -EFAULT; - - kargs.ctx = session_data; - _mali_ukk_pp_abort_job(&kargs); - return 0; } @@ -101,3 +71,18 @@ int pp_get_core_version_wrapper(struct mali_session_data *session_data, _mali_uk return 0; } + +int pp_disable_wb_wrapper(struct mali_session_data *session_data, _mali_uk_pp_disable_wb_s __user *uargs) +{ + _mali_uk_pp_disable_wb_s kargs; + + MALI_CHECK_NON_NULL(uargs, -EINVAL); + MALI_CHECK_NON_NULL(session_data, -EINVAL); + + if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_pp_disable_wb_s))) return -EFAULT; + + kargs.ctx = session_data; + _mali_ukk_pp_job_disable_wb(&kargs); + + return 0; +} diff --git a/drivers/media/video/samsung/mali/linux/mali_ukk_profiling.c b/drivers/media/video/samsung/mali/linux/mali_ukk_profiling.c index 17366be..7324d9d 100644 --- a/drivers/media/video/samsung/mali/linux/mali_ukk_profiling.c +++ b/drivers/media/video/samsung/mali/linux/mali_ukk_profiling.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -9,11 +9,12 @@ */ #include <linux/fs.h> /* file system operations */ #include <asm/uaccess.h> /* user space access */ +#include <linux/slab.h> #include "mali_ukk.h" #include "mali_osk.h" #include "mali_kernel_common.h" -#include "mali_kernel_session_manager.h" +#include "mali_session.h" #include "mali_ukk_wrappers.h" int profiling_start_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_start_s __user *uargs) @@ -133,51 +134,49 @@ int profiling_clear_wrapper(struct mali_session_data *session_data, _mali_uk_pro return 0; } -int profiling_get_config_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_get_config_s __user *uargs) +int profiling_report_sw_counters_wrapper(struct mali_session_data *session_data, _mali_uk_sw_counters_report_s __user *uargs) { - _mali_uk_profiling_get_config_s kargs; + _mali_uk_sw_counters_report_s kargs; _mali_osk_errcode_t err; + u32 *counter_buffer; MALI_CHECK_NON_NULL(uargs, -EINVAL); - kargs.ctx = session_data; - err = _mali_ukk_profiling_get_config(&kargs); - if (_MALI_OSK_ERR_OK != err) + if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_sw_counters_report_s))) { - return map_errcode(err); + return -EFAULT; } - if (0 != put_user(kargs.enable_events, &uargs->enable_events)) - { - return -EFAULT; + /* make sure that kargs.num_counters is [at least somewhat] sane */ + if (kargs.num_counters > 10000) { + MALI_DEBUG_PRINT(1, ("User space attempted to allocate too many counters.\n")); + return -EINVAL; } - return 0; -} + counter_buffer = (u32*)kmalloc(sizeof(u32) * kargs.num_counters, GFP_KERNEL); + if (NULL == counter_buffer) + { + return -ENOMEM; + } -#if MALI_TRACEPOINTS_ENABLED -int transfer_sw_counters_wrapper(struct mali_session_data *session_data, _mali_uk_sw_counters_s __user *uargs) -{ - _mali_uk_sw_counters_s kargs; - _mali_osk_errcode_t err; + if (0 != copy_from_user(counter_buffer, kargs.counters, sizeof(u32) * kargs.num_counters)) + { + kfree(counter_buffer); + return -EFAULT; + } - MALI_CHECK_NON_NULL(uargs, -EINVAL); - - kargs.ctx = session_data; + kargs.ctx = session_data; + kargs.counters = counter_buffer; - if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_sw_counters_s))) - { - return -EFAULT; - } + err = _mali_ukk_sw_counters_report(&kargs); - err = _mali_ukk_transfer_sw_counters(&kargs); + kfree(counter_buffer); - if (_MALI_OSK_ERR_OK != err) - { - return map_errcode(err); - } + if (_MALI_OSK_ERR_OK != err) + { + return map_errcode(err); + } - return 0; + return 0; } -#endif diff --git a/drivers/media/video/samsung/mali/linux/mali_ukk_vsync.c b/drivers/media/video/samsung/mali/linux/mali_ukk_vsync.c index 80a6afd..f9b5a3e 100644 --- a/drivers/media/video/samsung/mali/linux/mali_ukk_vsync.c +++ b/drivers/media/video/samsung/mali/linux/mali_ukk_vsync.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2011-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -13,7 +13,7 @@ #include "mali_ukk.h" #include "mali_osk.h" #include "mali_kernel_common.h" -#include "mali_kernel_session_manager.h" +#include "mali_session.h" #include "mali_ukk_wrappers.h" diff --git a/drivers/media/video/samsung/mali/linux/mali_ukk_wrappers.h b/drivers/media/video/samsung/mali/linux/mali_ukk_wrappers.h index 184ce8d..b568ce7 100644 --- a/drivers/media/video/samsung/mali/linux/mali_ukk_wrappers.h +++ b/drivers/media/video/samsung/mali/linux/mali_ukk_wrappers.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -28,6 +28,7 @@ int get_system_info_size_wrapper(struct mali_session_data *session_data, _mali_u int get_system_info_wrapper(struct mali_session_data *session_data, _mali_uk_get_system_info_s __user *uargs); int wait_for_notification_wrapper(struct mali_session_data *session_data, _mali_uk_wait_for_notification_s __user *uargs); int get_api_version_wrapper(struct mali_session_data *session_data, _mali_uk_get_api_version_s __user *uargs); +int get_user_settings_wrapper(struct mali_session_data *session_data, _mali_uk_get_user_settings_s __user *uargs); int post_notification_wrapper(struct mali_session_data *session_data, _mali_uk_post_notification_s __user *uargs); int mem_init_wrapper(struct mali_session_data *session_data, _mali_uk_init_mem_s __user *uargs); int mem_term_wrapper(struct mali_session_data *session_data, _mali_uk_term_mem_s __user *uargs); @@ -41,14 +42,11 @@ int mem_attach_ump_wrapper(struct mali_session_data *session_data, _mali_uk_atta int mem_release_ump_wrapper(struct mali_session_data *session_data, _mali_uk_release_ump_mem_s __user * argument); #endif /* MALI_USE_UNIFIED_MEMORY_PROVIDER */ -int mem_get_big_block_wrapper( struct file * filp, _mali_uk_get_big_block_s __user * argument ); -int mem_free_big_block_wrapper( struct mali_session_data *session_data, _mali_uk_free_big_block_s __user * argument); int pp_start_job_wrapper(struct mali_session_data *session_data, _mali_uk_pp_start_job_s __user *uargs); -int pp_abort_job_wrapper(struct mali_session_data *session_data, _mali_uk_pp_abort_job_s __user *uargs); int pp_get_number_of_cores_wrapper(struct mali_session_data *session_data, _mali_uk_get_pp_number_of_cores_s __user *uargs); int pp_get_core_version_wrapper(struct mali_session_data *session_data, _mali_uk_get_pp_core_version_s __user *uargs); +int pp_disable_wb_wrapper(struct mali_session_data *session_data, _mali_uk_pp_disable_wb_s __user *uargs); int gp_start_job_wrapper(struct mali_session_data *session_data, _mali_uk_gp_start_job_s __user *uargs); -int gp_abort_job_wrapper(struct mali_session_data *session_data, _mali_uk_gp_abort_job_s __user *uargs); int gp_get_number_of_cores_wrapper(struct mali_session_data *session_data, _mali_uk_get_gp_number_of_cores_s __user *uargs); int gp_get_core_version_wrapper(struct mali_session_data *session_data, _mali_uk_get_gp_core_version_s __user *uargs); int gp_suspend_response_wrapper(struct mali_session_data *session_data, _mali_uk_gp_suspend_response_s __user *uargs); @@ -58,14 +56,10 @@ int profiling_add_event_wrapper(struct mali_session_data *session_data, _mali_uk int profiling_stop_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_stop_s __user *uargs); int profiling_get_event_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_get_event_s __user *uargs); int profiling_clear_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_clear_s __user *uargs); -int profiling_get_config_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_get_config_s __user *uargs); +int profiling_report_sw_counters_wrapper(struct mali_session_data *session_data, _mali_uk_sw_counters_report_s __user *uargs); int vsync_event_report_wrapper(struct mali_session_data *session_data, _mali_uk_vsync_event_report_s __user *uargs); -#if MALI_TRACEPOINTS_ENABLED -int transfer_sw_counters_wrapper(struct mali_session_data *session_data, _mali_uk_sw_counters_s __user *uargs); -#endif - int map_errcode( _mali_osk_errcode_t err ); #ifdef __cplusplus diff --git a/drivers/media/video/samsung/mali/platform/default/mali_platform.c b/drivers/media/video/samsung/mali/platform/default/mali_platform.c index 44f877e..9e64ce7 100644 --- a/drivers/media/video/samsung/mali/platform/default/mali_platform.c +++ b/drivers/media/video/samsung/mali/platform/default/mali_platform.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2011 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -39,3 +39,5 @@ void mali_gpu_utilization_handler(u32 utilization) void set_mali_parent_power_domain(void* dev) { } + + diff --git a/drivers/media/video/samsung/mali/platform/mali_platform.h b/drivers/media/video/samsung/mali/platform/mali_platform.h index 70cfa14..6e55dee 100644 --- a/drivers/media/video/samsung/mali/platform/mali_platform.h +++ b/drivers/media/video/samsung/mali/platform/mali_platform.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -21,12 +21,7 @@ #ifdef CONFIG_CPU_EXYNOS4210 #define MALI_DVFS_STEPS 2 #else -#define MALI_DVFS_STEPS 4 -#endif - -#if !USING_MALI_PMM -/* @brief System power up/down cores that can be passed into mali_platform_powerdown/up() */ -#define MALI_PLATFORM_SYSTEM 0 +#define MALI_DVFS_STEPS 5 #endif /* @Enable or Disable Mali GPU Bottom Lock feature */ @@ -34,6 +29,9 @@ #define MALI_VOLTAGE_LOCK 1 +/* @Enable or Disable the CPU frequency lock when the GPU clock is 440 Mhz */ +#define CPUFREQ_LOCK_DURING_440 0 + #ifdef __cplusplus extern "C" { #endif @@ -42,9 +40,9 @@ extern "C" { */ typedef enum mali_power_mode_tag { - MALI_POWER_MODE_ON, - MALI_POWER_MODE_LIGHT_SLEEP, - MALI_POWER_MODE_DEEP_SLEEP, + MALI_POWER_MODE_ON, /**< Power Mali on */ + MALI_POWER_MODE_LIGHT_SLEEP, /**< Mali has been idle for a short time, or runtime PM suspend */ + MALI_POWER_MODE_DEEP_SLEEP, /**< Mali has been idle for a long time, or OS suspend */ } mali_power_mode; /** @brief Platform specific setup and initialisation of MALI @@ -65,22 +63,8 @@ _mali_osk_errcode_t mali_platform_deinit(void); /** @brief Platform specific powerdown sequence of MALI * - * Call as part of platform init if there is no PMM support, else the - * PMM will call it. - * There are three power modes defined: - * 1) MALI_POWER_MODE_ON - * 2) MALI_POWER_MODE_LIGHT_SLEEP - * 3) MALI_POWER_MODE_DEEP_SLEEP - * MALI power management module transitions to MALI_POWER_MODE_LIGHT_SLEEP mode when MALI is idle - * for idle timer (software timer defined in mali_pmm_policy_jobcontrol.h) duration, MALI transitions - * to MALI_POWER_MODE_LIGHT_SLEEP mode during timeout if there are no more jobs queued. - * MALI power management module transitions to MALI_POWER_MODE_DEEP_SLEEP mode when OS does system power - * off. - * Customer has to add power down code when MALI transitions to MALI_POWER_MODE_LIGHT_SLEEP or MALI_POWER_MODE_DEEP_SLEEP - * mode. - * MALI_POWER_MODE_ON mode is entered when the MALI is to powered up. Some customers want to control voltage regulators during - * the whole system powers on/off. Customer can track in this function whether the MALI is powered up from - * MALI_POWER_MODE_LIGHT_SLEEP or MALI_POWER_MODE_DEEP_SLEEP mode and manage the voltage regulators as well. + * Notification from the Mali device driver stating the new desired power mode. + * MALI_POWER_MODE_ON must be obeyed, while the other modes are optional. * @param power_mode defines the power modes * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. */ diff --git a/drivers/media/video/samsung/mali/platform/mali_platform_pmu_testing/mali_platform.c b/drivers/media/video/samsung/mali/platform/mali_platform_pmu_testing/mali_platform.c new file mode 100644 index 0000000..cb95dc6 --- /dev/null +++ b/drivers/media/video/samsung/mali/platform/mali_platform_pmu_testing/mali_platform.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** + * @file mali_platform.c + * Platform specific Mali driver functions for a default platform + */ +#include "mali_kernel_common.h" +#include "mali_osk.h" +#include "mali_platform.h" +#include "mali_pmu.h" +#include "linux/mali/mali_utgard.h" + +static u32 bPowerOff = 1; + +_mali_osk_errcode_t mali_platform_init(void) +{ + MALI_SUCCESS; +} + +_mali_osk_errcode_t mali_platform_deinit(void) +{ + MALI_SUCCESS; +} + +_mali_osk_errcode_t mali_platform_power_mode_change(mali_power_mode power_mode) +{ + switch (power_mode) + { + case MALI_POWER_MODE_ON: + if (bPowerOff == 1) + { + mali_pmu_powerup(); + bPowerOff = 0; + } + break; + case MALI_POWER_MODE_LIGHT_SLEEP: + case MALI_POWER_MODE_DEEP_SLEEP: + + if (bPowerOff == 0) + { + mali_pmu_powerdown(); + bPowerOff = 1; + } + + break; + } + MALI_SUCCESS; +} + +void mali_gpu_utilization_handler(u32 utilization) +{ +} + +void set_mali_parent_power_domain(void* dev) +{ +} + + diff --git a/drivers/media/video/samsung/mali/platform/orion-m400/mali_platform.c b/drivers/media/video/samsung/mali/platform/orion-m400/mali_platform.c index 0fc4503..792b9a9 100644 --- a/drivers/media/video/samsung/mali/platform/orion-m400/mali_platform.c +++ b/drivers/media/video/samsung/mali/platform/orion-m400/mali_platform.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. diff --git a/drivers/media/video/samsung/mali/platform/orion-m400/mali_platform_dvfs.c b/drivers/media/video/samsung/mali/platform/orion-m400/mali_platform_dvfs.c index 9e6edba..f8d76dc 100644 --- a/drivers/media/video/samsung/mali/platform/orion-m400/mali_platform_dvfs.c +++ b/drivers/media/video/samsung/mali/platform/orion-m400/mali_platform_dvfs.c @@ -1,414 +1 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** - * @file mali_platform_dvfs.c - * Platform specific Mali driver dvfs functions - */ - -#include "mali_kernel_common.h" -#include "mali_osk.h" -#include "mali_platform.h" - -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/regulator/consumer.h> -#include <linux/regulator/driver.h> - -#include <asm/io.h> - -#ifdef CONFIG_CPU_FREQ -#include <mach/asv.h> -#include <mach/regs-pmu.h> -#define EXYNOS4_ASV_ENABLED -#endif - -#include "mali_device_pause_resume.h" -#include <linux/workqueue.h> - -#define MALI_DVFS_WATING 10 // msec - -static int bMaliDvfsRun=0; - -#if MALI_GPU_BOTTOM_LOCK -static _mali_osk_atomic_t bottomlock_status; -#endif - -typedef struct mali_dvfs_tableTag{ - unsigned int clock; - unsigned int freq; - unsigned int vol; -}mali_dvfs_table; - -typedef struct mali_dvfs_statusTag{ - unsigned int currentStep; - mali_dvfs_table * pCurrentDvfs; - -}mali_dvfs_currentstatus; - -typedef struct mali_dvfs_thresholdTag{ - unsigned int downthreshold; - unsigned int upthreshold; -}mali_dvfs_threshold_table; - -typedef struct mali_dvfs_staycount{ - unsigned int staycount; -}mali_dvfs_staycount_table; - -mali_dvfs_staycount_table mali_dvfs_staycount[MALI_DVFS_STEPS]={ - /*step 0*/{1}, - /*step 1*/{1},}; - -/*dvfs threshold*/ -mali_dvfs_threshold_table mali_dvfs_threshold[MALI_DVFS_STEPS]={ - /*step 0*/{((int)((255*0)/100)), ((int)((255*85)/100))}, - /*step 1*/{((int)((255*75)/100)), ((int)((255*100)/100))} }; - -/*dvfs status*/ -mali_dvfs_currentstatus maliDvfsStatus; -int mali_dvfs_control=0; - -/*dvfs table*/ -mali_dvfs_table mali_dvfs[MALI_DVFS_STEPS]={ - /*step 0*/{160 ,1000000 , 950000}, - /*step 1*/{267 ,1000000 ,1000000} }; - -#ifdef EXYNOS4_ASV_ENABLED - -#define ASV_8_LEVEL 8 -#define ASV_5_LEVEL 5 - -static unsigned int asv_3d_volt_5_table[ASV_5_LEVEL][MALI_DVFS_STEPS] = { - /* L3(160MHz), L2(266MHz) */ - {1000000, 1100000}, /* S */ - {1000000, 1100000}, /* A */ - { 950000, 1000000}, /* B */ - { 950000, 1000000}, /* C */ - { 950000, 950000}, /* D */ -}; - -static unsigned int asv_3d_volt_8_table[ASV_8_LEVEL][MALI_DVFS_STEPS] = { - /* L3(160MHz), L2(266MHz)) */ - {1000000, 1100000}, /* SS */ - {1000000, 1100000}, /* A1 */ - {1000000, 1100000}, /* A2 */ - { 950000, 1000000}, /* B1 */ - { 950000, 1000000}, /* B2 */ - { 950000, 1000000}, /* C1 */ - { 950000, 1000000}, /* C2 */ - { 950000, 950000}, /* D1 */ -}; -#endif - -static u32 mali_dvfs_utilization = 255; - -static void mali_dvfs_work_handler(struct work_struct *w); - -static struct workqueue_struct *mali_dvfs_wq = 0; -extern mali_io_address clk_register_map; - -#if MALI_GPU_BOTTOM_LOCK -extern _mali_osk_lock_t *mali_dvfs_lock; -#endif - -static DECLARE_WORK(mali_dvfs_work, mali_dvfs_work_handler); - -static unsigned int get_mali_dvfs_status(void) -{ - return maliDvfsStatus.currentStep; -} - -#if MALI_GPU_BOTTOM_LOCK -#if MALI_PMM_RUNTIME_JOB_CONTROL_ON -int get_mali_dvfs_control_status(void) -{ - return mali_dvfs_control; -} - -mali_bool set_mali_dvfs_current_step(unsigned int step) -{ - _mali_osk_lock_wait(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW); - maliDvfsStatus.currentStep = step; - _mali_osk_lock_signal(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW); - return MALI_TRUE; -} -#endif -#endif - -static mali_bool set_mali_dvfs_status(u32 step,mali_bool boostup) -{ - u32 validatedStep=step; - -#ifdef CONFIG_REGULATOR - if (mali_regulator_get_usecount()==0) { - MALI_DEBUG_PRINT(1, ("regulator use_count is 0 \n")); - return MALI_FALSE; - } -#endif - - if (boostup) { -#ifdef CONFIG_REGULATOR - /*change the voltage*/ - mali_regulator_set_voltage(mali_dvfs[step].vol, mali_dvfs[step].vol); -#endif - /*change the clock*/ - mali_clk_set_rate(mali_dvfs[step].clock, mali_dvfs[step].freq); - } else { - /*change the clock*/ - mali_clk_set_rate(mali_dvfs[step].clock, mali_dvfs[step].freq); -#ifdef CONFIG_REGULATOR - /*change the voltage*/ - mali_regulator_set_voltage(mali_dvfs[step].vol, mali_dvfs[step].vol); -#endif - } - - maliDvfsStatus.currentStep = validatedStep; - /*for future use*/ - maliDvfsStatus.pCurrentDvfs = &mali_dvfs[validatedStep]; - - return MALI_TRUE; -} - -static void mali_platform_wating(u32 msec) -{ - /*sample wating - change this in the future with proper check routine. - */ - unsigned int read_val; - while(1) { - read_val = _mali_osk_mem_ioread32(clk_register_map, 0x00); - if ((read_val & 0x8000)==0x0000) break; - - _mali_osk_time_ubusydelay(100); // 1000 -> 100 : 20101218 - } - /* _mali_osk_time_ubusydelay(msec*1000);*/ -} - -static mali_bool change_mali_dvfs_status(u32 step, mali_bool boostup ) -{ - - MALI_DEBUG_PRINT(1, ("> change_mali_dvfs_status: %d, %d \n",step, boostup)); - - if (!set_mali_dvfs_status(step, boostup)) { - MALI_DEBUG_PRINT(1, ("error on set_mali_dvfs_status: %d, %d \n",step, boostup)); - return MALI_FALSE; - } - - /*wait until clock and voltage is stablized*/ - mali_platform_wating(MALI_DVFS_WATING); /*msec*/ - - return MALI_TRUE; -} - -static unsigned int decideNextStatus(unsigned int utilization) -{ - unsigned int level=0; // 0:stay, 1:up - - if (!mali_dvfs_control) { -#if MALI_GPU_BOTTOM_LOCK - if (_mali_osk_atomic_read(&bottomlock_status) > 0) - level = 1; /* or bigger */ - else if (utilization > mali_dvfs_threshold[maliDvfsStatus.currentStep].upthreshold) -#else - if (utilization > mali_dvfs_threshold[maliDvfsStatus.currentStep].upthreshold) -#endif - level=1; - else if (utilization < mali_dvfs_threshold[maliDvfsStatus.currentStep].downthreshold) - level=0; - else - level = maliDvfsStatus.currentStep; - } else { - if ((mali_dvfs_control > 0) && (mali_dvfs_control < mali_dvfs[1].clock)) - level=0; - else - level=1; - } - - return level; -} - -#ifdef EXYNOS4_ASV_ENABLED -static mali_bool mali_dvfs_table_update(void) -{ - unsigned int exynos_result_of_asv_group; - unsigned int target_asv; - unsigned int i; - exynos_result_of_asv_group = exynos_result_of_asv & 0xf; - target_asv = exynos_result_of_asv >> 28; - MALI_PRINT(("exynos_result_of_asv_group = 0x%x, target_asv = 0x%x\n", exynos_result_of_asv_group, target_asv)); - - if (target_asv == 0x8) { //SUPPORT_1400MHZ - for (i = 0; i < MALI_DVFS_STEPS; i++) { - mali_dvfs[i].vol = asv_3d_volt_5_table[exynos_result_of_asv_group][i]; - MALI_PRINT(("mali_dvfs[%d].vol = %d\n", i, mali_dvfs[i].vol)); - } - } else if (target_asv == 0x4){ //SUPPORT_1200MHZ - for (i = 0; i < MALI_DVFS_STEPS; i++) { - mali_dvfs[i].vol = asv_3d_volt_8_table[exynos_result_of_asv_group][i]; - MALI_PRINT(("mali_dvfs[%d].vol = %d\n", i, mali_dvfs[i].vol)); - } - } - - return MALI_TRUE; - -} -#endif - -static mali_bool mali_dvfs_status(u32 utilization) -{ - unsigned int nextStatus = 0; - unsigned int curStatus = 0; - mali_bool boostup = MALI_FALSE; -#ifdef EXYNOS4_ASV_ENABLED - static mali_bool asv_applied = MALI_FALSE; -#endif - static int stay_count = 0; // to prevent frequent switch - - MALI_DEBUG_PRINT(1, ("> mali_dvfs_status: %d \n",utilization)); -#ifdef EXYNOS4_ASV_ENABLED - if (asv_applied == MALI_FALSE) { - mali_dvfs_table_update(); - change_mali_dvfs_status(0,0); - asv_applied = MALI_TRUE; - - return MALI_TRUE; - } -#endif - - /*decide next step*/ - curStatus = get_mali_dvfs_status(); - nextStatus = decideNextStatus(utilization); - - MALI_DEBUG_PRINT(1, ("= curStatus %d, nextStatus %d, maliDvfsStatus.currentStep %d \n", curStatus, nextStatus, maliDvfsStatus.currentStep)); - - /*if next status is same with current status, don't change anything*/ - if ((curStatus!=nextStatus && stay_count==0)) { - /*check if boost up or not*/ - if (nextStatus > maliDvfsStatus.currentStep) - boostup = 1; - - /*change mali dvfs status*/ - if (!change_mali_dvfs_status(nextStatus,boostup)) { - MALI_DEBUG_PRINT(1, ("error on change_mali_dvfs_status \n")); - return MALI_FALSE; - } - stay_count = mali_dvfs_staycount[maliDvfsStatus.currentStep].staycount; - } else { - if (stay_count>0) - stay_count--; - } - - return MALI_TRUE; -} - - - -int mali_dvfs_is_running(void) -{ - return bMaliDvfsRun; -} - - - -void mali_dvfs_late_resume(void) -{ - // set the init clock as low when resume - set_mali_dvfs_status(0,0); -} - - -static void mali_dvfs_work_handler(struct work_struct *w) -{ - bMaliDvfsRun=1; - - MALI_DEBUG_PRINT(3, ("=== mali_dvfs_work_handler\n")); - - if (!mali_dvfs_status(mali_dvfs_utilization)) - MALI_DEBUG_PRINT(1,( "error on mali dvfs status in mali_dvfs_work_handler")); - - bMaliDvfsRun=0; -} - - -mali_bool init_mali_dvfs_status(int step) -{ - /*default status - add here with the right function to get initilization value. - */ - if (!mali_dvfs_wq) - mali_dvfs_wq = create_singlethread_workqueue("mali_dvfs"); - -#if MALI_GPU_BOTTOM_LOCK - _mali_osk_atomic_init(&bottomlock_status, 0); -#endif - - /*add a error handling here*/ - maliDvfsStatus.currentStep = step; - - return MALI_TRUE; -} - -void deinit_mali_dvfs_status(void) -{ -#if MALI_GPU_BOTTOM_LOCK - _mali_osk_atomic_term(&bottomlock_status); -#endif - - if (mali_dvfs_wq) - destroy_workqueue(mali_dvfs_wq); - mali_dvfs_wq = NULL; -} - -mali_bool mali_dvfs_handler(u32 utilization) -{ - mali_dvfs_utilization = utilization; - queue_work_on(0, mali_dvfs_wq,&mali_dvfs_work); - - /*add error handle here*/ - return MALI_TRUE; -} - -void mali_default_step_set(int step, mali_bool boostup) -{ - mali_clk_set_rate(mali_dvfs[step].clock, mali_dvfs[step].freq); - - if (maliDvfsStatus.currentStep == 1) - set_mali_dvfs_status(step, boostup); -} - -#if MALI_GPU_BOTTOM_LOCK -int mali_dvfs_bottom_lock_push(void) -{ - int prev_status = _mali_osk_atomic_read(&bottomlock_status); - - if (prev_status < 0) { - MALI_PRINT(("gpu bottom lock status is not valid for push")); - return -1; - } - - if (prev_status == 0) { - mali_regulator_set_voltage(mali_dvfs[1].vol, mali_dvfs[1].vol); - mali_clk_set_rate(mali_dvfs[1].clock, mali_dvfs[1].freq); - set_mali_dvfs_current_step(1); - } - - return _mali_osk_atomic_inc_return(&bottomlock_status); -} - -int mali_dvfs_bottom_lock_pop(void) -{ - if (_mali_osk_atomic_read(&bottomlock_status) <= 0) { - MALI_PRINT(("gpu bottom lock status is not valid for pop")); - return -1; - } - - return _mali_osk_atomic_dec_return(&bottomlock_status); -} -#endif +/* * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained from Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* @file mali_platform_dvfs.c
* Platform specific Mali driver dvfs functions
*/
#include "mali_kernel_common.h"
#include "mali_osk.h"
#include "mali_platform.h"
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h>
#include <asm/io.h>
#ifdef CONFIG_CPU_FREQ
#include <mach/asv.h>
#include <mach/regs-pmu.h>
#define EXYNOS4_ASV_ENABLED
#endif
#include "mali_device_pause_resume.h"
#include <linux/workqueue.h>
#define MALI_DVFS_WATING 10 // msec
static int bMaliDvfsRun=0;
#if MALI_GPU_BOTTOM_LOCK
static _mali_osk_atomic_t bottomlock_status;
#endif
typedef struct mali_dvfs_tableTag{
unsigned int clock;
unsigned int freq;
unsigned int vol;
}mali_dvfs_table;
typedef struct mali_dvfs_statusTag{
unsigned int currentStep;
mali_dvfs_table * pCurrentDvfs;
}mali_dvfs_currentstatus;
typedef struct mali_dvfs_thresholdTag{
unsigned int downthreshold;
unsigned int upthreshold;
}mali_dvfs_threshold_table;
typedef struct mali_dvfs_staycount{
unsigned int staycount;
}mali_dvfs_staycount_table;
mali_dvfs_staycount_table mali_dvfs_staycount[MALI_DVFS_STEPS]={
/*step 0*/{1},
/*step 1*/{1},};
/*dvfs threshold*/
mali_dvfs_threshold_table mali_dvfs_threshold[MALI_DVFS_STEPS]={
/*step 0*/{((int)((255*0)/100)), ((int)((255*85)/100))},
/*step 1*/{((int)((255*75)/100)), ((int)((255*100)/100))} };
/*dvfs status*/
mali_dvfs_currentstatus maliDvfsStatus;
int mali_dvfs_control=0;
/*dvfs table*/
mali_dvfs_table mali_dvfs[MALI_DVFS_STEPS]={
/*step 0*/{160 ,1000000 , 950000},
/*step 1*/{267 ,1000000 ,1000000} };
#ifdef EXYNOS4_ASV_ENABLED
#define ASV_8_LEVEL 8
#define ASV_5_LEVEL 5
#define ASV_LEVEL_SUPPORT 0
static unsigned int asv_3d_volt_5_table[ASV_5_LEVEL][MALI_DVFS_STEPS] = {
/* L3(160MHz), L2(266MHz) */
{1000000, 1100000}, /* S */
{1000000, 1100000}, /* A */
{ 950000, 1000000}, /* B */
{ 950000, 1000000}, /* C */
{ 950000, 950000}, /* D */
};
static unsigned int asv_3d_volt_8_table[ASV_8_LEVEL][MALI_DVFS_STEPS] = {
/* L3(160MHz), L2(266MHz)) */
{1000000, 1100000}, /* SS */
{1000000, 1100000}, /* A1 */
{1000000, 1100000}, /* A2 */
{ 950000, 1000000}, /* B1 */
{ 950000, 1000000}, /* B2 */
{ 950000, 1000000}, /* C1 */
{ 950000, 1000000}, /* C2 */
{ 950000, 950000}, /* D1 */
};
#endif
static u32 mali_dvfs_utilization = 255;
static void mali_dvfs_work_handler(struct work_struct *w);
static struct workqueue_struct *mali_dvfs_wq = 0;
extern mali_io_address clk_register_map;
#if MALI_GPU_BOTTOM_LOCK
extern _mali_osk_lock_t *mali_dvfs_lock;
#endif
static DECLARE_WORK(mali_dvfs_work, mali_dvfs_work_handler);
static unsigned int get_mali_dvfs_status(void)
{
return maliDvfsStatus.currentStep;
}
#if MALI_GPU_BOTTOM_LOCK
#if MALI_PMM_RUNTIME_JOB_CONTROL_ON
int get_mali_dvfs_control_status(void)
{
return mali_dvfs_control;
}
mali_bool set_mali_dvfs_current_step(unsigned int step)
{
_mali_osk_lock_wait(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW);
maliDvfsStatus.currentStep = step;
_mali_osk_lock_signal(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW);
return MALI_TRUE;
}
#endif
#endif
static mali_bool set_mali_dvfs_status(u32 step,mali_bool boostup)
{
u32 validatedStep=step;
#ifdef CONFIG_REGULATOR
if (mali_regulator_get_usecount()==0) {
MALI_DEBUG_PRINT(1, ("regulator use_count is 0 \n"));
return MALI_FALSE;
}
#endif
if (boostup) {
#ifdef CONFIG_REGULATOR
/*change the voltage*/
mali_regulator_set_voltage(mali_dvfs[step].vol, mali_dvfs[step].vol);
#endif
/*change the clock*/
mali_clk_set_rate(mali_dvfs[step].clock, mali_dvfs[step].freq);
} else {
/*change the clock*/
mali_clk_set_rate(mali_dvfs[step].clock, mali_dvfs[step].freq);
#ifdef CONFIG_REGULATOR
/*change the voltage*/
mali_regulator_set_voltage(mali_dvfs[step].vol, mali_dvfs[step].vol);
#endif
}
maliDvfsStatus.currentStep = validatedStep;
/*for future use*/
maliDvfsStatus.pCurrentDvfs = &mali_dvfs[validatedStep];
return MALI_TRUE;
}
static void mali_platform_wating(u32 msec)
{
/*sample wating
change this in the future with proper check routine.
*/
unsigned int read_val;
while(1) {
read_val = _mali_osk_mem_ioread32(clk_register_map, 0x00);
if ((read_val & 0x8000)==0x0000) break;
_mali_osk_time_ubusydelay(100); // 1000 -> 100 : 20101218
}
/* _mali_osk_time_ubusydelay(msec*1000);*/
}
static mali_bool change_mali_dvfs_status(u32 step, mali_bool boostup )
{
MALI_DEBUG_PRINT(1, ("> change_mali_dvfs_status: %d, %d \n",step, boostup));
if (!set_mali_dvfs_status(step, boostup)) {
MALI_DEBUG_PRINT(1, ("error on set_mali_dvfs_status: %d, %d \n",step, boostup));
return MALI_FALSE;
}
/*wait until clock and voltage is stablized*/
mali_platform_wating(MALI_DVFS_WATING); /*msec*/
return MALI_TRUE;
}
static unsigned int decideNextStatus(unsigned int utilization)
{
unsigned int level=0; // 0:stay, 1:up
if (!mali_dvfs_control) {
#if MALI_GPU_BOTTOM_LOCK
if (_mali_osk_atomic_read(&bottomlock_status) > 0)
level = 1; /* or bigger */
else if (utilization > mali_dvfs_threshold[maliDvfsStatus.currentStep].upthreshold)
#else
if (utilization > mali_dvfs_threshold[maliDvfsStatus.currentStep].upthreshold)
#endif
level=1;
else if (utilization < mali_dvfs_threshold[maliDvfsStatus.currentStep].downthreshold)
level=0;
else
level = maliDvfsStatus.currentStep;
} else {
if ((mali_dvfs_control > 0) && (mali_dvfs_control < mali_dvfs[1].clock))
level=0;
else
level=1;
}
return level;
}
#ifdef EXYNOS4_ASV_ENABLED
static mali_bool mali_dvfs_table_update(void)
{
unsigned int exynos_result_of_asv_group;
unsigned int i;
exynos_result_of_asv_group = exynos_result_of_asv & 0xf;
MALI_PRINT(("exynos_result_of_asv_group = 0x%x\n", exynos_result_of_asv_group));
if (ASV_LEVEL_SUPPORT) { //asv level information will be added.
for (i = 0; i < MALI_DVFS_STEPS; i++) {
mali_dvfs[i].vol = asv_3d_volt_5_table[exynos_result_of_asv_group][i];
MALI_PRINT(("mali_dvfs[%d].vol = %d\n", i, mali_dvfs[i].vol));
}
} else {
for (i = 0; i < MALI_DVFS_STEPS; i++) {
mali_dvfs[i].vol = asv_3d_volt_8_table[exynos_result_of_asv_group][i];
MALI_PRINT(("mali_dvfs[%d].vol = %d\n", i, mali_dvfs[i].vol));
}
}
return MALI_TRUE;
}
#endif
static mali_bool mali_dvfs_status(u32 utilization)
{
unsigned int nextStatus = 0;
unsigned int curStatus = 0;
mali_bool boostup = MALI_FALSE;
#ifdef EXYNOS4_ASV_ENABLED
static mali_bool asv_applied = MALI_FALSE;
#endif
static int stay_count = 0; // to prevent frequent switch
MALI_DEBUG_PRINT(1, ("> mali_dvfs_status: %d \n",utilization));
#ifdef EXYNOS4_ASV_ENABLED
if (asv_applied == MALI_FALSE) {
mali_dvfs_table_update();
change_mali_dvfs_status(0,0);
asv_applied = MALI_TRUE;
return MALI_TRUE;
}
#endif
/*decide next step*/
curStatus = get_mali_dvfs_status();
nextStatus = decideNextStatus(utilization);
MALI_DEBUG_PRINT(1, ("= curStatus %d, nextStatus %d, maliDvfsStatus.currentStep %d \n", curStatus, nextStatus, maliDvfsStatus.currentStep));
/*if next status is same with current status, don't change anything*/
if ((curStatus!=nextStatus && stay_count==0)) {
/*check if boost up or not*/
if (nextStatus > maliDvfsStatus.currentStep)
boostup = 1;
/*change mali dvfs status*/
if (!change_mali_dvfs_status(nextStatus,boostup)) {
MALI_DEBUG_PRINT(1, ("error on change_mali_dvfs_status \n"));
return MALI_FALSE;
}
stay_count = mali_dvfs_staycount[maliDvfsStatus.currentStep].staycount;
} else {
if (stay_count>0)
stay_count--;
}
return MALI_TRUE;
}
int mali_dvfs_is_running(void)
{
return bMaliDvfsRun;
}
void mali_dvfs_late_resume(void)
{
// set the init clock as low when resume
set_mali_dvfs_status(0,0);
}
static void mali_dvfs_work_handler(struct work_struct *w)
{
bMaliDvfsRun=1;
MALI_DEBUG_PRINT(3, ("=== mali_dvfs_work_handler\n"));
if (!mali_dvfs_status(mali_dvfs_utilization))
MALI_DEBUG_PRINT(1,( "error on mali dvfs status in mali_dvfs_work_handler"));
bMaliDvfsRun=0;
}
mali_bool init_mali_dvfs_status(int step)
{
/*default status
add here with the right function to get initilization value.
*/
if (!mali_dvfs_wq)
mali_dvfs_wq = create_singlethread_workqueue("mali_dvfs");
#if MALI_GPU_BOTTOM_LOCK
_mali_osk_atomic_init(&bottomlock_status, 0);
#endif
/*add a error handling here*/
maliDvfsStatus.currentStep = step;
return MALI_TRUE;
}
void deinit_mali_dvfs_status(void)
{
#if MALI_GPU_BOTTOM_LOCK
_mali_osk_atomic_term(&bottomlock_status);
#endif
if (mali_dvfs_wq)
destroy_workqueue(mali_dvfs_wq);
mali_dvfs_wq = NULL;
}
mali_bool mali_dvfs_handler(u32 utilization)
{
mali_dvfs_utilization = utilization;
queue_work_on(0, mali_dvfs_wq,&mali_dvfs_work);
/*add error handle here*/
return MALI_TRUE;
}
void mali_default_step_set(int step, mali_bool boostup)
{
mali_clk_set_rate(mali_dvfs[step].clock, mali_dvfs[step].freq);
if (maliDvfsStatus.currentStep == 1)
set_mali_dvfs_status(step, boostup);
}
#if MALI_GPU_BOTTOM_LOCK
int mali_dvfs_bottom_lock_push(void)
{
int prev_status = _mali_osk_atomic_read(&bottomlock_status);
if (prev_status < 0) {
MALI_PRINT(("gpu bottom lock status is not valid for push"));
return -1;
}
if (prev_status == 0) {
mali_regulator_set_voltage(mali_dvfs[1].vol, mali_dvfs[1].vol);
mali_clk_set_rate(mali_dvfs[1].clock, mali_dvfs[1].freq);
set_mali_dvfs_current_step(1);
}
return _mali_osk_atomic_inc_return(&bottomlock_status);
}
int mali_dvfs_bottom_lock_pop(void)
{
if (_mali_osk_atomic_read(&bottomlock_status) <= 0) {
MALI_PRINT(("gpu bottom lock status is not valid for pop"));
return -1;
}
return _mali_osk_atomic_dec_return(&bottomlock_status);
}
#endif
\ No newline at end of file diff --git a/drivers/media/video/samsung/mali/platform/pegasus-m400/mali_platform.c b/drivers/media/video/samsung/mali/platform/pegasus-m400/mali_platform.c index 397ba942..e8e5129 100644 --- a/drivers/media/video/samsung/mali/platform/pegasus-m400/mali_platform.c +++ b/drivers/media/video/samsung/mali/platform/pegasus-m400/mali_platform.c @@ -1,5 +1,4 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. +/* Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -19,7 +18,7 @@ #include "mali_linux_pm.h" #if USING_MALI_PMM -#include "mali_pmm.h" +#include "mali_pm.h" #endif #include <linux/clk.h> @@ -32,8 +31,9 @@ #include <plat/pd.h> #endif -#if MALI_TIMELINE_PROFILING_ENABLED -#include "mali_kernel_profiling.h" +#if MALI_INTERNAL_TIMELINE_PROFILING_ENABLED +#include "mali_osk_profiling.h" +#include "cinstr/mali_cinstr_profiling_events_m200.h" #endif #include <asm/io.h> @@ -58,12 +58,20 @@ typedef struct mali_runtime_resumeTag{ int vol; }mali_runtime_resume_table; -mali_runtime_resume_table mali_runtime_resume = {266, 900000}; +mali_runtime_resume_table mali_runtime_resume = {350, 950000}; /* lock/unlock CPU freq by Mali */ extern int cpufreq_lock_by_mali(unsigned int freq); extern void cpufreq_unlock_by_mali(void); +/* start of modification by skkim */ +extern mali_bool init_mali_dvfs_status(int step); +extern void deinit_mali_dvfs_status(void); +extern mali_bool mali_dvfs_handler(u32 utilization); +extern int get_mali_dvfs_control_status(void); +extern mali_bool set_mali_dvfs_current_step(unsigned int step); +/* end of modification by skkim */ + static struct clk *ext_xtal_clock = 0; static struct clk *vpll_src_clock = 0; static struct clk *fout_vpll_clock = 0; @@ -76,11 +84,11 @@ static struct clk *mali_clock = 0; static unsigned int GPU_MHZ = 1000000; -int mali_gpu_clk = 266; -int mali_gpu_vol = 900000; +int mali_gpu_clk = 350; +int mali_gpu_vol = 950000; #if MALI_DVFS_ENABLED -#define MALI_DVFS_DEFAULT_STEP 0 +#define MALI_DVFS_DEFAULT_STEP 2 #endif #if MALI_VOLTAGE_LOCK int mali_lock_vol = 0; @@ -134,7 +142,6 @@ int mali_regulator_get_usecount(void) void mali_regulator_disable(void) { - bPoweroff = 1; if( IS_ERR_OR_NULL(g3d_regulator) ) { MALI_DEBUG_PRINT(1, ("error on mali_regulator_disable : g3d_regulator is null\n")); @@ -142,11 +149,11 @@ void mali_regulator_disable(void) } regulator_disable(g3d_regulator); MALI_DEBUG_PRINT(1, ("regulator_disable -> use cnt: %d \n",mali_regulator_get_usecount())); + bPoweroff = 1; } void mali_regulator_enable(void) { - bPoweroff = 0; if( IS_ERR_OR_NULL(g3d_regulator) ) { MALI_DEBUG_PRINT(1, ("error on mali_regulator_enable : g3d_regulator is null\n")); @@ -154,6 +161,7 @@ void mali_regulator_enable(void) } regulator_enable(g3d_regulator); MALI_DEBUG_PRINT(1, ("regulator_enable -> use cnt: %d \n",mali_regulator_get_usecount())); + bPoweroff = 0; } void mali_regulator_set_voltage(int min_uV, int max_uV) @@ -196,8 +204,8 @@ void mali_regulator_set_voltage(int min_uV, int max_uV) MALI_DEBUG_PRINT(2, ("= regulator_set_voltage: %d, %d \n",min_uV, max_uV)); -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event( MALI_PROFILING_EVENT_TYPE_SINGLE | +#if MALI_INTERNAL_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_add_event( MALI_PROFILING_EVENT_TYPE_SINGLE | MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | MALI_PROFILING_EVENT_REASON_SINGLE_SW_GPU_VOLTS, min_uV, max_uV, 1, 0, 0); @@ -206,8 +214,8 @@ void mali_regulator_set_voltage(int min_uV, int max_uV) regulator_set_voltage(g3d_regulator,min_uV,max_uV); voltage = regulator_get_voltage(g3d_regulator); -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event( MALI_PROFILING_EVENT_TYPE_SINGLE | +#if MALI_INTERNAL_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_add_event( MALI_PROFILING_EVENT_TYPE_SINGLE | MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | MALI_PROFILING_EVENT_REASON_SINGLE_SW_GPU_VOLTS, voltage, 0, 2, 0, 0); @@ -398,18 +406,20 @@ mali_bool mali_clk_set_rate(unsigned int clk, unsigned int mhz) if (clk_enable(mali_clock) < 0) return MALI_FALSE; -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event( MALI_PROFILING_EVENT_TYPE_SINGLE | +#if MALI_INTERNAL_TIMELINE_PROFILING_ENABLED + unsigned long previous_rate = 0; + previous_rate = clk_get_rate(mali_clock); + _mali_osk_profiling_add_event( MALI_PROFILING_EVENT_TYPE_SINGLE | MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | MALI_PROFILING_EVENT_REASON_SINGLE_SW_GPU_FREQ, - rate, 0, 0, 0, 0); + previous_rate, 0, 0, 0, 0); #endif clk_set_rate(mali_clock, rate); rate = clk_get_rate(mali_clock); -#if MALI_TIMELINE_PROFILING_ENABLED - _mali_profiling_add_event( MALI_PROFILING_EVENT_TYPE_SINGLE | +#if MALI_INTERNAL_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_add_event( MALI_PROFILING_EVENT_TYPE_SINGLE | MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | MALI_PROFILING_EVENT_REASON_SINGLE_SW_GPU_FREQ, rate, 1, 0, 0, 0); @@ -434,8 +444,6 @@ static mali_bool init_mali_clock(void) { mali_bool ret = MALI_TRUE; - gpu_power_state = 0; - if (mali_clock != 0) return ret; // already initialized @@ -475,15 +483,15 @@ static mali_bool init_mali_clock(void) MALI_DEBUG_PRINT(2, ("MALI Clock is set at mali driver\n")); - MALI_DEBUG_PRINT(3,("::clk_put:: %s mali_parent_clock - normal\n", __FUNCTION__)); MALI_DEBUG_PRINT(3,("::clk_put:: %s mpll_clock - normal\n", __FUNCTION__)); mali_clk_put(MALI_FALSE); - return MALI_TRUE; - + gpu_power_state=0; + bPoweroff=1; + return MALI_TRUE; #ifdef CONFIG_REGULATOR err_regulator: regulator_put(g3d_regulator); @@ -526,12 +534,13 @@ static _mali_osk_errcode_t enable_mali_clocks(void) else { mali_regulator_set_voltage(mali_runtime_resume.vol, mali_runtime_resume.vol); mali_clk_set_rate(mali_runtime_resume.clk, GPU_MHZ); + set_mali_dvfs_current_step(MALI_DVFS_DEFAULT_STEP); } - if (mali_gpu_clk <= mali_runtime_resume.clk) - set_mali_dvfs_current_step(5); +#if CPUFREQ_LOCK_DURING_440 /* lock/unlock CPU freq by Mali */ if (mali_gpu_clk == 440) err = cpufreq_lock_by_mali(1200); +#endif #else mali_regulator_set_voltage(mali_runtime_resume.vol, mali_runtime_resume.vol); mali_clk_set_rate(mali_runtime_resume.clk, GPU_MHZ); @@ -547,8 +556,10 @@ static _mali_osk_errcode_t disable_mali_clocks(void) clk_disable(mali_clock); MALI_DEBUG_PRINT(3,("disable_mali_clocks mali_clock %p \n", mali_clock)); +#if MALI_DVFS_ENABLED /* lock/unlock CPU freq by Mali */ cpufreq_unlock_by_mali(); +#endif MALI_SUCCESS; } @@ -569,7 +580,7 @@ _mali_osk_errcode_t g3d_power_domain_control(int bpower_on) { #if MALI_PMM_RUNTIME_JOB_CONTROL_ON MALI_DEBUG_PRINT(3,("_mali_osk_pmm_dev_activate \n")); - _mali_osk_pmm_dev_activate(); + _mali_osk_pm_dev_activate(); #else //MALI_PMM_RUNTIME_JOB_CONTROL_ON void __iomem *status; u32 timeout; @@ -586,14 +597,14 @@ _mali_osk_errcode_t g3d_power_domain_control(int bpower_on) timeout--; _mali_osk_time_ubusydelay(100); } + MALI_PRINTF(("MALI Power domain enabled")); #endif //MALI_PMM_RUNTIME_JOB_CONTROL_ON } else { #if MALI_PMM_RUNTIME_JOB_CONTROL_ON MALI_DEBUG_PRINT( 4,("_mali_osk_pmm_dev_idle\n")); - _mali_osk_pmm_dev_idle(); - + _mali_osk_pm_dev_idle(); #else //MALI_PMM_RUNTIME_JOB_CONTROL_ON void __iomem *status; u32 timeout; @@ -611,6 +622,7 @@ _mali_osk_errcode_t g3d_power_domain_control(int bpower_on) timeout--; _mali_osk_time_ubusydelay( 100); } + MALI_PRINTF(("MALI Power domain disabled")); #endif //MALI_PMM_RUNTIME_JOB_CONTROL_ON } @@ -714,7 +726,51 @@ u32 pmu_get_power_up_down_info(void) _mali_osk_errcode_t mali_platform_power_mode_change(mali_power_mode power_mode) { - MALI_SUCCESS; + switch (power_mode) + { + case MALI_POWER_MODE_ON: + MALI_DEBUG_PRINT(1, ("Mali platform: Got MALI_POWER_MODE_ON event, %s\n", bPoweroff ? "powering on" : "already on")); + if (bPoweroff == 1) + { + /** If run time power management is used, donot call this function */ +#ifndef CONFIG_PM_RUNTIME + g3d_power_domain_control(1); +#endif + + MALI_DEBUG_PRINT(4,("enable clock \n")); + enable_mali_clocks(); +#if MALI_INTERNAL_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE| MALI_PROFILING_EVENT_CHANNEL_GPU|MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE, mali_gpu_clk, mali_gpu_vol/1000, 0, 0, 0); +#endif + //MALI_PRINTF(("Mali Platform powered up")); + gpu_power_state=1; + bPoweroff=0; + } + break; + case MALI_POWER_MODE_LIGHT_SLEEP: + case MALI_POWER_MODE_DEEP_SLEEP: + MALI_DEBUG_PRINT(1, ("Mali platform: Got %s event, %s\n", + power_mode == MALI_POWER_MODE_LIGHT_SLEEP ? "MALI_POWER_MODE_LIGHT_SLEEP" : "MALI_POWER_MODE_DEEP_SLEEP", + bPoweroff ? "already off" : "powering off")); + if (bPoweroff == 0) + { + disable_mali_clocks(); +#if MALI_INTERNAL_TIMELINE_PROFILING_ENABLED + _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE| MALI_PROFILING_EVENT_CHANNEL_GPU|MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE, 0, 0, 0, 0, 0); +#endif + +#ifndef CONFIG_PM_RUNTIME + g3d_power_domain_control(0); +#endif + + //MALI_PRINTF(("Mali Platform powered down")); + gpu_power_state=0; + bPoweroff=1; + } + + break; + } + MALI_SUCCESS; } #if MALI_VOLTAGE_LOCK diff --git a/drivers/media/video/samsung/mali/platform/pegasus-m400/mali_platform_dvfs.c b/drivers/media/video/samsung/mali/platform/pegasus-m400/mali_platform_dvfs.c index 8293d6e..2d47dba 100644 --- a/drivers/media/video/samsung/mali/platform/pegasus-m400/mali_platform_dvfs.c +++ b/drivers/media/video/samsung/mali/platform/pegasus-m400/mali_platform_dvfs.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -27,7 +27,7 @@ #include "mali_device_pause_resume.h" #include <linux/workqueue.h> -#define MAX_MALI_DVFS_STEPS 4 +#define MAX_MALI_DVFS_STEPS 5 #define MALI_DVFS_WATING 10 // msec #ifdef CONFIG_CPU_FREQ @@ -35,10 +35,12 @@ #define EXYNOS4_ASV_ENABLED #endif +#include <plat/cpu.h> + static int bMaliDvfsRun=0; static _mali_osk_atomic_t bottomlock_status; -static int bottom_lock_step; +int bottom_lock_step = 0; typedef struct mali_dvfs_tableTag{ unsigned int clock; @@ -73,7 +75,10 @@ mali_dvfs_step step[MALI_DVFS_STEPS]={ #if (MALI_DVFS_STEPS > 2) /*step 2 clk*/ {350, 950000}, #if (MALI_DVFS_STEPS > 3) - /*step 3 clk*/ {440, 1025000} + /*step 3 clk*/ {440, 1025000}, +#if (MALI_DVFS_STEPS > 4) + /*step 4 clk*/ {533, 1075000} +#endif #endif #endif #endif @@ -86,17 +91,21 @@ mali_dvfs_staycount_table mali_dvfs_staycount[MALI_DVFS_STEPS]={ #if (MALI_DVFS_STEPS > 2) /*step 2*/{0}, #if (MALI_DVFS_STEPS > 3) - /*step 3*/{0} + /*step 3*/{0}, +#if (MALI_DVFS_STEPS > 4) + /*step 4*/{0} +#endif #endif #endif #endif }; /* dvfs information */ -// L0 = 440Mhz, 1.025V -// L1 = 350Mhz, 0.95V -// L2 = 266Mhz, 0.90V -// L3 = 160Mhz, 0.875V +// L0 = 533Mhz, 1.075V +// L1 = 440Mhz, 1.025V +// L2 = 350Mhz, 0.95V +// L3 = 266Mhz, 0.90V +// L4 = 160Mhz, 0.875V int step0_clk = 160; int step0_vol = 875000; @@ -114,7 +123,13 @@ int step2_down = 85; int step3_clk = 440; int step3_vol = 1025000; int step2_up = 90; -int step3_down = 90; +int step3_down = 85; +#if (MALI_DVFS_STEPS > 4) +int step4_clk = 533; +int step4_vol = 1075000; +int step3_up = 90; +int step4_down = 95; +#endif #endif #endif #endif @@ -123,7 +138,8 @@ mali_dvfs_table mali_dvfs_all[MAX_MALI_DVFS_STEPS]={ {160 ,1000000 , 875000}, {266 ,1000000 , 900000}, {350 ,1000000 , 950000}, - {440 ,1000000 , 1025000} }; + {440 ,1000000 , 1025000}, + {533 ,1000000 , 1075000} }; mali_dvfs_table mali_dvfs[MALI_DVFS_STEPS]={ {160 ,1000000 , 875000}, @@ -132,7 +148,10 @@ mali_dvfs_table mali_dvfs[MALI_DVFS_STEPS]={ #if (MALI_DVFS_STEPS > 2) {350 ,1000000 , 950000}, #if (MALI_DVFS_STEPS > 3) - {440 ,1000000 ,1025000} + {440 ,1000000 ,1025000}, +#if (MALI_DVFS_STEPS > 4) + {533 ,1000000 ,1075000} +#endif #endif #endif #endif @@ -145,7 +164,10 @@ mali_dvfs_threshold_table mali_dvfs_threshold[MALI_DVFS_STEPS]={ #if (MALI_DVFS_STEPS > 2) {85 , 90}, #if (MALI_DVFS_STEPS > 3) - {90 ,100} + {85 ,90}, +#if (MALI_DVFS_STEPS > 4) + {95 ,100} +#endif #endif #endif #endif @@ -154,19 +176,48 @@ mali_dvfs_threshold_table mali_dvfs_threshold[MALI_DVFS_STEPS]={ #ifdef EXYNOS4_ASV_ENABLED #define ASV_LEVEL 12 /* ASV0, 1, 11 is reserved */ -static unsigned int asv_3d_volt_9_table[MALI_DVFS_STEPS][ASV_LEVEL] = { +static unsigned int asv_3d_volt_9_table_1ghz_type[MALI_DVFS_STEPS-1][ASV_LEVEL] = { + { 975000, 950000, 950000, 950000, 925000, 925000, 925000, 900000, 900000, 900000, 900000, 875000}, /* L3(160Mhz) */ +#if (MALI_DVFS_STEPS > 1) + { 1000000, 975000, 975000, 975000, 950000, 950000, 950000, 900000, 900000, 900000, 900000, 875000}, /* L2(266Mhz) */ +#if (MALI_DVFS_STEPS > 2) + { 1075000, 1050000, 1050000, 1050000, 1000000, 1000000, 1000000, 975000, 975000, 975000, 975000, 925000}, /* L1(350Mhz) */ +#if (MALI_DVFS_STEPS > 3) + { 1125000, 1100000, 1100000, 1100000, 1075000, 1075000, 1075000, 1025000, 1025000, 1025000, 1025000, 975000}, /* L0(440Mhz) */ +#endif +#endif +#endif +}; + +static unsigned int asv_3d_volt_9_table[MALI_DVFS_STEPS-1][ASV_LEVEL] = { { 950000, 925000, 900000, 900000, 875000, 875000, 875000, 875000, 850000, 850000, 850000, 850000}, /* L3(160Mhz) */ #if (MALI_DVFS_STEPS > 1) - { 975000, 950000, 925000, 925000, 925000, 900000, 900000, 875000, 875000, 875000, 875000, 850000}, /* L2(266Mhz) */ + { 975000, 950000, 925000, 925000, 925000, 900000, 900000, 875000, 875000, 875000, 875000, 850000}, /* L2(266Mhz) */ #if (MALI_DVFS_STEPS > 2) - { 1050000, 1025000, 1000000, 1000000, 975000, 950000, 950000, 950000, 925000, 925000, 925000, 900000}, /* L1(350Mhz) */ + { 1050000, 1025000, 1000000, 1000000, 975000, 950000, 950000, 950000, 925000, 925000, 925000, 900000}, /* L1(350Mhz) */ #if (MALI_DVFS_STEPS > 3) - { 1100000, 1075000, 1050000, 1050000, 1050000, 1025000, 1025000, 1000000, 1000000, 1000000, 975000, 950000}, /* L0(440Mhz) */ + { 1100000, 1075000, 1050000, 1050000, 1050000, 1025000, 1025000, 1000000, 1000000, 1000000, 975000, 950000}, /* L0(440Mhz) */ #endif #endif #endif }; + +static unsigned int asv_3d_volt_9_table_for_prime[MALI_DVFS_STEPS][ASV_LEVEL] = { + { 950000, 937500, 925000, 912500, 900000, 887500, 875000, 862500, 875000, 862500, 850000, 850000}, /* L4(160Mhz) */ +#if (MALI_DVFS_STEPS > 1) + { 975000, 962500, 950000, 937500, 925000, 912500, 900000, 887500, 900000, 887500, 875000, 862500}, /* L3(266Mhz) */ +#if (MALI_DVFS_STEPS > 2) + { 1025000, 1012500, 1000000, 987500, 975000, 962500, 950000, 937500, 950000, 937500, 925000, 912500}, /* L2(350Mhz) */ +#if (MALI_DVFS_STEPS > 3) + { 1087500, 1075000, 1062500, 1050000, 1037500, 1025000, 1012500, 1000000, 1012500, 1000000, 987500, 975000}, /* L1(440Mhz) */ +#if (MALI_DVFS_STEPS > 4) + { 1150000, 1137500, 1125000, 1112500, 1100000, 1087500, 1075000, 1062500, 1087500, 1075000, 1062500, 1050000}, /* L0(533Mhz) */ +#endif #endif +#endif +#endif +}; +#endif /* ASV_LEVEL */ /*dvfs status*/ mali_dvfs_currentstatus maliDvfsStatus; @@ -279,10 +330,12 @@ static mali_bool set_mali_dvfs_status(u32 step,mali_bool boostup) } #ifdef EXYNOS4_ASV_ENABLED - if (mali_dvfs[step].clock == 160) - exynos4x12_set_abb_member(ABB_G3D, ABB_MODE_100V); - else - exynos4x12_set_abb_member(ABB_G3D, ABB_MODE_130V); + if (samsung_rev() < EXYNOS4412_REV_2_0) { + if (mali_dvfs[step].clock == 160) + exynos4x12_set_abb_member(ABB_G3D, ABB_MODE_100V); + else + exynos4x12_set_abb_member(ABB_G3D, ABB_MODE_130V); + } #endif @@ -290,11 +343,13 @@ static mali_bool set_mali_dvfs_status(u32 step,mali_bool boostup) /*for future use*/ maliDvfsStatus.pCurrentDvfs = &mali_dvfs[validatedStep]; +#if CPUFREQ_LOCK_DURING_440 /* lock/unlock CPU freq by Mali */ if (mali_dvfs[step].clock == 440) err = cpufreq_lock_by_mali(1200); else cpufreq_unlock_by_mali(); +#endif return MALI_TRUE; } @@ -335,11 +390,30 @@ extern unsigned int exynos_result_of_asv; static mali_bool mali_dvfs_table_update(void) { unsigned int i; - - for (i = 0; i < MALI_DVFS_STEPS; i++) { - MALI_PRINT((":::exynos_result_of_asv : %d\n", exynos_result_of_asv)); - mali_dvfs[i].vol = asv_3d_volt_9_table[i][exynos_result_of_asv]; - MALI_PRINT(("mali_dvfs[%d].vol = %d\n", i, mali_dvfs[i].vol)); + unsigned int step_num = MALI_DVFS_STEPS; + + if(soc_is_exynos4412()) { + if (exynos_armclk_max == 1000000) { + step_num = MALI_DVFS_STEPS - 1; + for (i = 0; i < step_num; i++) { + MALI_PRINT((":::exynos_result_of_asv : %d\n", exynos_result_of_asv)); + mali_dvfs[i].vol = asv_3d_volt_9_table_1ghz_type[i][exynos_result_of_asv]; + MALI_PRINT(("mali_dvfs[%d].vol = %d 1ghz_type\n", i, mali_dvfs[i].vol)); + } + } else if (samsung_rev() >= EXYNOS4412_REV_2_0) { + for (i = 0; i < step_num; i++) { + MALI_PRINT((":::exynos_result_of_asv : %d\n", exynos_result_of_asv)); + mali_dvfs[i].vol = asv_3d_volt_9_table_for_prime[i][exynos_result_of_asv]; + MALI_PRINT(("mali_dvfs[%d].vol = %d 1.6ghz_type\n", i, mali_dvfs[i].vol)); + } + } else { + step_num = MALI_DVFS_STEPS - 1; + for (i = 0; i < step_num; i++) { + MALI_PRINT((":::exynos_result_of_asv : %d\n", exynos_result_of_asv)); + mali_dvfs[i].vol = asv_3d_volt_9_table[i][exynos_result_of_asv]; + MALI_PRINT(("mali_dvfs[%d].vol = %d 1.4ghz_type\n", i, mali_dvfs[i].vol)); + } + } } return MALI_TRUE; @@ -354,7 +428,6 @@ static unsigned int decideNextStatus(unsigned int utilization) if (mali_runtime_resumed >= 0) { level = mali_runtime_resumed; mali_runtime_resumed = -1; - return level; } if (mali_dvfs_threshold[maliDvfsStatus.currentStep].upthreshold @@ -369,6 +442,9 @@ static unsigned int decideNextStatus(unsigned int utilization) if (utilization > (int)(255 * mali_dvfs_threshold[maliDvfsStatus.currentStep].upthreshold / 100) && level < MALI_DVFS_STEPS - 1) { level++; + if ((samsung_rev() < EXYNOS4412_REV_2_0) && (maliDvfsStatus.currentStep == 3)) { + level=get_mali_dvfs_status(); + } } if (utilization < (int)(255 * mali_dvfs_threshold[maliDvfsStatus.currentStep].downthreshold / 100) && level > 0) { @@ -400,6 +476,10 @@ static unsigned int decideNextStatus(unsigned int utilization) #if (MALI_DVFS_STEPS > 3) step3_clk = step[3].clk; change_dvfs_tableset(step3_clk, 3); +#if (MALI_DVFS_STEPS > 4) + step4_clk = step[4].clk; + change_dvfs_tableset(step4_clk, 4); +#endif #endif #endif #endif @@ -422,12 +502,18 @@ static unsigned int decideNextStatus(unsigned int utilization) step[i].clk = mali_dvfs_all[2].clock; } maliDvfsStatus.currentStep = 2; - } else { + } else if (mali_dvfs_control < mali_dvfs_all[4].clock && mali_dvfs_control >= mali_dvfs_all[3].clock) { int i = 0; for (i = 0; i < MALI_DVFS_STEPS; i++) { step[i].clk = mali_dvfs_all[3].clock; } maliDvfsStatus.currentStep = 3; + } else { + int i = 0; + for (i = 0; i < MALI_DVFS_STEPS; i++) { + step[i].clk = mali_dvfs_all[4].clock; + } + maliDvfsStatus.currentStep = 4; } step0_clk = step[0].clk; change_dvfs_tableset(step0_clk, 0); @@ -440,6 +526,10 @@ static unsigned int decideNextStatus(unsigned int utilization) #if (MALI_DVFS_STEPS > 3) step3_clk = step[3].clk; change_dvfs_tableset(step3_clk, 3); +#if (MALI_DVFS_STEPS > 4) + step4_clk = step[4].clk; + change_dvfs_tableset(step4_clk, 4); +#endif #endif #endif #endif @@ -577,6 +667,22 @@ static void mali_dvfs_work_handler(struct work_struct *w) MALI_PRINT((":::step3_down change to %d %\n", step3_down)); mali_dvfs_threshold[3].downthreshold = step3_down; } +#if (MALI_DVFS_STEPS > 4) + if (step4_clk != mali_dvfs[4].clock) { + MALI_PRINT(("::: step4_clk change to %d Mhz\n", step4_clk)); + change_clk = step4_clk; + change_step = 4; + step4_clk = change_dvfs_tableset(change_clk, change_step); + } + if (step3_up != mali_dvfs_threshold[3].upthreshold) { + MALI_PRINT((":::step3_up change to %d %\n", step3_up)); + mali_dvfs_threshold[3].upthreshold = step3_up; + } + if (step4_down != mali_dvfs_threshold[4].downthreshold) { + MALI_PRINT((":::step4_down change to %d %\n", step4_down)); + mali_dvfs_threshold[4].downthreshold = step4_down; + } +#endif #endif #endif #endif @@ -587,6 +693,7 @@ static void mali_dvfs_work_handler(struct work_struct *w) mali_dvfs[1].vol = step1_vol; mali_dvfs[2].vol = step2_vol; mali_dvfs[3].vol = step3_vol; + mali_dvfs[4].vol = step4_vol; #endif MALI_DEBUG_PRINT(3, ("=== mali_dvfs_work_handler\n")); @@ -641,8 +748,10 @@ int change_dvfs_tableset(int change_clk, int change_step) mali_dvfs[change_step].clock = mali_dvfs_all[1].clock; } else if (change_clk < mali_dvfs_all[3].clock && change_clk >= mali_dvfs_all[2].clock) { mali_dvfs[change_step].clock = mali_dvfs_all[2].clock; - } else { + } else if (change_clk < mali_dvfs_all[4].clock && change_clk >= mali_dvfs_all[3].clock) { mali_dvfs[change_step].clock = mali_dvfs_all[3].clock; + } else { + mali_dvfs[change_step].clock = mali_dvfs_all[4].clock; } MALI_PRINT((":::mali dvfs step %d clock and voltage = %d Mhz, %d V\n",change_step, mali_dvfs[change_step].clock, mali_dvfs[change_step].vol)); @@ -655,11 +764,13 @@ int change_dvfs_tableset(int change_clk, int change_step) /*change the clock*/ mali_clk_set_rate(mali_dvfs[change_step].clock, mali_dvfs[change_step].freq); +#if CPUFREQ_LOCK_DURING_440 /* lock/unlock CPU freq by Mali */ if (mali_dvfs[change_step].clock == 440) err = cpufreq_lock_by_mali(1200); else cpufreq_unlock_by_mali(); +#endif } return mali_dvfs[change_step].clock; @@ -684,10 +795,8 @@ int mali_dvfs_bottom_lock_push(int lock_step) if (bottom_lock_step < lock_step) { bottom_lock_step = lock_step; if (get_mali_dvfs_status() < lock_step) { - mali_regulator_set_voltage(mali_dvfs[lock_step].vol, - mali_dvfs[lock_step].vol); - mali_clk_set_rate(mali_dvfs[lock_step].clock, - mali_dvfs[lock_step].freq); + mali_regulator_set_voltage(mali_dvfs[lock_step].vol, mali_dvfs[lock_step].vol); + mali_clk_set_rate(mali_dvfs[lock_step].clock, mali_dvfs[lock_step].freq); set_mali_dvfs_current_step(lock_step); } } diff --git a/drivers/media/video/samsung/mali/readme.txt b/drivers/media/video/samsung/mali/readme.txt new file mode 100644 index 0000000..3acc51c --- /dev/null +++ b/drivers/media/video/samsung/mali/readme.txt @@ -0,0 +1,28 @@ +Building the Mali Device Driver for Linux +----------------------------------------- + +Build the Mali Device Driver for Linux by running the following make command: + +KDIR=<kdir_path> USING_UMP=<ump_option> BUILD=<build_option> \ +TARGET_PLATFORM=<target_platform> CONFIG=<your_config> make + +where + kdir_path: Path to your Linux Kernel directory + ump_option: 1 = Enable UMP support(*) + 0 = disable UMP support + build_option: debug = debug build of driver + release = release build of driver + target_platform: Name of the sub-folder in platform/ that contains the + required mali_platform.c file. + your_config: Name of the sub-folder to find the required config.h(**) file + ("arch-" will be prepended) + +(*) For newer Linux Kernels, the Module.symvers file for the UMP device driver + must be available. The UMP_SYMVERS_FILE variable in the Makefile should + point to this file. This file is generated when the UMP driver is built. + +(**) The config.h file contains the configuration parameters needed, like where the + Mali GPU is located, interrupts it uses, memory and so on. + +The result will be a mali.ko file, which can be loaded into the Linux kernel +by using the insmod command. diff --git a/drivers/media/video/samsung/mali/regs/mali_200_regs.h b/drivers/media/video/samsung/mali/regs/mali_200_regs.h index e9da7ab..59e92c8 100644 --- a/drivers/media/video/samsung/mali/regs/mali_200_regs.h +++ b/drivers/media/video/samsung/mali/regs/mali_200_regs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010, 2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -51,7 +51,7 @@ enum mali200_mgmt_ctrl_mgmt { #endif MALI200_REG_VAL_CTRL_MGMT_FORCE_RESET = (1<<5), MALI200_REG_VAL_CTRL_MGMT_START_RENDERING = (1<<6), -#if defined(USING_MALI400) +#if defined(USING_MALI400) || defined(USING_MALI450) MALI400PP_REG_VAL_CTRL_MGMT_SOFT_RESET = (1<<7), #endif }; @@ -72,7 +72,7 @@ enum mali200_mgmt_irq { MALI400PP_REG_VAL_IRQ_RESET_COMPLETED = (1<<12), }; -#if defined USING_MALI200 +#if defined(USING_MALI200) #define MALI200_REG_VAL_IRQ_MASK_ALL ((enum mali200_mgmt_irq) (\ MALI200_REG_VAL_IRQ_END_OF_FRAME |\ MALI200_REG_VAL_IRQ_END_OF_TILE |\ @@ -83,7 +83,7 @@ enum mali200_mgmt_irq { MALI200_REG_VAL_IRQ_CNT_0_LIMIT |\ MALI200_REG_VAL_IRQ_CNT_1_LIMIT |\ MALI200_REG_VAL_IRQ_WRITE_BOUNDARY_ERROR)) -#elif defined USING_MALI400 +#elif defined(USING_MALI400) || defined(USING_MALI450) #define MALI200_REG_VAL_IRQ_MASK_ALL ((enum mali200_mgmt_irq) (\ MALI200_REG_VAL_IRQ_END_OF_FRAME |\ MALI200_REG_VAL_IRQ_END_OF_TILE |\ @@ -102,14 +102,14 @@ enum mali200_mgmt_irq { #error "No supported mali core defined" #endif -#if defined USING_MALI200 +#if defined(USING_MALI200) #define MALI200_REG_VAL_IRQ_MASK_USED ((enum mali200_mgmt_irq) (\ MALI200_REG_VAL_IRQ_END_OF_FRAME |\ MALI200_REG_VAL_IRQ_HANG |\ MALI200_REG_VAL_IRQ_FORCE_HANG |\ MALI200_REG_VAL_IRQ_BUS_ERROR |\ MALI200_REG_VAL_IRQ_WRITE_BOUNDARY_ERROR)) -#elif defined USING_MALI400 +#elif defined(USING_MALI400) || defined(USING_MALI450) #define MALI200_REG_VAL_IRQ_MASK_USED ((enum mali200_mgmt_irq) (\ MALI200_REG_VAL_IRQ_END_OF_FRAME |\ MALI200_REG_VAL_IRQ_HANG |\ @@ -134,11 +134,14 @@ enum mali200_mgmt_status { enum mali200_render_unit { MALI200_REG_ADDR_FRAME = 0x0000, + MALI200_REG_ADDR_STACK = 0x0030 }; -#if defined USING_MALI200 +#if defined(USING_MALI200) #define MALI200_NUM_REGS_FRAME ((0x04C/4)+1) -#elif defined USING_MALI400 +#elif defined(USING_MALI400) +#define MALI200_NUM_REGS_FRAME ((0x058/4)+1) +#elif defined(USING_MALI450) #define MALI200_NUM_REGS_FRAME ((0x058/4)+1) #else #error "No supported mali core defined" @@ -150,21 +153,20 @@ enum mali200_wb_unit { MALI200_REG_ADDR_WB2 = 0x0300 }; +enum mali200_wb_unit_regs { + MALI200_REG_ADDR_WB_SOURCE_SELECT = 0x0000, +}; + /** The number of registers in one single writeback unit */ #ifndef MALI200_NUM_REGS_WBx #define MALI200_NUM_REGS_WBx ((0x02C/4)+1) #endif /* This should be in the top 16 bit of the version register of Mali PP */ -#if defined USING_MALI200 -#define MALI_PP_PRODUCT_ID 0xC807 -#elif defined USING_MALI400 +#define MALI200_PP_PRODUCT_ID 0xC807 #define MALI300_PP_PRODUCT_ID 0xCE07 #define MALI400_PP_PRODUCT_ID 0xCD07 -#define MALI_PP_PRODUCT_ID MALI400_PP_PRODUCT_ID -#else -#error "No supported mali core defined" -#endif +#define MALI450_PP_PRODUCT_ID 0xCF07 #endif /* _MALI200_REGS_H_ */ diff --git a/drivers/media/video/samsung/mali/regs/mali_gp_regs.h b/drivers/media/video/samsung/mali/regs/mali_gp_regs.h index 14719a3..21c83c0 100644 --- a/drivers/media/video/samsung/mali/regs/mali_gp_regs.h +++ b/drivers/media/video/samsung/mali/regs/mali_gp_regs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010, 2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -12,9 +12,9 @@ #define _MALIGP2_CONROL_REGS_H_ /** - * These are the different geometry processor controll registers. + * These are the different geometry processor control registers. * Their usage is to control and monitor the operation of the - * Vertex Shader and the Polygon List Builer in the geometry processor. + * Vertex Shader and the Polygon List Builder in the geometry processor. * Addresses are in 32-bit word relative sizes. * @see [P0081] "Geometry Processor Data Structures" for details */ @@ -60,7 +60,7 @@ typedef enum MALIGP2_REG_VAL_CMD_RESET = (1<< 5), MALIGP2_REG_VAL_CMD_FORCE_HANG = (1<< 6), MALIGP2_REG_VAL_CMD_STOP_BUS = (1<< 9), -#if defined(USING_MALI400) +#if defined(USING_MALI400) || defined(USING_MALI450) MALI400GP_REG_VAL_CMD_SOFT_RESET = (1<<10), #endif } mgp_contr_reg_val_cmd; @@ -84,7 +84,7 @@ typedef enum #define MALIGP2_REG_VAL_IRQ_WRITE_BOUND_ERR (1 << 9) #define MALIGP2_REG_VAL_IRQ_SYNC_ERROR (1 << 10) #define MALIGP2_REG_VAL_IRQ_AXI_BUS_ERROR (1 << 11) -#if defined USING_MALI400 +#if defined(USING_MALI400) || defined(USING_MALI450) #define MALI400GP_REG_VAL_IRQ_AXI_BUS_STOPPED (1 << 12) #define MALI400GP_REG_VAL_IRQ_VS_INVALID_CMD (1 << 13) #define MALI400GP_REG_VAL_IRQ_PLB_INVALID_CMD (1 << 14) @@ -97,7 +97,7 @@ typedef enum #endif /* Mask defining all IRQs in MaliGP2 */ -#if defined USING_MALI200 +#if defined(USING_MALI200) #define MALIGP2_REG_VAL_IRQ_MASK_ALL \ (\ MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST | \ @@ -112,7 +112,7 @@ typedef enum MALIGP2_REG_VAL_IRQ_WRITE_BOUND_ERR | \ MALIGP2_REG_VAL_IRQ_SYNC_ERROR | \ MALIGP2_REG_VAL_IRQ_AXI_BUS_ERROR) -#elif defined USING_MALI400 +#elif defined(USING_MALI400) || defined(USING_MALI450) #define MALIGP2_REG_VAL_IRQ_MASK_ALL \ (\ MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST | \ @@ -139,7 +139,7 @@ typedef enum #endif /* Mask defining the IRQs in MaliGP2 which we use*/ -#if defined USING_MALI200 +#if defined(USING_MALI200) #define MALIGP2_REG_VAL_IRQ_MASK_USED \ (\ MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST | \ @@ -150,7 +150,7 @@ typedef enum MALIGP2_REG_VAL_IRQ_WRITE_BOUND_ERR | \ MALIGP2_REG_VAL_IRQ_SYNC_ERROR | \ MALIGP2_REG_VAL_IRQ_AXI_BUS_ERROR) -#elif defined USING_MALI400 +#elif defined(USING_MALI400) || defined(USING_MALI450) #define MALIGP2_REG_VAL_IRQ_MASK_USED \ (\ MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST | \ @@ -197,15 +197,10 @@ typedef enum MALIGP2_REG_VAL_STATUS_WRITE_BOUND_ERR ) /* This should be in the top 16 bit of the version register of gp.*/ -#if defined(USING_MALI200) -#define MALI_GP_PRODUCT_ID 0xA07 -#elif defined(USING_MALI400) +#define MALI200_GP_PRODUCT_ID 0xA07 #define MALI300_GP_PRODUCT_ID 0xC07 #define MALI400_GP_PRODUCT_ID 0xB07 -#define MALI_GP_PRODUCT_ID MALI400_GP_PRODUCT_ID -#else -#error "No supported mali core defined" -#endif +#define MALI450_GP_PRODUCT_ID 0xD07 /** * The different sources for instrumented on the geometry processor. diff --git a/drivers/media/video/samsung/mali/timestamp-arm11-cc/mali_timestamp.c b/drivers/media/video/samsung/mali/timestamp-arm11-cc/mali_timestamp.c index cddfa58..a6b1d76 100644 --- a/drivers/media/video/samsung/mali/timestamp-arm11-cc/mali_timestamp.c +++ b/drivers/media/video/samsung/mali/timestamp-arm11-cc/mali_timestamp.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2011 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. diff --git a/drivers/media/video/samsung/mali/timestamp-arm11-cc/mali_timestamp.h b/drivers/media/video/samsung/mali/timestamp-arm11-cc/mali_timestamp.h index 442c6e0..3279dae 100644 --- a/drivers/media/video/samsung/mali/timestamp-arm11-cc/mali_timestamp.h +++ b/drivers/media/video/samsung/mali/timestamp-arm11-cc/mali_timestamp.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2011 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. diff --git a/drivers/media/video/samsung/mali/timestamp-default/mali_timestamp.c b/drivers/media/video/samsung/mali/timestamp-default/mali_timestamp.c index cddfa58..a6b1d76 100644 --- a/drivers/media/video/samsung/mali/timestamp-default/mali_timestamp.c +++ b/drivers/media/video/samsung/mali/timestamp-default/mali_timestamp.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2011 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. diff --git a/drivers/media/video/samsung/mali/timestamp-default/mali_timestamp.h b/drivers/media/video/samsung/mali/timestamp-default/mali_timestamp.h index 470eac9..94b842a 100644 --- a/drivers/media/video/samsung/mali/timestamp-default/mali_timestamp.h +++ b/drivers/media/video/samsung/mali/timestamp-default/mali_timestamp.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2011 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. diff --git a/drivers/media/video/samsung/tvout/Kconfig b/drivers/media/video/samsung/tvout/Kconfig index 176efeb..da7bda7 100644 --- a/drivers/media/video/samsung/tvout/Kconfig +++ b/drivers/media/video/samsung/tvout/Kconfig @@ -62,6 +62,16 @@ config HDMI_CONTROLLED_BY_EXT_IC For example, the H/W has HDMI level shifter then it should be turned on when HPD interrupt comes. +config HDMI_TX_STRENGTH + bool "Tuning TX amplitude" + depends on VIDEO_TVOUT && ARCH_EXYNOS4 + default n + ---help--- + Say y here if the H/W needs to be tuned for TX amplitude. + HDMI driver will take the values registered at board file + and apply them through HDMI phy i2c according to the requested + channel number. + config HDMI_SWITCH_HPD bool "HDMI HPD switch uevent driver support" depends on HDMI_HPD diff --git a/drivers/media/video/samsung/tvout/hw_if/hdcp.c b/drivers/media/video/samsung/tvout/hw_if/hdcp.c index 569de28..41caf19 100644 --- a/drivers/media/video/samsung/tvout/hw_if/hdcp.c +++ b/drivers/media/video/samsung/tvout/hw_if/hdcp.c @@ -379,7 +379,9 @@ static int s5p_hdcp_read_bcaps(void) if (s5p_ddc_read(HDCP_Bcaps, BCAPS_SIZE, &bcaps) < 0) goto bcaps_read_err; - if (s5p_hdmi_ctrl_status() == false || !s5p_hdmi_reg_get_hpd_status() || on_stop_process) + if (s5p_hdmi_ctrl_status() == false || + !s5p_hdmi_reg_get_hpd_status() || + on_stop_process) goto bcaps_read_err; writeb(bcaps, hdmi_base + S5P_HDMI_HDCP_BCAPS); @@ -532,7 +534,8 @@ static void s5p_hdcp_reset_auth(void) unsigned long spin_flags; if (s5p_hdmi_ctrl_status() == false || - !s5p_hdmi_reg_get_hpd_status() || on_stop_process) + !s5p_hdmi_reg_get_hpd_status() || + on_stop_process) return; spin_lock_irqsave(&hdcp_info.reset_lock, spin_flags); @@ -956,9 +959,12 @@ check_ri_err: static void s5p_hdcp_work(void *arg) { + s5p_tvout_mutex_lock(); if (!hdcp_info.hdcp_enable || s5p_hdmi_ctrl_status() == false || - !s5p_hdmi_reg_get_hpd_status() || on_stop_process) + !s5p_hdmi_reg_get_hpd_status() || on_stop_process) { + s5p_tvout_mutex_unlock(); return; + } if (hdcp_info.event & HDCP_EVENT_READ_BKSV_START) { if (s5p_hdcp_bksv() < 0) @@ -987,13 +993,16 @@ static void s5p_hdcp_work(void *arg) else hdcp_info.event &= ~HDCP_EVENT_CHECK_RI_START; } + s5p_tvout_mutex_unlock(); return; work_err: if (!hdcp_info.hdcp_enable || s5p_hdmi_ctrl_status() == false || !s5p_hdmi_reg_get_hpd_status() || on_stop_process) { + s5p_tvout_mutex_unlock(); return; } s5p_hdcp_reset_auth(); + s5p_tvout_mutex_unlock(); } irqreturn_t s5p_hdcp_irq_handler(int irq, void *dev_id) @@ -1121,3 +1130,8 @@ int s5p_hdcp_encrypt_stop(bool on) return 0; } + +void s5p_hdcp_flush_work(void) +{ + flush_workqueue(hdcp_wq); +} diff --git a/drivers/media/video/samsung/tvout/hw_if/hdmi.c b/drivers/media/video/samsung/tvout/hw_if/hdmi.c index dfb3152..67099af 100644 --- a/drivers/media/video/samsung/tvout/hw_if/hdmi.c +++ b/drivers/media/video/samsung/tvout/hw_if/hdmi.c @@ -871,10 +871,10 @@ static void s5p_hdmi_print_phy_config(void) printk(KERN_WARNING "read buffer :\n"); - for (i = 1; i < size; i++) { + for (i = 0; i < size; i++) { printk("0x%02x", read_buffer[i]); - if (i % 8) + if ((i+1) % 8) printk(" "); else printk("\n"); @@ -1146,6 +1146,58 @@ void s5p_hdmi_reg_sw_reset(void) s5p_hdmi_ctrl_clock(0); } +#ifdef CONFIG_HDMI_TX_STRENGTH +int s5p_hdmi_phy_set_tx_strength(u8 ch, u8 *value) +{ + u8 buff[2]; + + if (ch & TX_EMP_LVL) { /* REG10 BIT7:4 */ + buff[0] = HDMI_PHY_I2C_REG10; + buff[1] = (value[TX_EMP_LVL_VAL] & 0x0f) << 4; + if (s5p_hdmi_i2c_phy_write(PHY_I2C_ADDRESS, 2, buff) != 0) + goto err_exit; + } + + if (ch & TX_AMP_LVL) { /* REG10 BIT3:0, REG0F BIT7 */ + buff[0] = HDMI_PHY_I2C_REG10; + buff[1] = (value[TX_AMP_LVL_VAL] & 0x0e) >> 1; + if (s5p_hdmi_i2c_phy_write(PHY_I2C_ADDRESS, 2, buff) != 0) + goto err_exit; + buff[0] = HDMI_PHY_I2C_REG0F; + buff[1] = (value[TX_AMP_LVL_VAL] & 0x01) << 7; + if (s5p_hdmi_i2c_phy_write(PHY_I2C_ADDRESS, 2, buff) != 0) + goto err_exit; + } + + if (ch & TX_LVL_CH0) { /* REG04 BIT7:6 */ + buff[0] = HDMI_PHY_I2C_REG04; + buff[1] = (value[TX_LVL_CH0_VAL] & 0x3) << 6; + if (s5p_hdmi_i2c_phy_write(PHY_I2C_ADDRESS, 2, buff) != 0) + goto err_exit; + } + + if (ch & TX_LVL_CH1) { /* REG13 BIT1:0 */ + buff[0] = HDMI_PHY_I2C_REG13; + buff[1] = (value[TX_LVL_CH1_VAL] & 0x3); + if (s5p_hdmi_i2c_phy_write(PHY_I2C_ADDRESS, 2, buff) != 0) + goto err_exit; + } + + if (ch & TX_LVL_CH2) { /* REG17 BIT1:0 */ + buff[0] = HDMI_PHY_I2C_REG17; + buff[1] = (value[TX_LVL_CH2_VAL] & 0x3); + if (s5p_hdmi_i2c_phy_write(PHY_I2C_ADDRESS, 2, buff) != 0) + goto err_exit; + } + + return 0; + +err_exit: + pr_err("%s: failed to set tx strength\n", __func__); + return -1; +} +#endif + int s5p_hdmi_phy_power(bool on) { u32 size; diff --git a/drivers/media/video/samsung/tvout/hw_if/hw_if.h b/drivers/media/video/samsung/tvout/hw_if/hw_if.h index 11bda99..e437b0a 100644 --- a/drivers/media/video/samsung/tvout/hw_if/hw_if.h +++ b/drivers/media/video/samsung/tvout/hw_if/hw_if.h @@ -364,6 +364,27 @@ struct s5p_hdmi_v_format { u8 mhl_vsync; }; +#ifdef CONFIG_HDMI_TX_STRENGTH +#define HDMI_PHY_I2C_REG10 0x10 +#define HDMI_PHY_I2C_REG0F 0x0F +#define HDMI_PHY_I2C_REG04 0x04 +#define HDMI_PHY_I2C_REG13 0x13 +#define HDMI_PHY_I2C_REG17 0x17 + +#define TX_EMP_LVL 0x10 +#define TX_AMP_LVL 0x08 +#define TX_LVL_CH0 0x04 +#define TX_LVL_CH1 0x02 +#define TX_LVL_CH2 0x01 + +#define TX_EMP_LVL_VAL 0 +#define TX_AMP_LVL_VAL 1 +#define TX_LVL_CH0_VAL 2 +#define TX_LVL_CH1_VAL 3 +#define TX_LVL_CH2_VAL 4 + +extern int s5p_hdmi_phy_set_tx_strength(u8 ch, u8 *value); +#endif extern int s5p_hdmi_phy_power(bool on); extern s32 s5p_hdmi_phy_config( enum phy_freq freq, enum s5p_hdmi_color_depth cd); @@ -750,6 +771,7 @@ extern int s5p_hdcp_encrypt_stop(bool on); extern int __init s5p_hdcp_init(void); extern int s5p_hdcp_start(void); extern int s5p_hdcp_stop(void); +extern void s5p_hdcp_flush_work(void); /**************************************** * Definitions for sdo ctrl class @@ -1000,6 +1022,10 @@ struct s5p_tvif_ctrl_private_data { struct device *bus_dev; /* for BusFreq with Opp */ #endif struct device *dev; /* hpd device pointer */ +#ifdef CONFIG_HDMI_TX_STRENGTH + u8 tx_ch; + u8 *tx_val; +#endif }; #endif /* _SAMSUNG_TVOUT_HW_IF_H_ */ diff --git a/drivers/media/video/samsung/tvout/s5p_mixer_ctrl.c b/drivers/media/video/samsung/tvout/s5p_mixer_ctrl.c index a0169cb..5e78a3c 100644 --- a/drivers/media/video/samsung/tvout/s5p_mixer_ctrl.c +++ b/drivers/media/video/samsung/tvout/s5p_mixer_ctrl.c @@ -241,7 +241,7 @@ static void s5p_mixer_ctrl_clock(bool on) clk_enable(s5p_mixer_ctrl_private.clk[ACLK].ptr); - // Restore mixer_base address + /* Restore mixer_base address */ s5p_mixer_init(s5p_mixer_ctrl_private.reg_mem.base); } else { clk_disable(s5p_mixer_ctrl_private.clk[ACLK].ptr); @@ -252,7 +252,7 @@ static void s5p_mixer_ctrl_clock(bool on) clk_disable(s5p_mixer_ctrl_private.clk[MUX].ptr); - // Set mixer_base address to NULL + /* Set mixer_base address to NULL */ s5p_mixer_init(NULL); } } @@ -267,7 +267,7 @@ void s5p_mixer_ctrl_init_grp_layer(enum s5p_mixer_layer layer) { struct s5ptvfb_user_scaling scaling; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return; @@ -278,12 +278,16 @@ void s5p_mixer_ctrl_init_grp_layer(enum s5p_mixer_layer layer) s5p_mixer_set_priority(layer, s5p_mixer_ctrl_private.layer[layer].priority); s5p_mixer_set_pre_mul_mode(layer, - s5p_mixer_ctrl_private.layer[layer].pre_mul_mode); + s5p_mixer_ctrl_private.layer[layer]. + pre_mul_mode); s5p_mixer_set_chroma_key(layer, - s5p_mixer_ctrl_private.layer[layer].chroma_enable, - s5p_mixer_ctrl_private.layer[layer].chroma_key); + s5p_mixer_ctrl_private.layer[layer]. + chroma_enable, + s5p_mixer_ctrl_private.layer[layer]. + chroma_key); s5p_mixer_set_layer_blend(layer, - s5p_mixer_ctrl_private.layer[layer].layer_blend); + s5p_mixer_ctrl_private.layer[layer]. + layer_blend); s5p_mixer_set_alpha(layer, s5p_mixer_ctrl_private.layer[layer].alpha); s5p_mixer_set_grp_layer_dst_pos(layer, @@ -299,7 +303,8 @@ void s5p_mixer_ctrl_init_grp_layer(enum s5p_mixer_layer layer) } } -int s5p_mixer_ctrl_set_pixel_format(enum s5p_mixer_layer layer, u32 bpp, u32 trans_len) +int s5p_mixer_ctrl_set_pixel_format( + enum s5p_mixer_layer layer, u32 bpp, u32 trans_len) { enum s5p_mixer_color_fmt format; @@ -322,7 +327,7 @@ int s5p_mixer_ctrl_set_pixel_format(enum s5p_mixer_layer layer, u32 bpp, u32 tra s5p_mixer_ctrl_private.layer[layer].format = format; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -351,7 +356,7 @@ int s5p_mixer_ctrl_enable_layer(enum s5p_mixer_layer layer) tvout_err("invalid layer\n"); return -1; } -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -384,7 +389,7 @@ int s5p_mixer_ctrl_disable_layer(enum s5p_mixer_layer layer) return -1; } -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -523,7 +528,7 @@ int s5p_mixer_ctrl_set_dst_win_pos(enum s5p_mixer_layer layer, s5p_mixer_ctrl_private.layer[layer].dst_x = (u32)dst_x; s5p_mixer_ctrl_private.layer[layer].dst_y = (u32)dst_y; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -551,7 +556,7 @@ int s5p_mixer_ctrl_set_src_win_pos(enum s5p_mixer_layer layer, s5p_mixer_ctrl_private.layer[layer].width = w; s5p_mixer_ctrl_private.layer[layer].height = h; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -559,7 +564,8 @@ int s5p_mixer_ctrl_set_src_win_pos(enum s5p_mixer_layer layer, #endif { if (s5p_mixer_ctrl_private.running) - s5p_mixer_set_grp_layer_src_pos(layer, src_x, src_y, w, w, h); + s5p_mixer_set_grp_layer_src_pos( + layer, src_x, src_y, w, w, h); } return 0; @@ -577,7 +583,7 @@ int s5p_mixer_ctrl_set_buffer_address(enum s5p_mixer_layer layer, s5p_mixer_ctrl_private.layer[layer].fb_addr = start_addr; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -602,7 +608,7 @@ int s5p_mixer_ctrl_set_chroma_key(enum s5p_mixer_layer layer, s5p_mixer_ctrl_private.layer[layer].chroma_enable = enabled; s5p_mixer_ctrl_private.layer[layer].chroma_key = chroma.key; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -709,7 +715,7 @@ int s5p_mixer_ctrl_set_alpha_blending(enum s5p_mixer_layer layer, case PIXEL_BLENDING: tvout_dbg("pixel blending\n"); s5p_mixer_ctrl_private.layer[layer].pixel_blend = true; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -723,7 +729,7 @@ int s5p_mixer_ctrl_set_alpha_blending(enum s5p_mixer_layer layer, tvout_dbg("layer blending : alpha value = 0x%x\n", alpha); s5p_mixer_ctrl_private.layer[layer].layer_blend = true; s5p_mixer_ctrl_private.layer[layer].alpha = alpha; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -739,7 +745,7 @@ int s5p_mixer_ctrl_set_alpha_blending(enum s5p_mixer_layer layer, tvout_dbg("alpha blending off\n"); s5p_mixer_ctrl_private.layer[layer].pixel_blend = false; s5p_mixer_ctrl_private.layer[layer].layer_blend = false; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -780,7 +786,7 @@ int s5p_mixer_ctrl_scaling(enum s5p_mixer_layer layer, s5p_mixer_ctrl_private.layer[layer].ver = scaling.ver; s5p_mixer_ctrl_private.layer[layer].hor = scaling.hor; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return 0; @@ -796,7 +802,8 @@ int s5p_mixer_ctrl_mux_clk(struct clk *ptr) { if (clk_set_parent(s5p_mixer_ctrl_private.clk[MUX].ptr, ptr)) { tvout_err("unable to set parent %s of clock %s.\n", - ptr->name, s5p_mixer_ctrl_private.clk[MUX].ptr->name); + ptr->name, + s5p_mixer_ctrl_private.clk[MUX].ptr->name); return -1; } @@ -828,6 +835,12 @@ bool s5p_mixer_ctrl_get_vsync_interrupt() return s5p_mixer_ctrl_private.vsync_interrupt_enable; } +void s5p_mixer_ctrl_disable_vsync_interrupt() +{ + if (s5p_mixer_ctrl_private.running) + s5p_mixer_set_vsync_interrupt(false); +} + void s5p_mixer_ctrl_clear_pend_all(void) { if (s5p_mixer_ctrl_private.running) @@ -840,7 +853,7 @@ void s5p_mixer_ctrl_stop(void) tvout_dbg("running(%d)\n", s5p_mixer_ctrl_private.running); if (s5p_mixer_ctrl_private.running) { -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); } else @@ -848,11 +861,12 @@ void s5p_mixer_ctrl_stop(void) { s5p_mixer_set_vsync_interrupt(false); - for (i = 0; i < S5PTV_VP_BUFF_CNT -1; i++) + for (i = 0; i < S5PTV_VP_BUFF_CNT-1; i++) s5ptv_vp_buff.copy_buff_idxs[i] = i; s5ptv_vp_buff.curr_copy_idx = 0; - s5ptv_vp_buff.vp_access_buff_idx = S5PTV_VP_BUFF_CNT - 1; + s5ptv_vp_buff.vp_access_buff_idx = + S5PTV_VP_BUFF_CNT - 1; s5p_mixer_stop(); s5p_mixer_ctrl_clock(0); @@ -1006,10 +1020,24 @@ int s5p_mixer_ctrl_start( s5p_mixer_init_csc_coef_default(csc_for_coeff); s5p_mixer_init_display_mode(disp, out, csc); +#ifndef __CONFIG_HDMI_SUPPORT_FULL_RANGE__ if (!s5p_tvif_get_q_range() || out == TVOUT_HDMI_RGB) mixer_video_limiter = true; else mixer_video_limiter = false; +#else + /* full range */ + if ((out == TVOUT_HDMI_RGB && disp == TVOUT_480P_60_4_3) || + (out != TVOUT_HDMI_RGB && s5p_tvif_get_q_range())) { + mixer_video_limiter = false; + for (i = MIXER_BG_COLOR_0; i <= MIXER_BG_COLOR_2; i++) + s5p_mixer_ctrl_private.bg_color[i].color_y = 0; + } else { /* limited range */ + mixer_video_limiter = true; + for (i = MIXER_BG_COLOR_0; i <= MIXER_BG_COLOR_2; i++) + s5p_mixer_ctrl_private.bg_color[i].color_y = 16; + } +#endif s5p_mixer_set_video_limiter(s5p_mixer_ctrl_private.v_layer.y_min, s5p_mixer_ctrl_private.v_layer.y_max, diff --git a/drivers/media/video/samsung/tvout/s5p_tvif_ctrl.c b/drivers/media/video/samsung/tvout/s5p_tvif_ctrl.c index 93cb640..43e7a1f 100644 --- a/drivers/media/video/samsung/tvout/s5p_tvif_ctrl.c +++ b/drivers/media/video/samsung/tvout/s5p_tvif_ctrl.c @@ -49,6 +49,12 @@ #if defined(CONFIG_BUSFREQ_OPP) || defined(CONFIG_BUSFREQ_LOCK_WRAPPER) #include <mach/dev.h> #endif +#include <mach/regs-hdmi.h> + +#ifdef CONFIG_HDMI_TX_STRENGTH +#include <plat/tvout.h> +#endif + #include "s5p_tvout_common_lib.h" #include "hw_if/hw_if.h" @@ -1758,7 +1764,7 @@ static void s5p_sdo_ctrl_clock(bool on) #ifdef CONFIG_ARCH_EXYNOS4 s5p_tvout_pm_runtime_get(); #endif - // Restore sdo_base address + /* Restore sdo_base address */ s5p_sdo_init(s5p_sdo_ctrl_private.reg_mem.base); clk_enable(s5p_sdo_ctrl_private.clk[SDO_PCLK].ptr); @@ -1771,7 +1777,7 @@ static void s5p_sdo_ctrl_clock(bool on) clk_disable(s5p_sdo_ctrl_private.clk[SDO_MUX].ptr); - // Set sdo_base address to NULL + /* Set sdo_base address to NULL */ s5p_sdo_init(NULL); } @@ -2362,8 +2368,10 @@ static void s5p_hdmi_ctrl_internal_stop(void) #ifdef CONFIG_HDMI_HPD s5p_hpd_set_eint(); #endif - if (ctrl->hdcp_en) + if (ctrl->hdcp_en) { s5p_hdcp_stop(); + s5p_hdcp_flush_work(); + } s5p_hdmi_reg_enable(false); @@ -2376,10 +2384,16 @@ int s5p_hdmi_ctrl_phy_power(bool on) if (on) { /* on */ clk_enable(s5ptv_status.i2c_phy_clk); - // Restore i2c_hdmi_phy_base address + /* Restore i2c_hdmi_phy_base address */ s5p_hdmi_phy_init(s5p_hdmi_ctrl_private.reg_mem[HDMI_PHY].base); s5p_hdmi_phy_power(true); +#ifdef CONFIG_HDMI_TX_STRENGTH + if (s5p_tvif_ctrl_private.tx_val) + s5p_hdmi_phy_set_tx_strength( + s5p_tvif_ctrl_private.tx_ch, + s5p_tvif_ctrl_private.tx_val); +#endif } else { /* @@ -2398,7 +2412,7 @@ int s5p_hdmi_ctrl_phy_power(bool on) s5p_hdmi_phy_power(false); clk_disable(s5ptv_status.i2c_phy_clk); - // Set i2c_hdmi_phy_base to NULL + /* Set i2c_hdmi_phy_base to NULL */ s5p_hdmi_phy_init(NULL); } @@ -2419,7 +2433,7 @@ void s5p_hdmi_ctrl_clock(bool on) #endif clk_enable(clk[HDMI_PCLK].ptr); - // Restore hdmi_base address + /* Restore hdmi_base address */ s5p_hdmi_init(s5p_hdmi_ctrl_private.reg_mem[HDMI].base); } else { clk_disable(clk[HDMI_PCLK].ptr); @@ -2430,7 +2444,7 @@ void s5p_hdmi_ctrl_clock(bool on) clk_disable(clk[HDMI_MUX].ptr); - // Set hdmi_base to NULL + /* Set hdmi_base to NULL */ s5p_hdmi_init(NULL); } } @@ -2447,7 +2461,7 @@ void s5p_hdmi_ctrl_stop(void) tvout_dbg("running(%d)\n", ctrl->running); if (ctrl->running) { ctrl->running = false; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); } else @@ -2681,7 +2695,7 @@ static int s5p_tvif_ctrl_internal_stop(void) case TVOUT_HDMI: case TVOUT_HDMI_RGB: s5p_hdmi_ctrl_stop(); -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); } else @@ -2705,6 +2719,10 @@ static void s5p_tvif_ctrl_internal_start( enum s5p_tvout_o_mode inf) { tvout_dbg("\n"); +#ifdef __CONFIG_HDMI_SUPPORT_FULL_RANGE__ + s5p_hdmi_output[inf].reg.pxl_limit = + S5P_HDMI_PX_LMT_CTRL_BYPASS; +#endif s5p_mixer_ctrl_set_int_enable(false); /* Clear All Interrupt Pending */ @@ -2724,6 +2742,47 @@ static void s5p_tvif_ctrl_internal_start( case TVOUT_HDMI: case TVOUT_HDMI_RGB: case TVOUT_DVI: +#ifdef __CONFIG_HDMI_SUPPORT_FULL_RANGE__ + switch (std) { + case TVOUT_480P_60_4_3: + if (inf == TVOUT_HDMI_RGB) /* full range */ + s5p_hdmi_output[inf].reg.pxl_limit = + S5P_HDMI_PX_LMT_CTRL_BYPASS; + else if (s5p_tvif_get_q_range()) /* full range */ + s5p_hdmi_output[inf].reg.pxl_limit = + S5P_HDMI_PX_LMT_CTRL_BYPASS; + else /* limited range */ + s5p_hdmi_output[inf].reg.pxl_limit = + S5P_HDMI_PX_LMT_CTRL_YPBPR; + break; + case TVOUT_480P_60_16_9: + case TVOUT_480P_59: + case TVOUT_576P_50_16_9: + case TVOUT_576P_50_4_3: + case TVOUT_720P_60: + case TVOUT_720P_50: + case TVOUT_720P_59: + case TVOUT_1080I_60: + case TVOUT_1080I_59: + case TVOUT_1080I_50: + case TVOUT_1080P_60: + case TVOUT_1080P_30: + case TVOUT_1080P_59: + case TVOUT_1080P_50: + if (inf == TVOUT_HDMI_RGB) /* limited range */ + s5p_hdmi_output[inf].reg.pxl_limit = + S5P_HDMI_PX_LMT_CTRL_RGB; + else if (s5p_tvif_get_q_range()) /* full range */ + s5p_hdmi_output[inf].reg.pxl_limit = + S5P_HDMI_PX_LMT_CTRL_BYPASS; + else /* limited range */ + s5p_hdmi_output[inf].reg.pxl_limit = + S5P_HDMI_PX_LMT_CTRL_YPBPR; + break; + default: + break; + } +#endif s5p_hdmi_ctrl_phy_power(1); if (s5p_mixer_ctrl_start(std, inf) < 0) @@ -2854,7 +2913,7 @@ int s5p_tvif_ctrl_start( goto cannot_change; } -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); } else @@ -2889,6 +2948,16 @@ void s5p_tvif_ctrl_stop(void) int s5p_tvif_ctrl_constructor(struct platform_device *pdev) { +#ifdef CONFIG_HDMI_TX_STRENGTH + struct s5p_platform_tvout *pdata = to_tvout_plat(&pdev->dev); + s5p_tvif_ctrl_private.tx_ch = 0x00; + s5p_tvif_ctrl_private.tx_val = NULL; + if ((pdata) && (pdata->tx_tune)) { + s5p_tvif_ctrl_private.tx_ch = pdata->tx_tune->tx_ch; + s5p_tvif_ctrl_private.tx_val = pdata->tx_tune->tx_val; + } +#endif + #ifdef CONFIG_ANALOG_TVENC if (s5p_sdo_ctrl_constructor(pdev)) goto err; diff --git a/drivers/media/video/samsung/tvout/s5p_tvout.c b/drivers/media/video/samsung/tvout/s5p_tvout.c index 7407670..5f00ebc 100644 --- a/drivers/media/video/samsung/tvout/s5p_tvout.c +++ b/drivers/media/video/samsung/tvout/s5p_tvout.c @@ -13,6 +13,7 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/mm.h> +#include <linux/delay.h> #if defined(CONFIG_S5P_SYSMMU_TV) #include <plat/sysmmu.h> @@ -25,6 +26,10 @@ #include <mach/media.h> #endif +#if defined(CONFIG_HDMI_TX_STRENGTH) && !defined(CONFIG_USER_ALLOC_TVOUT) +#include <plat/tvout.h> +#endif + #include "s5p_tvout_common_lib.h" #include "s5p_tvout_ctrl.h" #include "s5p_tvout_fb.h" @@ -291,6 +296,12 @@ static int __devinit s5p_tvout_probe(struct platform_device *pdev) struct device *hdmi_audio_dev; #endif +#if defined(CONFIG_HDMI_TX_STRENGTH) && !defined(CONFIG_USER_ALLOC_TVOUT) + struct s5p_platform_tvout *pdata; + u8 tx_ch; + u8 *tx_val; +#endif + #ifdef CONFIG_TVOUT_DEBUG struct class *sec_tvout; tvout_dbg_flag = 1 << DBG_FLAG_HPD; @@ -339,6 +350,15 @@ static int __devinit s5p_tvout_probe(struct platform_device *pdev) s5p_hdmi_phy_power(true); if (s5p_tvif_ctrl_start(TVOUT_720P_60, TVOUT_HDMI) < 0) goto err_tvif_start; +#ifdef CONFIG_HDMI_TX_STRENGTH + pdata = to_tvout_plat(&pdev->dev); + if (pdata && pdata->tx_tune) { + tx_ch = pdata->tx_tune->tx_ch; + tx_val = pdata->tx_tune->tx_val; + } + if (tx_ch && tx_val) + s5p_hdmi_phy_set_tx_strength(tx_ch, tx_val); +#endif #endif /* prepare memory */ @@ -495,14 +515,19 @@ static int s5p_tvout_remove(struct platform_device *pdev) static void s5p_tvout_early_suspend(struct early_suspend *h) { tvout_dbg("\n"); +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND mutex_lock(&s5p_tvout_mutex); - s5p_mixer_ctrl_set_vsync_interrupt(false); + /* disable vsync interrupt during early suspend */ + s5p_mixer_ctrl_disable_vsync_interrupt(); s5p_vp_ctrl_suspend(); s5p_mixer_ctrl_suspend(); s5p_tvif_ctrl_suspend(); suspend_status = 1; tvout_dbg("suspend_status is true\n"); mutex_unlock(&s5p_tvout_mutex); +#else + suspend_status = 1; +#endif return; } @@ -511,6 +536,7 @@ static void s5p_tvout_late_resume(struct early_suspend *h) { tvout_dbg("\n"); +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND mutex_lock(&s5p_tvout_mutex); #if defined(CONFIG_CPU_EXYNOS4212) || defined(CONFIG_CPU_EXYNOS4412) @@ -521,11 +547,17 @@ static void s5p_tvout_late_resume(struct early_suspend *h) #endif suspend_status = 0; tvout_dbg("suspend_status is false\n"); + s5p_tvif_ctrl_resume(); s5p_mixer_ctrl_resume(); s5p_vp_ctrl_resume(); - s5p_mixer_ctrl_set_vsync_interrupt(s5p_mixer_ctrl_get_vsync_interrupt()); + /* restore vsync interrupt setting */ + s5p_mixer_ctrl_set_vsync_interrupt( + s5p_mixer_ctrl_get_vsync_interrupt()); mutex_unlock(&s5p_tvout_mutex); +#else + suspend_status = 0; +#endif return; } @@ -562,8 +594,10 @@ static int s5p_tvout_suspend(struct device *dev) static int s5p_tvout_resume(struct device *dev) { tvout_dbg("\n"); +#if defined(CLOCK_GATING_ON_EARLY_SUSPEND) #if defined(CONFIG_CPU_EXYNOS4212) || defined(CONFIG_CPU_EXYNOS4412) flag_after_resume = true; +#endif #else queue_work_on(0, tvout_resume_wq, &tvout_resume_work); #endif diff --git a/drivers/media/video/samsung/tvout/s5p_tvout_common_lib.h b/drivers/media/video/samsung/tvout/s5p_tvout_common_lib.h index e43b9c7..467ab1d 100644 --- a/drivers/media/video/samsung/tvout/s5p_tvout_common_lib.h +++ b/drivers/media/video/samsung/tvout/s5p_tvout_common_lib.h @@ -45,6 +45,12 @@ do { \ #endif #endif +/* +#if defined(CONFIG_MACH_T0) || defined(CONFIG_MACH_M3) +#define __CONFIG_HDMI_SUPPORT_FULL_RANGE__ +#endif +*/ + #define S5PTV_FB_CNT 2 #define S5PTV_VP_BUFF_CNT 4 #define S5PTV_VP_BUFF_SIZE (4*1024*1024) @@ -53,6 +59,10 @@ do { \ #define HDMI_START_NUM 0x1000 +#ifdef CONFIG_CPU_EXYNOS4210 +#define CLOCK_GATING_ON_EARLY_SUSPEND +#endif + enum s5p_tvout_disp_mode { TVOUT_NTSC_M = 0, TVOUT_PAL_BDGHI, diff --git a/drivers/media/video/samsung/tvout/s5p_tvout_ctrl.h b/drivers/media/video/samsung/tvout/s5p_tvout_ctrl.h index 43043b4..b330a95 100644 --- a/drivers/media/video/samsung/tvout/s5p_tvout_ctrl.h +++ b/drivers/media/video/samsung/tvout/s5p_tvout_ctrl.h @@ -29,7 +29,8 @@ extern void s5p_mixer_ctrl_init_fb_addr_phy(enum s5p_mixer_layer layer, dma_addr_t fb_addr); extern void s5p_mixer_ctrl_init_grp_layer(enum s5p_mixer_layer layer); -extern int s5p_mixer_ctrl_set_pixel_format(enum s5p_mixer_layer layer, u32 bpp, u32 trans_len); +extern int s5p_mixer_ctrl_set_pixel_format( + enum s5p_mixer_layer layer, u32 bpp, u32 trans_len); extern int s5p_mixer_ctrl_enable_layer(enum s5p_mixer_layer layer); extern int s5p_mixer_ctrl_disable_layer(enum s5p_mixer_layer layer); extern int s5p_mixer_ctrl_set_priority(enum s5p_mixer_layer layer, u32 prio); @@ -52,6 +53,7 @@ extern int s5p_mixer_ctrl_mux_clk(struct clk *ptr); extern void s5p_mixer_ctrl_set_int_enable(bool en); extern void s5p_mixer_ctrl_set_vsync_interrupt(bool en); extern bool s5p_mixer_ctrl_get_vsync_interrupt(void); +extern void s5p_mixer_ctrl_disable_vsync_interrupt(void); extern void s5p_mixer_ctrl_clear_pend_all(void); extern void s5p_mixer_ctrl_stop(void); extern void s5p_mixer_ctrl_internal_start(void); diff --git a/drivers/media/video/samsung/tvout/s5p_tvout_fb.c b/drivers/media/video/samsung/tvout/s5p_tvout_fb.c index 5a2ce5a..c0a3508 100644 --- a/drivers/media/video/samsung/tvout/s5p_tvout_fb.c +++ b/drivers/media/video/samsung/tvout/s5p_tvout_fb.c @@ -303,7 +303,7 @@ static int s5p_tvout_fb_blank(int blank_mode, struct fb_info *fb) tvout_dbg("change blank mode\n"); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif switch (fb->node) { @@ -336,12 +336,12 @@ static int s5p_tvout_fb_blank(int blank_mode, struct fb_info *fb) goto err_fb_blank; } -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return 1; err_fb_blank: -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return -1; @@ -356,7 +356,7 @@ static int s5p_tvout_fb_set_par(struct fb_info *fb) tvout_dbg("[fb%d] set_par\n", win->id); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif if (!fb->fix.smem_start) { @@ -390,7 +390,7 @@ static int s5p_tvout_fb_set_par(struct fb_info *fb) s5p_mixer_ctrl_set_src_win_pos(layer, src_x, src_y, w, h); s5p_mixer_ctrl_set_alpha_blending(layer, win->alpha.mode, win->alpha.value); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return 0; @@ -472,7 +472,7 @@ static int s5p_tvout_fb_ioctl(struct fb_info *fb, unsigned int cmd, } p; tvout_dbg("\n"); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif switch (fb->node) { @@ -552,13 +552,13 @@ static int s5p_tvout_fb_ioctl(struct fb_info *fb, unsigned int cmd, s5p_mixer_ctrl_scaling(layer, p.user_scaling); break; } -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return 0; err_fb_ioctl: -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return -1; diff --git a/drivers/media/video/samsung/tvout/s5p_tvout_hpd.c b/drivers/media/video/samsung/tvout/s5p_tvout_hpd.c index 4f35a91..1c98453 100644 --- a/drivers/media/video/samsung/tvout/s5p_tvout_hpd.c +++ b/drivers/media/video/samsung/tvout/s5p_tvout_hpd.c @@ -67,6 +67,12 @@ struct hpd_struct { #endif }; +#ifdef CONFIG_HDMI_CONTROLLED_BY_EXT_IC +static work_func_t ext_ic_control_func(void) ; +static DECLARE_DELAYED_WORK(ext_ic_control_dwork, + (work_func_t)ext_ic_control_func); +#endif + static struct hpd_struct hpd_struct; static int last_hpd_state; @@ -81,6 +87,10 @@ static ssize_t s5p_hpd_read(struct file *file, char __user *buffer, static unsigned int s5p_hpd_poll(struct file *file, poll_table *wait); static long s5p_hpd_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +#ifdef CONFIG_SAMSUNG_WORKAROUND_HPD_GLANCE +void mhl_hpd_handler(bool onoff); +bool (*is_mhl_power_state_on)(void); +#endif static const struct file_operations hpd_fops = { .owner = THIS_MODULE, @@ -139,6 +149,7 @@ static void s5p_hpd_kobject_uevent(void) if (hpd_state) { if (last_uevent_state == -1 || last_uevent_state == HPD_LO) { #ifdef CONFIG_HDMI_CONTROLLED_BY_EXT_IC + HPDPRINTK("ext_ic power ON\n"); hpd_struct.ext_ic_control(true); msleep(20); #endif @@ -154,9 +165,13 @@ static void s5p_hpd_kobject_uevent(void) KOBJ_CHANGE, envp); #endif HPDPRINTK("[HDMI] HPD event -connect!!!\n"); - on_start_process = true; + if (atomic_read(&hdmi_status) == HDMI_OFF) { + on_start_process = true; + } else { + on_start_process = false; + } HPDIFPRINTK("%s() on_start_process(%d)\n", - __func__, on_start_process); + __func__, on_start_process); } last_uevent_state = HPD_HI; } else { @@ -176,10 +191,14 @@ static void s5p_hpd_kobject_uevent(void) KOBJ_CHANGE, envp); #endif HPDPRINTK("[HDMI] HPD event -disconnet!!!\n"); - on_stop_process = true; -#ifdef CONFIG_HDMI_CONTROLLED_BY_EXT_IC - hpd_struct.ext_ic_control(false); -#endif + if (atomic_read(&hdmi_status) == HDMI_ON) { + on_stop_process = true; + } else { + on_stop_process = false; + } + HPDIFPRINTK("%s() on_stop_process(%d)\n", + __func__, on_stop_process); + } last_uevent_state = HPD_LO; } @@ -233,9 +252,16 @@ static unsigned int s5p_hpd_poll(struct file *file, poll_table * wait) void hdmi_send_audio_ch_num( int supported_ch_num, struct switch_dev *p_audio_ch_switch) { - printk(KERN_INFO "%s() hdmi_send_audio_ch_num :: " - "HDMI Audio supported ch = %d", - __func__, supported_ch_num); + if (last_uevent_state == HPD_LO) { + printk(KERN_INFO "[WARNING] %s() " + "HDMI Audio ch = %d but not send\n", + __func__, supported_ch_num); + return; + } else + printk(KERN_INFO "%s() " + "HDMI Audio ch = %d\n", + __func__, supported_ch_num); + p_audio_ch_switch->state = 0; switch_set_state(p_audio_ch_switch, (int)supported_ch_num); } @@ -366,7 +392,16 @@ static int s5p_hpd_irq_eint(int irq) atomic_set(&poll_state, 1); last_hpd_state = HPD_LO; +#ifdef CONFIG_SAMSUNG_WORKAROUND_HPD_GLANCE + if (is_mhl_power_state_on != NULL) + if (!is_mhl_power_state_on()) + mhl_hpd_handler(false); +#endif +#ifdef CONFIG_HDMI_CONTROLLED_BY_EXT_IC + schedule_delayed_work(&ext_ic_control_dwork , + msecs_to_jiffies(1000)); +#endif wake_up_interruptible(&hpd_struct.waitq); } schedule_work(&hpd_work); @@ -438,6 +473,15 @@ static int s5p_hpd_irq_hdmi(int irq) atomic_set(&poll_state, 1); last_hpd_state = HPD_LO; +#ifdef CONFIG_SAMSUNG_WORKAROUND_HPD_GLANCE + if (is_mhl_power_state_on != NULL) + if (!is_mhl_power_state_on()) + mhl_hpd_handler(false); +#endif +#ifdef CONFIG_HDMI_CONTROLLED_BY_EXT_IC + schedule_delayed_work(&ext_ic_control_dwork , + msecs_to_jiffies(1000)); +#endif wake_up_interruptible(&hpd_struct.waitq); } @@ -474,6 +518,20 @@ static irqreturn_t s5p_hpd_irq_handler(int irq, void *dev_id) return ret; } +#ifdef CONFIG_HDMI_CONTROLLED_BY_EXT_IC +static work_func_t ext_ic_control_func(void) +{ + if (!hpd_struct.read_gpio()) { + hpd_struct.ext_ic_control(false); + HPDPRINTK("HDMI_EXT_IC Power Off\n"); + } else { + HPDPRINTK("HDMI_EXT_IC Delay work do nothing\n"); + } + return 0; +} +#endif + + #ifdef CONFIG_SAMSUNG_WORKAROUND_HPD_GLANCE static irqreturn_t s5p_hpd_irq_default_handler(int irq, void *dev_id) { @@ -566,6 +624,9 @@ static int __devinit s5p_hpd_probe(struct platform_device *pdev) if (hpd_struct.read_gpio()) { atomic_set(&hpd_struct.state, HPD_HI); last_hpd_state = HPD_HI; +#ifdef CONFIG_HDMI_CONTROLLED_BY_EXT_IC + hpd_struct.ext_ic_control(true); +#endif } else { atomic_set(&hpd_struct.state, HPD_LO); last_hpd_state = HPD_LO; @@ -575,6 +636,7 @@ static int __devinit s5p_hpd_probe(struct platform_device *pdev) hpd_struct.hpd_switch.name = "hdmi"; switch_dev_register(&hpd_struct.hpd_switch); #endif + switch_set_state(&hpd_struct.hpd_switch, last_hpd_state); irq_set_irq_type(hpd_struct.irq_n, IRQ_TYPE_EDGE_BOTH); ret = request_irq(hpd_struct.irq_n, (irq_handler_t) s5p_hpd_irq_handler, diff --git a/drivers/media/video/samsung/tvout/s5p_tvout_v4l2.c b/drivers/media/video/samsung/tvout/s5p_tvout_v4l2.c index 68508e7..3fa6e55 100644 --- a/drivers/media/video/samsung/tvout/s5p_tvout_v4l2.c +++ b/drivers/media/video/samsung/tvout/s5p_tvout_v4l2.c @@ -369,7 +369,7 @@ static int s5p_tvout_tvif_s_std( int i; v4l2_std_id std_id = *norm; -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif for (i = 0; i < S5P_TVOUT_TVIF_NO_OF_STANDARD; i++) { @@ -379,7 +379,8 @@ static int s5p_tvout_tvif_s_std( if (i == S5P_TVOUT_TVIF_NO_OF_STANDARD) { tvout_err("There is no TV standard(0x%08Lx)\n", std_id); -#ifdef CONFIG_HAS_EARLYSUSPEND + +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return -EINVAL; @@ -390,7 +391,7 @@ static int s5p_tvout_tvif_s_std( tvout_dbg("standard id=0x%X, name=\"%s\"\n", (u32) std_id, s5p_tvout_tvif_standard[i].name); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif @@ -437,7 +438,7 @@ static int s5p_tvout_tvif_s_output( return -EINVAL; } -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) s5p_tvout_mutex_lock(); #endif on_start_process = true; @@ -582,12 +583,12 @@ static int s5p_tvout_tvif_s_output( s5p_tvif_ctrl_start(tv_std, tv_if); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) s5p_tvout_mutex_unlock(); #endif return 0; error_on_tvif_s_output: -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) s5p_tvout_mutex_unlock(); #endif return -1; @@ -749,7 +750,7 @@ long s5p_tvout_tvif_ioctl( void *argp = (void *) arg; int i = 0; -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif @@ -916,13 +917,13 @@ long s5p_tvout_tvif_ioctl( break; } -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return video_ioctl2(file, cmd, arg); end_tvif_ioctl: -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return ret; @@ -1035,7 +1036,7 @@ static int s5p_tvout_vo_s_fmt_type_private( (u32) vparam.base_y, (u32) vparam.base_c, pix_fmt->field); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif /* check progressive or not */ @@ -1133,52 +1134,72 @@ static int s5p_tvout_vo_s_fmt_type_private( pix_fmt->height, color, field); #else if (pix_fmt->priv) { - copy_buff_idx = s5ptv_vp_buff.copy_buff_idxs[s5ptv_vp_buff.curr_copy_idx]; - - if ((void *)s5ptv_vp_buff.vp_buffs[copy_buff_idx].vir_base == NULL) { - s5p_vp_ctrl_set_src_plane((u32) vparam.base_y, (u32) vparam.base_c, - pix_fmt->width, pix_fmt->height, color, field); + copy_buff_idx = + s5ptv_vp_buff. + copy_buff_idxs[s5ptv_vp_buff.curr_copy_idx]; + + if ((void *)s5ptv_vp_buff.vp_buffs[copy_buff_idx].vir_base + == NULL) { + s5p_vp_ctrl_set_src_plane( + (u32) vparam.base_y, (u32) vparam.base_c, + pix_fmt->width, pix_fmt->height, color, field); } else { - if (pix_fmt->pixelformat == V4L2_PIX_FMT_NV12T - || pix_fmt->pixelformat == V4L2_PIX_FMT_NV21T) { - y_size = ALIGN(ALIGN(pix_fmt->width, 128) * ALIGN(pix_fmt->height, 32), SZ_8K); - cbcr_size = ALIGN(ALIGN(pix_fmt->width, 128) * ALIGN(pix_fmt->height >> 1, 32), SZ_8K); + if (pix_fmt->pixelformat == + V4L2_PIX_FMT_NV12T + || pix_fmt->pixelformat == V4L2_PIX_FMT_NV21T) { + y_size = ALIGN(ALIGN(pix_fmt->width, 128) * + ALIGN(pix_fmt->height, 32), SZ_8K); + cbcr_size = ALIGN(ALIGN(pix_fmt->width, 128) * + ALIGN(pix_fmt->height >> 1, 32), SZ_8K); } else { y_size = pix_fmt->width * pix_fmt->height; - cbcr_size = pix_fmt->width * (pix_fmt->height >> 1); + cbcr_size = + pix_fmt->width * (pix_fmt->height >> 1); } - src_vir_y_addr = (unsigned int)phys_to_virt((unsigned long)vparam.base_y); - src_vir_cb_addr = (unsigned int)phys_to_virt((unsigned long)vparam.base_c); + src_vir_y_addr = (unsigned int)phys_to_virt( + (unsigned long)vparam.base_y); + src_vir_cb_addr = (unsigned int)phys_to_virt( + (unsigned long)vparam.base_c); - memcpy((void *)s5ptv_vp_buff.vp_buffs[copy_buff_idx].vir_base, - (void *)src_vir_y_addr, y_size); - memcpy((void *)s5ptv_vp_buff.vp_buffs[copy_buff_idx].vir_base + y_size, - (void *)src_vir_cb_addr, cbcr_size); + memcpy( + (void *) + s5ptv_vp_buff.vp_buffs[copy_buff_idx].vir_base, + (void *)src_vir_y_addr, y_size); + memcpy( + (void *)s5ptv_vp_buff.vp_buffs[copy_buff_idx]. + vir_base + y_size, + (void *)src_vir_cb_addr, cbcr_size); flush_all_cpu_caches(); outer_flush_all(); - s5p_vp_ctrl_set_src_plane((u32) s5ptv_vp_buff.vp_buffs[copy_buff_idx].phy_base, - (u32) s5ptv_vp_buff.vp_buffs[copy_buff_idx].phy_base + y_size, - pix_fmt->width, pix_fmt->height, color, field); + s5p_vp_ctrl_set_src_plane( + (u32) s5ptv_vp_buff. + vp_buffs[copy_buff_idx].phy_base, + (u32) s5ptv_vp_buff. + vp_buffs[copy_buff_idx].phy_base + + y_size, + pix_fmt->width, pix_fmt->height, color, field); s5ptv_vp_buff.curr_copy_idx++; - if (s5ptv_vp_buff.curr_copy_idx >= S5PTV_VP_BUFF_CNT - 1) + if (s5ptv_vp_buff.curr_copy_idx >= + S5PTV_VP_BUFF_CNT - 1) s5ptv_vp_buff.curr_copy_idx = 0; } } else { - s5p_vp_ctrl_set_src_plane((u32) vparam.base_y, (u32) vparam.base_c, - pix_fmt->width, pix_fmt->height, color, field); + s5p_vp_ctrl_set_src_plane( + (u32) vparam.base_y, (u32) vparam.base_c, + pix_fmt->width, pix_fmt->height, color, field); } #endif -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return 0; error_on_s_fmt_type_private: -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return -1; @@ -1201,7 +1222,7 @@ static int s5p_tvout_vo_s_fmt_vid_overlay( rect->left, rect->top, rect->width, rect->height, a->fmt.win.global_alpha); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif s5p_tvout_v4l2_private.vo_dst_fmt = a->fmt.win; @@ -1211,7 +1232,7 @@ static int s5p_tvout_vo_s_fmt_vid_overlay( rect->left, rect->top, rect->width, rect->height); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return 0; @@ -1237,7 +1258,7 @@ static int s5p_tvout_vo_s_crop( struct file *file, void *fh, struct v4l2_crop *a) { tvout_dbg("\n"); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif switch (a->type) { @@ -1260,7 +1281,7 @@ static int s5p_tvout_vo_s_crop( tvout_err("Invalid buf type(0x%08x)\n", a->type); break; } -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return 0; @@ -1285,7 +1306,7 @@ static int s5p_tvout_vo_s_fbuf( (a->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) ? 1 : 0, a->fmt.priv); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif @@ -1294,7 +1315,7 @@ static int s5p_tvout_vo_s_fbuf( s5p_vp_ctrl_set_dest_win_priority(a->fmt.priv); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return 0; @@ -1305,15 +1326,21 @@ static int s5p_tvout_vo_overlay( { tvout_dbg("%s\n", (i) ? "start" : "stop"); -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_lock(); #endif - if (i) + if (i) { s5p_vp_ctrl_start(); - else + /* restore vsync interrupt setting */ + s5p_mixer_set_vsync_interrupt( + s5p_mixer_ctrl_get_vsync_interrupt()); + } else { + /* disable vsync interrupt when VP is disabled */ + s5p_mixer_ctrl_disable_vsync_interrupt(); s5p_vp_ctrl_stop(); + } -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(CLOCK_GATING_ON_EARLY_SUSPEND) s5p_tvout_mutex_unlock(); #endif return 0; diff --git a/drivers/media/video/samsung/tvout/s5p_vp_ctrl.c b/drivers/media/video/samsung/tvout/s5p_vp_ctrl.c index d074da3..148e3e9 100644 --- a/drivers/media/video/samsung/tvout/s5p_vp_ctrl.c +++ b/drivers/media/video/samsung/tvout/s5p_vp_ctrl.c @@ -279,7 +279,7 @@ static int s5p_vp_ctrl_set_reg(void) struct s5p_vp_ctrl_pp_param *pp_param = &s5p_vp_ctrl_private.pp_param; struct s5p_vp_ctrl_op_mode *op_mode = &s5p_vp_ctrl_private.op_mode; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); } else @@ -362,7 +362,7 @@ static int s5p_vp_ctrl_set_reg(void) static void s5p_vp_ctrl_internal_stop(void) { -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); } else @@ -409,7 +409,7 @@ void s5p_vp_ctrl_set_src_plane( src_plane->w = width; src_plane->h = height; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return; @@ -434,7 +434,7 @@ void s5p_vp_ctrl_set_src_win(u32 left, u32 top, u32 width, u32 height) src_win->w = width; src_win->h = height; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return; @@ -466,7 +466,7 @@ void s5p_vp_ctrl_set_dest_win(u32 left, u32 top, u32 width, u32 height) dst_win->y = top; dst_win->w = width; dst_win->h = height; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return; @@ -493,7 +493,7 @@ void s5p_vp_ctrl_set_dest_win(u32 left, u32 top, u32 width, u32 height) void s5p_vp_ctrl_set_dest_win_alpha_val(u32 alpha) { s5p_vp_ctrl_private.mixer_param.alpha = alpha; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return; @@ -505,7 +505,7 @@ void s5p_vp_ctrl_set_dest_win_alpha_val(u32 alpha) void s5p_vp_ctrl_set_dest_win_blend(bool enable) { s5p_vp_ctrl_private.mixer_param.blend = enable; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return; @@ -518,7 +518,7 @@ void s5p_vp_ctrl_set_dest_win_blend(bool enable) void s5p_vp_ctrl_set_dest_win_priority(u32 prio) { s5p_vp_ctrl_private.mixer_param.prio = prio; -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); return; @@ -531,7 +531,7 @@ void s5p_vp_ctrl_stop(void) { if (s5p_vp_ctrl_private.running) { s5p_vp_ctrl_internal_stop(); -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); } else @@ -647,7 +647,7 @@ int s5p_vp_ctrl_start(void) if (s5p_vp_ctrl_private.running) s5p_vp_ctrl_internal_stop(); else { -#ifdef CONFIG_HAS_EARLYSUSPEND +#ifdef CLOCK_GATING_ON_EARLY_SUSPEND if (suspend_status) { tvout_dbg("driver is suspend_status\n"); } else diff --git a/drivers/media/video/samsung/ump/Kconfig b/drivers/media/video/samsung/ump/Kconfig index aaae26e..6304825 100644 --- a/drivers/media/video/samsung/ump/Kconfig +++ b/drivers/media/video/samsung/ump/Kconfig @@ -20,7 +20,7 @@ config UMP_VCM_ALLOC choice depends on VIDEO_UMP prompt "UMP MEMEMORY OPTION" -default UMP_OSMEM_ONLY +default UMP_OSMEM_ONLY config UMP_DED_ONLY bool "ump dedicated memory only" ---help--- @@ -37,7 +37,7 @@ config UMP_VCM_ONLY endchoice config UMP_MEM_SIZE int "UMP Memory Size" - depends on VIDEO_UMP + depends on VIDEO_UMP default "512" ---help--- This value is dedicated memory size of UMP (unit is MByte). @@ -48,4 +48,3 @@ config VIDEO_UMP_DEBUG default n help This enables UMP driver debug messages. - diff --git a/drivers/media/video/samsung/ump/Makefile b/drivers/media/video/samsung/ump/Makefile index f429c40..b3157a3 100644 --- a/drivers/media/video/samsung/ump/Makefile +++ b/drivers/media/video/samsung/ump/Makefile @@ -1,9 +1,9 @@ # # Copyright (C) 2010 ARM Limited. All rights reserved. -# +# # This program is free software and is provided to you under the terms of the GNU General Public License version 2 # as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. -# +# # A copy of the licence is included with the program, and can also be obtained from Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # @@ -30,14 +30,13 @@ DEFINES += -DDEBUG endif # Set up our defines, which will be passed to gcc -DEFINES += -DKERNEL_BUILTIN=1 DEFINES += -DMALI_USE_UNIFIED_MEMORY_PROVIDER DEFINES += -DUSING_MEMORY=$(USING_MEMORY) DEFINES += -DUMP_MEM_SIZE=$(UMP_MEM_SIZE) DEFINES += -DMALI_STATE_TRACKING=1 UDD_FILE_PREFIX := drivers/media/video/samsung/ump/ -KBUILDROOT = +KBUILDROOT = # linux build system integration @@ -61,7 +60,7 @@ OSKFILES+=\ $(KBUILDROOT)../mali/linux/mali_osk_locks.o \ $(KBUILDROOT)../mali/linux/mali_osk_math.o \ $(KBUILDROOT)../mali/linux/mali_osk_memory.o \ - $(KBUILDROOT)../mali/linux/mali_osk_misc.o + $(KBUILDROOT)../mali/linux/mali_osk_misc.o ump-y := \ $(KBUILDROOT)linux/ump_kernel_linux.o \ @@ -83,12 +82,11 @@ ump-$(CONFIG_UMP_VCM_ALLOC) += \ $(KBUILDROOT)linux/ump_kernel_memory_backend_vcm.o \ EXTRA_CFLAGS += $(INCLUDES) \ - $(DEFINES) - - + $(DEFINES) + + # Get subversion revision number, fall back to 0000 if no svn info is available SVN_REV:=$(shell ((svnversion | grep -qv exported && echo -n 'Revision: ' && svnversion) || git svn info | sed -e 's/$$$$/M/' | grep '^Revision: ' || echo ${MALI_RELEASE_NAME}) 2>/dev/null | sed -e 's/^Revision: //') - + EXTRA_CFLAGS += -DSVN_REV=$(SVN_REV) EXTRA_CFLAGS += -DSVN_REV_STRING=\"$(SVN_REV)\" - diff --git a/drivers/media/video/samsung/ump/Makefile.common b/drivers/media/video/samsung/ump/Makefile.common index 4b5db24..35527a2 100644 --- a/drivers/media/video/samsung/ump/Makefile.common +++ b/drivers/media/video/samsung/ump/Makefile.common @@ -1,17 +1,20 @@ # -# Copyright (C) 2010 ARM Limited. All rights reserved. -# +# Copyright (C) 2010-2012 ARM Limited. All rights reserved. +# # This program is free software and is provided to you under the terms of the GNU General Public License version 2 # as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. -# +# # A copy of the licence is included with the program, and can also be obtained from Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # -UMP_FILE_PREFIX = ./drivers/video/samsung/ump +SRC = $(UMP_FILE_PREFIX)common/ump_kernel_common.c \ + $(UMP_FILE_PREFIX)common/ump_kernel_descriptor_mapping.c \ + $(UMP_FILE_PREFIX)common/ump_kernel_api.c \ + $(UMP_FILE_PREFIX)common/ump_kernel_ref_drv.c -SRC = $(UMP_FILE_PREFIX)/common/ump_kernel_common.c \ - $(UMP_FILE_PREFIX)/common/ump_kernel_descriptor_mapping.c \ - $(UMP_FILE_PREFIX)/common/ump_kernel_api.c \ - $(UMP_FILE_PREFIX)/common/ump_kernel_ref_drv.c +# Get subversion revision number, fall back to 0000 if no svn info is available +SVN_REV:=$(shell ((svnversion | grep -qv exported && echo -n 'Revision: ' && svnversion) || git svn info | sed -e 's/$$$$/M/' | grep '^Revision: ' || echo ${MALI_RELEASE_NAME}) 2>/dev/null | sed -e 's/^Revision: //') +EXTRA_CFLAGS += -DSVN_REV=$(SVN_REV) +EXTRA_CFLAGS += -DSVN_REV_STRING=\"$(SVN_REV)\" diff --git a/drivers/media/video/samsung/ump/Makefile_backup b/drivers/media/video/samsung/ump/Makefile_backup deleted file mode 100644 index 632cb0c..0000000 --- a/drivers/media/video/samsung/ump/Makefile_backup +++ /dev/null @@ -1,80 +0,0 @@ -# -# Copyright (C) 2010 ARM Limited. All rights reserved. -# -# This program is free software and is provided to you under the terms of the GNU General Public License version 2 -# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. -# -# A copy of the licence is included with the program, and can also be obtained from Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -BUILD ?= debug -USING_MALI400 ?= 1 -USING_ZBT ?= 0 -USING_MMU ?= 1 -USING_UMP ?= 1 -CPU ?= vega1 -CONFIG ?= marcopolo-vega1-m400 - - -# Set up our defines, which will be passed to gcc -DEFINES += -DUSING_MALI400=$(USING_MALI400) -DEFINES += -DUSING_ZBT=$(USING_ZBT) -DEFINES += -DUSING_MMU=$(USING_MMU) -DEFINES += -DUSING_UMP=$(USING_UMP) -DEFINES += -DMALI_USE_UNIFIED_MEMORY_PROVIDER -ifeq ($(BUILD), debug) -DEFINES += -DDEBUG -endif - - -UMP_FILE_PREFIX := drivers/video/samsung/ump -UDD_FILE_PREFIX := drivers/video/samsung/mali -KBUILDROOT = - -# linux build system integration - -obj-y += ump.o - -# For customer releases the Linux Device Drivers will be provided as ARM proprietary and GPL releases: -# The ARM proprietary product will only include the license/proprietary directory -# The GPL product will only include the license/gpl directory - -INCLUDES = \ - -I$(UMP_FILE_PREFIX)\ - -I$(UMP_FILE_PREFIX)/common\ - -I$(UMP_FILE_PREFIX)/linux\ - -I$(UMP_FILE_PREFIX)/include\ - -I$(UMP_FILE_PREFIX)/linux/license/proprietary/\ - -I$(UDD_FILE_PREFIX)/common\ - -I$(UDD_FILE_PREFIX)/linux - -ump-y := \ - $(KBUILDROOT)linux/ump_kernel_linux.o \ - $(KBUILDROOT)linux/ump_kernel_memory_backend_os.o \ - $(KBUILDROOT)linux/ump_kernel_memory_backend_dedicated.o \ - $(KBUILDROOT)linux/ump_memory_backend.o \ - $(KBUILDROOT)linux/ump_ukk_wrappers.o \ - $(KBUILDROOT)linux/ump_ukk_ref_wrappers.o \ - $(KBUILDROOT)linux/ump_osk_atomics.o \ - $(KBUILDROOT)linux/ump_osk_low_level_mem.o \ - $(KBUILDROOT)linux/ump_osk_misc.o \ - $(KBUILDROOT)../mali/linux/mali_osk_atomics.o \ - $(KBUILDROOT)../mali/linux/mali_osk_locks.o \ - $(KBUILDROOT)../mali/linux/mali_osk_memory.o \ - $(KBUILDROOT)../mali/linux/mali_osk_math.o \ - $(KBUILDROOT)../mali/linux/mali_osk_misc.o \ - $(KBUILDROOT)common/ump_kernel_common.o \ - $(KBUILDROOT)common/ump_kernel_descriptor_mapping.o \ - $(KBUILDROOT)common/ump_kernel_api.o \ - $(KBUILDROOT)common/ump_kernel_ref_drv.o - -EXTRA_CFLAGS += $(INCLUDES) \ - $(DEFINES) - - -# Get subversion revision number, fall back to 0000 if no svn info is available -SVN_REV:=$(shell ((svnversion | grep -qv exported && echo -n 'Revision: ' && svnversion) || git svn info | sed -e 's/$$$$/M/' | grep '^Revision: ' || echo ${MALI_RELEASE_NAME}) 2>/dev/null | sed -e 's/^Revision: //') - -EXTRA_CFLAGS += -DSVN_REV=$(SVN_REV) -EXTRA_CFLAGS += -DSVN_REV_STRING=\"$(SVN_REV)\" - diff --git a/drivers/media/video/samsung/ump/Makefile_module b/drivers/media/video/samsung/ump/Makefile_module new file mode 100644 index 0000000..f0c3829 --- /dev/null +++ b/drivers/media/video/samsung/ump/Makefile_module @@ -0,0 +1,119 @@ +# +# Copyright (C) 2010-2012 ARM Limited. All rights reserved. +# +# This program is free software and is provided to you under the terms of the GNU General Public License version 2 +# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. +# +# A copy of the licence is included with the program, and can also be obtained from Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +UMP_FILE_PREFIX = +UDD_FILE_PREFIX = ../mali/ + +ifneq ($(KBUILD_EXTMOD),) +include $(KBUILD_EXTMOD)/Makefile.common +else +include ./Makefile.common +endif + +# For each arch check: CROSS_COMPILE , KDIR , CFLAGS += -DARCH + +ARCH ?= arm +BUILD ?= debug + +EXTRA_CFLAGS += -DDEBUG -DMALI_STATE_TRACKING=0 +ifeq ($(BUILD), debug) +EXTRA_CFLAGS += -DDEBUG +endif + +# linux build system integration + +ifneq ($(KERNELRELEASE),) +# Inside the kernel build system + +EXTRA_CFLAGS += -I$(KBUILD_EXTMOD) -I$(KBUILD_EXTMOD)/common -I$(KBUILD_EXTMOD)/linux -I$(KBUILD_EXTMOD)/../mali/common -I$(KBUILD_EXTMOD)/../mali/linux -I$(KBUILD_EXTMOD)/../../ump/include/ump + +# For customer releases the Linux Device Drivers will be provided as ARM proprietary and GPL releases: +# The ARM proprietary product will only include the license/proprietary directory +# The GPL product will only include the license/gpl directory + +ifeq ($(wildcard $(KBUILD_EXTMOD)/linux/license/gpl/*),) +EXTRA_CFLAGS += -I$(KBUILD_EXTMOD)/linux/license/proprietary +else +EXTRA_CFLAGS += -I$(KBUILD_EXTMOD)/linux/license/gpl +endif + +SRC += $(UMP_FILE_PREFIX)linux/ump_kernel_linux.c \ + $(UMP_FILE_PREFIX)linux/ump_kernel_memory_backend_os.c \ + $(UMP_FILE_PREFIX)linux/ump_kernel_memory_backend_dedicated.c \ + $(UMP_FILE_PREFIX)linux/ump_memory_backend.c \ + $(UMP_FILE_PREFIX)linux/ump_ukk_wrappers.c \ + $(UMP_FILE_PREFIX)linux/ump_ukk_ref_wrappers.c \ + $(UMP_FILE_PREFIX)linux/ump_osk_atomics.c \ + $(UMP_FILE_PREFIX)linux/ump_osk_low_level_mem.c \ + $(UMP_FILE_PREFIX)linux/ump_osk_misc.c \ + $(UDD_FILE_PREFIX)linux/mali_osk_atomics.c \ + $(UDD_FILE_PREFIX)linux/mali_osk_locks.c \ + $(UDD_FILE_PREFIX)linux/mali_osk_memory.c \ + $(UDD_FILE_PREFIX)linux/mali_osk_math.c \ + $(UDD_FILE_PREFIX)linux/mali_osk_misc.c + +# Selecting files to compile by parsing the config file + +MODULE:=ump.ko + +obj-m := $(MODULE:.ko=.o) +$(MODULE:.ko=-y) := $(SRC:.c=.o) + +else +# Outside the kernel build system + +# Check that required parameters are supplied. +ifeq ($(CONFIG),) +$(error "CONFIG must be specified.") +endif +ifeq ($(CPU)$(KDIR),) +$(error "KDIR or CPU must be specified.") +endif + +# Get any user defined KDIR-<names> or maybe even a hardcoded KDIR +-include KDIR_CONFIGURATION + +# Define host system directory +KDIR-$(shell uname -m):=/lib/modules/$(shell uname -r)/build + +ifeq ($(ARCH), arm) + # when compiling for ARM we're cross compiling + export CROSS_COMPILE ?= arm-none-linux-gnueabi- +endif + +# look up KDIR based om CPU selection +KDIR ?= $(KDIR-$(CPU)) + +ifeq ($(KDIR),) +$(error No KDIR found for platform $(CPU)) +endif + +# Validate selected config +ifneq ($(shell [ -d arch-$(CONFIG) ] && [ -f arch-$(CONFIG)/config.h ] && echo "OK"), OK) +$(warning Current directory is $(shell pwd)) +$(error No configuration found for config $(CONFIG). Check that arch-$(CONFIG)/config.h exists) +else +# Link arch to the selected arch-config directory +$(shell [ -L arch ] && rm arch) +$(shell ln -sf arch-$(CONFIG) arch) +$(shell touch arch/config.h) +endif + +all: + $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) modules + +kernelrelease: + $(MAKE) ARCH=$(ARCH) -C $(KDIR) kernelrelease + +clean: + $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) clean + $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR)/../mali clean + +endif diff --git a/drivers/media/video/samsung/ump/arch b/drivers/media/video/samsung/ump/arch deleted file mode 120000 index a65a3fc..0000000 --- a/drivers/media/video/samsung/ump/arch +++ /dev/null @@ -1 +0,0 @@ -./arch-orion-m400
\ No newline at end of file diff --git a/drivers/media/video/samsung/mali/common/mali_kernel_pp.h b/drivers/media/video/samsung/ump/arch-debug/config.h index 8cf7bf7..688edc9 100644 --- a/drivers/media/video/samsung/mali/common/mali_kernel_pp.h +++ b/drivers/media/video/samsung/ump/arch-debug/config.h @@ -1,21 +1,22 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __MALI_KERNEL_PP_H__ -#define __MALI_KERNEL_PP_H__ +#ifndef __ARCH_CONFIG_UMP_H__ +#define __ARCH_CONFIG_UMP_H__ -extern struct mali_kernel_subsystem mali_subsystem_mali200; - -#if USING_MALI_PMM -_mali_osk_errcode_t malipp_signal_power_up( u32 core_num, mali_bool queue_only ); -_mali_osk_errcode_t malipp_signal_power_down( u32 core_num, mali_bool immediate_only ); +#define ARCH_UMP_BACKEND_DEFAULT USING_MEMORY +#if (USING_MEMORY == 0) /* Dedicated Memory */ +#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0x2C000000 +#else +#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0 #endif -#endif /* __MALI_KERNEL_PP_H__ */ +#define ARCH_UMP_MEMORY_SIZE_DEFAULT UMP_MEM_SIZE*1024*1024 +#endif /* __ARCH_CONFIG_UMP_H__ */ diff --git a/drivers/media/video/samsung/ump/arch-marcopolo-vega1-m400/config.h.org b/drivers/media/video/samsung/ump/arch-marcopolo-vega1-m400/config.h.org deleted file mode 100755 index c92a32a..0000000 --- a/drivers/media/video/samsung/ump/arch-marcopolo-vega1-m400/config.h.org +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * - * This program is free software and is provided to you under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * - * A copy of the licence is included with the program, and can also be obtained from Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __ARCH_CONFIG_H__ -#define __ARCH_CONFIG_H__ - -/* Configuration for the EB platform with ZBT memory enabled */ -#define MALI_BASE_ADDR 0xf0000000 -#define GP_ADDR MALI_BASE_ADDR -#define L2_ADDR MALI_BASE_ADDR+0x1000 -#define PMU_ADDR MALI_BASE_ADDR+0x2000 -#define GP_MMU_ADDR MALI_BASE_ADDR+0x3000 -#define PP_MMU_ADDR MALI_BASE_ADDR+0x4000 -#define PP_ADDR MALI_BASE_ADDR+0x8000 - -// See 3-11 page in trm. It describes control register address map. cglee - -static _mali_osk_resource_t arch_configuration [] = -{ - { - .type = MALI400GP, - .description = "Mali-400 GP", - .base = GP_ADDR, - .irq = 18+32, - .mmu_id = 1 - }, - { - .type = MALI400PP, - .base = PP_ADDR, - .irq = 16+32, - .description = "Mali-400 PP 0", - .mmu_id = 2 - }, -#if USING_MMU - { - .type = MMU, - .base = GP_MMU_ADDR, - .irq = 19+32, - .description = "Mali-400 MMU for GP", - .mmu_id = 1 - }, - { - .type = MMU, - .base = PP_MMU_ADDR, - .irq = 17+32, - .description = "Mali-400 MMU for PP 0", - .mmu_id = 2 - }, - { - .type = OS_MEMORY, - .description = "System Memory", - .size = 0x06000000, - .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE | _MALI_GP_READABLE | _MALI_GP_WRITEABLE - }, - { - .type = MEM_VALIDATION, - .description = "memory validation", - .base = 0x204e0000, - .size = 0x7B20000, - .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE | _MALI_GP_READABLE | _MALI_GP_WRITEABLE | - _MALI_MMU_READABLE | _MALI_MMU_WRITEABLE - }, -#else - { - .type = MEMORY, - .description = "Dedicated Memory", - .base = 0x2E000000, - .size = 0x02000000, - .flags = _MALI_CPU_WRITEABLE | _MALI_CPU_READABLE | _MALI_PP_READABLE | _MALI_PP_WRITEABLE | _MALI_GP_READABLE | _MALI_GP_WRITEABLE | - _MALI_MMU_READABLE | _MALI_MMU_WRITEABLE - }, -#endif - { - .type = MALI400L2, - .base = L2_ADDR, - .description = "Mali-400 L2 cache" - }, -}; - -#endif /* __ARCH_CONFIG_H__ */ diff --git a/drivers/media/video/samsung/ump/arch-orion-m400/config.h b/drivers/media/video/samsung/ump/arch-orion-m400/config.h index 117cc6e..688edc9 100644 --- a/drivers/media/video/samsung/ump/arch-orion-m400/config.h +++ b/drivers/media/video/samsung/ump/arch-orion-m400/config.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -11,12 +11,12 @@ #ifndef __ARCH_CONFIG_UMP_H__ #define __ARCH_CONFIG_UMP_H__ -#define ARCH_UMP_BACKEND_DEFAULT USING_MEMORY +#define ARCH_UMP_BACKEND_DEFAULT USING_MEMORY #if (USING_MEMORY == 0) /* Dedicated Memory */ -#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0x2C000000 +#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0x2C000000 #else -#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0 +#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0 #endif -#define ARCH_UMP_MEMORY_SIZE_DEFAULT UMP_MEM_SIZE*1024*1024 +#define ARCH_UMP_MEMORY_SIZE_DEFAULT UMP_MEM_SIZE*1024*1024 #endif /* __ARCH_CONFIG_UMP_H__ */ diff --git a/drivers/media/video/samsung/ump/arch-pb-virtex5/config.h b/drivers/media/video/samsung/ump/arch-pb-virtex5/config.h index 560eda9..38ae1ee 100644 --- a/drivers/media/video/samsung/ump/arch-pb-virtex5/config.h +++ b/drivers/media/video/samsung/ump/arch-pb-virtex5/config.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010-2011 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -12,7 +12,7 @@ #define __ARCH_CONFIG_H__ #define ARCH_UMP_BACKEND_DEFAULT 0 -#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0xC8000000 +#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0xCE000000 #define ARCH_UMP_MEMORY_SIZE_DEFAULT 32UL * 1024UL * 1024UL #endif /* __ARCH_CONFIG_H__ */ diff --git a/drivers/media/video/samsung/ump/arch-pegasus-m400/config.h b/drivers/media/video/samsung/ump/arch-pegasus-m400/config.h new file mode 100644 index 0000000..688edc9 --- /dev/null +++ b/drivers/media/video/samsung/ump/arch-pegasus-m400/config.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __ARCH_CONFIG_UMP_H__ +#define __ARCH_CONFIG_UMP_H__ + +#define ARCH_UMP_BACKEND_DEFAULT USING_MEMORY +#if (USING_MEMORY == 0) /* Dedicated Memory */ +#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0x2C000000 +#else +#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0 +#endif + +#define ARCH_UMP_MEMORY_SIZE_DEFAULT UMP_MEM_SIZE*1024*1024 +#endif /* __ARCH_CONFIG_UMP_H__ */ diff --git a/drivers/media/video/samsung/ump/arch-release/config.h b/drivers/media/video/samsung/ump/arch-release/config.h new file mode 100644 index 0000000..688edc9 --- /dev/null +++ b/drivers/media/video/samsung/ump/arch-release/config.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __ARCH_CONFIG_UMP_H__ +#define __ARCH_CONFIG_UMP_H__ + +#define ARCH_UMP_BACKEND_DEFAULT USING_MEMORY +#if (USING_MEMORY == 0) /* Dedicated Memory */ +#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0x2C000000 +#else +#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0 +#endif + +#define ARCH_UMP_MEMORY_SIZE_DEFAULT UMP_MEM_SIZE*1024*1024 +#endif /* __ARCH_CONFIG_UMP_H__ */ diff --git a/drivers/media/video/samsung/ump/arch/config.h b/drivers/media/video/samsung/ump/arch/config.h new file mode 100644 index 0000000..688edc9 --- /dev/null +++ b/drivers/media/video/samsung/ump/arch/config.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. + * + * A copy of the licence is included with the program, and can also be obtained from Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __ARCH_CONFIG_UMP_H__ +#define __ARCH_CONFIG_UMP_H__ + +#define ARCH_UMP_BACKEND_DEFAULT USING_MEMORY +#if (USING_MEMORY == 0) /* Dedicated Memory */ +#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0x2C000000 +#else +#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0 +#endif + +#define ARCH_UMP_MEMORY_SIZE_DEFAULT UMP_MEM_SIZE*1024*1024 +#endif /* __ARCH_CONFIG_UMP_H__ */ diff --git a/drivers/media/video/samsung/ump/common/ump_kernel_api.c b/drivers/media/video/samsung/ump/common/ump_kernel_api.c index ddc9ef7..83f0d30 100644 --- a/drivers/media/video/samsung/ump/common/ump_kernel_api.c +++ b/drivers/media/video/samsung/ump/common/ump_kernel_api.c @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -161,7 +161,7 @@ UMP_KERNEL_API_EXPORT void ump_dd_reference_add(ump_dd_handle memh) new_ref = _ump_osk_atomic_inc_and_read(&mem->ref_count); - DBG_MSG(4, ("Memory reference incremented. ID: %u, new value: %d\n", mem->secure_id, new_ref)); + DBG_MSG(5, ("Memory reference incremented. ID: %u, new value: %d\n", mem->secure_id, new_ref)); } @@ -181,7 +181,7 @@ UMP_KERNEL_API_EXPORT void ump_dd_reference_release(ump_dd_handle memh) new_ref = _ump_osk_atomic_dec_and_read(&mem->ref_count); - DBG_MSG(4, ("Memory reference decremented. ID: %u, new value: %d\n", mem->secure_id, new_ref)); + DBG_MSG(5, ("Memory reference decremented. ID: %u, new value: %d\n", mem->secure_id, new_ref)); if (0 == new_ref) { @@ -277,7 +277,7 @@ _mali_osk_errcode_t _ump_ukk_release( _ump_uk_release_s *release_info ) } _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); - DBG_MSG_IF(1, _MALI_OSK_ERR_OK != ret, ("UMP memory with ID %u does not belong to this session.\n", secure_id)); + DBG_MSG_IF(1, _MALI_OSK_ERR_OK != ret, ("UMP memory with ID %u does not belong to this session.\n", secure_id)); DBG_MSG(4, ("_ump_ukk_release() returning 0x%x\n", ret)); return ret; @@ -313,15 +313,22 @@ _mali_osk_errcode_t _ump_ukk_size_get( _ump_uk_size_get_s *user_interaction ) void _ump_ukk_msync( _ump_uk_msync_s *args ) { ump_dd_mem * mem = NULL; + void *virtual = NULL; + u32 size = 0; + u32 offset = 0; + _mali_osk_lock_wait(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW); ump_descriptor_mapping_get(device.secure_id_map, (int)args->secure_id, (void**)&mem); - _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW); - if (NULL==mem) + if (NULL == mem) { + _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW); DBG_MSG(1, ("Failed to look up mapping in _ump_ukk_msync(). ID: %u\n", (ump_secure_id)args->secure_id)); return; } + /* Ensure the memory doesn't dissapear when we are flushing it. */ + ump_dd_reference_add(mem); + _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW); /* Returns the cache settings back to Userspace */ args->is_cached=mem->is_cached; @@ -330,17 +337,215 @@ void _ump_ukk_msync( _ump_uk_msync_s *args ) if ( _UMP_UK_MSYNC_READOUT_CACHE_ENABLED==args->op ) { DBG_MSG(3, ("_ump_ukk_msync READOUT ID: %u Enabled: %d\n", (ump_secure_id)args->secure_id, mem->is_cached)); - return; + goto msync_release_and_return; } /* Nothing to do if the memory is not caches */ if ( 0==mem->is_cached ) { DBG_MSG(3, ("_ump_ukk_msync IGNORING ID: %u Enabled: %d OP: %d\n", (ump_secure_id)args->secure_id, mem->is_cached, args->op)); - return ; + goto msync_release_and_return; + } + DBG_MSG(3, ("UMP[%02u] _ump_ukk_msync Flush OP: %d Address: 0x%08x Mapping: 0x%08x\n", + (ump_secure_id)args->secure_id, args->op, args->address, args->mapping)); + + if ( args->address ) + { + virtual = (void *)((u32)args->address); + offset = (u32)((args->address) - (args->mapping)); + } else { + /* Flush entire mapping when no address is specified. */ + virtual = args->mapping; + } + if ( args->size ) + { + size = args->size; + } else { + /* Flush entire mapping when no size is specified. */ + size = mem->size_bytes - offset; + } + + if ( (offset + size) > mem->size_bytes ) + { + DBG_MSG(1, ("Trying to flush more than the entire UMP allocation: offset: %u + size: %u > %u\n", offset, size, mem->size_bytes)); + goto msync_release_and_return; } - DBG_MSG(3, ("_ump_ukk_msync FLUSHING ID: %u Enabled: %d OP: %d\n", (ump_secure_id)args->secure_id, mem->is_cached, args->op)); /* The actual cache flush - Implemented for each OS*/ - _ump_osk_msync( mem , args->op, (u32)args->mapping, (u32)args->address, args->size); + _ump_osk_msync( mem, virtual, offset, size, args->op, NULL); + +msync_release_and_return: + ump_dd_reference_release(mem); + return; +} + +void _ump_ukk_cache_operations_control(_ump_uk_cache_operations_control_s* args) +{ + ump_session_data * session_data; + ump_uk_cache_op_control op; + + DEBUG_ASSERT_POINTER( args ); + DEBUG_ASSERT_POINTER( args->ctx ); + + op = args->op; + session_data = (ump_session_data *)args->ctx; + + _mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW); + if ( op== _UMP_UK_CACHE_OP_START ) + { + session_data->cache_operations_ongoing++; + DBG_MSG(4, ("Cache ops start\n" )); + if ( session_data->cache_operations_ongoing != 1 ) + { + DBG_MSG(2, ("UMP: Number of simultanious cache control ops: %d\n", session_data->cache_operations_ongoing) ); + } + } + else if ( op== _UMP_UK_CACHE_OP_FINISH ) + { + DBG_MSG(4, ("Cache ops finish\n")); + session_data->cache_operations_ongoing--; + #if 0 + if ( session_data->has_pending_level1_cache_flush) + { + /* This function will set has_pending_level1_cache_flush=0 */ + _ump_osk_msync( NULL, NULL, 0, 0, _UMP_UK_MSYNC_FLUSH_L1, session_data); + } + #endif + + /* to be on the safe side: always flush l1 cache when cache operations are done */ + _ump_osk_msync( NULL, NULL, 0, 0, _UMP_UK_MSYNC_FLUSH_L1, session_data); + DBG_MSG(4, ("Cache ops finish end\n" )); + } + else + { + DBG_MSG(1, ("Illegal call to %s at line %d\n", __FUNCTION__, __LINE__)); + } + _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); + +} + +void _ump_ukk_switch_hw_usage(_ump_uk_switch_hw_usage_s *args ) +{ + ump_dd_mem * mem = NULL; + ump_uk_user old_user; + ump_uk_msync_op cache_op = _UMP_UK_MSYNC_CLEAN_AND_INVALIDATE; + ump_session_data *session_data; + + DEBUG_ASSERT_POINTER( args ); + DEBUG_ASSERT_POINTER( args->ctx ); + + session_data = (ump_session_data *)args->ctx; + + _mali_osk_lock_wait(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW); + ump_descriptor_mapping_get(device.secure_id_map, (int)args->secure_id, (void**)&mem); + + if (NULL == mem) + { + _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW); + DBG_MSG(1, ("Failed to look up mapping in _ump_ukk_switch_hw_usage(). ID: %u\n", (ump_secure_id)args->secure_id)); + return; + } + + old_user = mem->hw_device; + mem->hw_device = args->new_user; + + DBG_MSG(3, ("UMP[%02u] Switch usage Start New: %s Prev: %s.\n", (ump_secure_id)args->secure_id, args->new_user?"MALI":"CPU",old_user?"MALI":"CPU")); + + if ( ! mem->is_cached ) + { + _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW); + DBG_MSG(3, ("UMP[%02u] Changing owner of uncached memory. Cache flushing not needed.\n", (ump_secure_id)args->secure_id)); + return; + } + + if ( old_user == args->new_user) + { + _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW); + DBG_MSG(4, ("UMP[%02u] Setting the new_user equal to previous for. Cache flushing not needed.\n", (ump_secure_id)args->secure_id)); + return; + } + if ( + /* Previous AND new is both different from CPU */ + (old_user != _UMP_UK_USED_BY_CPU) && (args->new_user != _UMP_UK_USED_BY_CPU ) + ) + { + _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW); + DBG_MSG(4, ("UMP[%02u] Previous and new user is not CPU. Cache flushing not needed.\n", (ump_secure_id)args->secure_id)); + return; + } + + if ( (old_user != _UMP_UK_USED_BY_CPU ) && (args->new_user==_UMP_UK_USED_BY_CPU) ) + { + cache_op =_UMP_UK_MSYNC_INVALIDATE; + DBG_MSG(4, ("UMP[%02u] Cache invalidation needed\n", (ump_secure_id)args->secure_id)); +#ifdef UMP_SKIP_INVALIDATION +#error + _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW); + DBG_MSG(4, ("UMP[%02u] Performing Cache invalidation SKIPPED\n", (ump_secure_id)args->secure_id)); + return; +#endif + } + /* Ensure the memory doesn't dissapear when we are flushing it. */ + ump_dd_reference_add(mem); + _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW); + + /* Take lock to protect: session->cache_operations_ongoing and session->has_pending_level1_cache_flush */ + _mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW); + /* Actual cache flush */ + _ump_osk_msync( mem, NULL, 0, mem->size_bytes, cache_op, session_data); + _mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW); + + ump_dd_reference_release(mem); + DBG_MSG(4, ("UMP[%02u] Switch usage Finish\n", (ump_secure_id)args->secure_id)); + return; +} + +void _ump_ukk_lock(_ump_uk_lock_s *args ) +{ + ump_dd_mem * mem = NULL; + + _mali_osk_lock_wait(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW); + ump_descriptor_mapping_get(device.secure_id_map, (int)args->secure_id, (void**)&mem); + + if (NULL == mem) + { + _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW); + DBG_MSG(1, ("UMP[%02u] Failed to look up mapping in _ump_ukk_lock(). ID: %u\n", (ump_secure_id)args->secure_id)); + return; + } + ump_dd_reference_add(mem); + _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW); + + DBG_MSG(1, ("UMP[%02u] Lock. New lock flag: %d. Old Lock flag:\n", (u32)args->secure_id, (u32)args->lock_usage, (u32) mem->lock_usage )); + + mem->lock_usage = (ump_lock_usage) args->lock_usage; + + /** TODO: TAKE LOCK HERE */ + + ump_dd_reference_release(mem); +} + +void _ump_ukk_unlock(_ump_uk_unlock_s *args ) +{ + ump_dd_mem * mem = NULL; + + _mali_osk_lock_wait(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW); + ump_descriptor_mapping_get(device.secure_id_map, (int)args->secure_id, (void**)&mem); + + if (NULL == mem) + { + _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW); + DBG_MSG(1, ("Failed to look up mapping in _ump_ukk_unlock(). ID: %u\n", (ump_secure_id)args->secure_id)); + return; + } + ump_dd_reference_add(mem); + _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW); + + DBG_MSG(1, ("UMP[%02u] Unlocking. Old Lock flag:\n", (u32)args->secure_id, (u32) mem->lock_usage )); + + mem->lock_usage = (ump_lock_usage) UMP_NOT_LOCKED; + + /** TODO: RELEASE LOCK HERE */ + + ump_dd_reference_release(mem); } diff --git a/drivers/media/video/samsung/ump/common/ump_kernel_common.c b/drivers/media/video/samsung/ump/common/ump_kernel_common.c index e5ff198..1fa7c8a 100644 --- a/drivers/media/video/samsung/ump/common/ump_kernel_common.c +++ b/drivers/media/video/samsung/ump/common/ump_kernel_common.c @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -147,6 +147,9 @@ _mali_osk_errcode_t _ump_ukk_open( void** context ) *context = (void*)session_data; + session_data->cache_operations_ongoing = 0 ; + session_data->has_pending_level1_cache_flush = 0; + DBG_MSG(2, ("New session opened\n")); return _MALI_OSK_ERR_OK; @@ -225,19 +228,17 @@ _mali_osk_errcode_t _ump_ukk_map_mem( _ump_uk_map_mem_s *args ) int map_id; session_data = (ump_session_data *)args->ctx; - if (NULL == session_data) + if(NULL == session_data) { MSG_ERR(("Session data is NULL in _ump_ukk_map_mem()\n")); return _MALI_OSK_ERR_INVALID_ARGS; } - /* SEC kernel stability 2012-02-17 */ if (NULL == session_data->cookies_map) { MSG_ERR(("session_data->cookies_map is NULL in _ump_ukk_map_mem()\n")); return _MALI_OSK_ERR_INVALID_ARGS; } - descriptor = (ump_memory_allocation*) _mali_osk_calloc( 1, sizeof(ump_memory_allocation)); if (NULL == descriptor) { @@ -370,14 +371,12 @@ void _ump_ukk_unmap_mem( _ump_uk_unmap_mem_s *args ) MSG_ERR(("Session data is NULL in _ump_ukk_map_mem()\n")); return; } - /* SEC kernel stability 2012-02-17 */ if (NULL == session_data->cookies_map) { MSG_ERR(("session_data->cookies_map is NULL in _ump_ukk_map_mem()\n")); return; } - if (0 != ump_descriptor_mapping_get( session_data->cookies_map, (int)args->cookie, (void**)&descriptor) ) { MSG_ERR(("_ump_ukk_map_mem: cookie 0x%X not found for this session\n", args->cookie )); diff --git a/drivers/media/video/samsung/ump/common/ump_kernel_common.h b/drivers/media/video/samsung/ump/common/ump_kernel_common.h index c8b5541..03d213d 100644 --- a/drivers/media/video/samsung/ump/common/ump_kernel_common.h +++ b/drivers/media/video/samsung/ump/common/ump_kernel_common.h @@ -1,15 +1,15 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __UMP_KERNEL_H__ -#define __UMP_KERNEL_H__ +#ifndef __UMP_KERNEL_COMMON_H__ +#define __UMP_KERNEL_COMMON_H__ #include "ump_kernel_types.h" #include "ump_kernel_interface.h" @@ -77,6 +77,8 @@ typedef struct ump_session_data int api_version; _mali_osk_lock_t * lock; ump_descriptor_mapping * cookies_map; /**< Secure mapping of cookies from _ump_ukk_map_mem() */ + int cache_operations_ongoing; + int has_pending_level1_cache_flush; } ump_session_data; @@ -123,4 +125,4 @@ int map_errcode( _mali_osk_errcode_t err ); #define __user #endif -#endif /* __UMP_KERNEL_H__ */ +#endif /* __UMP_KERNEL_COMMON_H__ */ diff --git a/drivers/media/video/samsung/ump/common/ump_kernel_descriptor_mapping.c b/drivers/media/video/samsung/ump/common/ump_kernel_descriptor_mapping.c index 5174839..cc7b8be 100644 --- a/drivers/media/video/samsung/ump/common/ump_kernel_descriptor_mapping.c +++ b/drivers/media/video/samsung/ump/common/ump_kernel_descriptor_mapping.c @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -65,9 +65,9 @@ void ump_descriptor_mapping_destroy(ump_descriptor_mapping * map) int ump_descriptor_mapping_allocate_mapping(ump_descriptor_mapping * map, void * target) { - int descriptor = -1;/*-EFAULT;*/ - _mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RW); - descriptor = _mali_osk_find_first_zero_bit(map->table->usage, map->current_nr_mappings); + int descriptor = -1;/*-EFAULT;*/ + _mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RW); + descriptor = _mali_osk_find_first_zero_bit(map->table->usage, map->current_nr_mappings); if (descriptor == map->current_nr_mappings) { int nr_mappings_new; @@ -89,8 +89,8 @@ int ump_descriptor_mapping_allocate_mapping(ump_descriptor_mapping * map, void * goto unlock_and_exit; } - _mali_osk_memcpy(new_table->usage, old_table->usage, (sizeof(unsigned long)*map->current_nr_mappings) / BITS_PER_LONG); - _mali_osk_memcpy(new_table->mappings, old_table->mappings, map->current_nr_mappings * sizeof(void*)); + _mali_osk_memcpy(new_table->usage, old_table->usage, (sizeof(unsigned long)*map->current_nr_mappings) / BITS_PER_LONG); + _mali_osk_memcpy(new_table->mappings, old_table->mappings, map->current_nr_mappings * sizeof(void*)); map->table = new_table; map->current_nr_mappings = nr_mappings_new; descriptor_table_free(old_table); @@ -107,10 +107,10 @@ unlock_and_exit: int ump_descriptor_mapping_get(ump_descriptor_mapping * map, int descriptor, void** target) { - int result = -1;/*-EFAULT;*/ - DEBUG_ASSERT(map); - _mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RO); - if ( (descriptor >= 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage) ) + int result = -1;/*-EFAULT;*/ + DEBUG_ASSERT(map); + _mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RO); + if ( (descriptor >= 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage) ) { *target = map->table->mappings[descriptor]; result = 0; @@ -122,9 +122,9 @@ int ump_descriptor_mapping_get(ump_descriptor_mapping * map, int descriptor, voi int ump_descriptor_mapping_set(ump_descriptor_mapping * map, int descriptor, void * target) { - int result = -1;/*-EFAULT;*/ - _mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RO); - if ( (descriptor >= 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage) ) + int result = -1;/*-EFAULT;*/ + _mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RO); + if ( (descriptor >= 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage) ) { map->table->mappings[descriptor] = target; result = 0; @@ -135,8 +135,8 @@ int ump_descriptor_mapping_set(ump_descriptor_mapping * map, int descriptor, voi void ump_descriptor_mapping_free(ump_descriptor_mapping * map, int descriptor) { - _mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RW); - if ( (descriptor >= 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage) ) + _mali_osk_lock_wait(map->lock, _MALI_OSK_LOCKMODE_RW); + if ( (descriptor >= 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage) ) { map->table->mappings[descriptor] = NULL; _mali_osk_clear_nonatomic_bit(descriptor, map->table->usage); @@ -163,4 +163,3 @@ static void descriptor_table_free(ump_descriptor_table * table) { _mali_osk_free(table); } - diff --git a/drivers/media/video/samsung/ump/common/ump_kernel_descriptor_mapping.h b/drivers/media/video/samsung/ump/common/ump_kernel_descriptor_mapping.h index 319cc3b..881d3d8 100644 --- a/drivers/media/video/samsung/ump/common/ump_kernel_descriptor_mapping.h +++ b/drivers/media/video/samsung/ump/common/ump_kernel_descriptor_mapping.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff --git a/drivers/media/video/samsung/ump/common/ump_kernel_memory_backend.h b/drivers/media/video/samsung/ump/common/ump_kernel_memory_backend.h index d329bb5..73915ee 100644 --- a/drivers/media/video/samsung/ump/common/ump_kernel_memory_backend.h +++ b/drivers/media/video/samsung/ump/common/ump_kernel_memory_backend.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -49,4 +49,3 @@ ump_memory_backend * ump_memory_backend_create ( void ); void ump_memory_backend_destroy( void ); #endif /*__UMP_KERNEL_MEMORY_BACKEND_H__ */ - diff --git a/drivers/media/video/samsung/ump/common/ump_kernel_ref_drv.c b/drivers/media/video/samsung/ump/common/ump_kernel_ref_drv.c index 4dcbe21..a5ccfeb 100644 --- a/drivers/media/video/samsung/ump/common/ump_kernel_ref_drv.c +++ b/drivers/media/video/samsung/ump/common/ump_kernel_ref_drv.c @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -95,6 +95,8 @@ UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_phys_blocks(ump_dd mem->release_func = phys_blocks_release; /* For now UMP handles created by ump_dd_handle_create_from_phys_blocks() is forced to be Uncached */ mem->is_cached = 0; + mem->hw_device = _UMP_UK_USED_BY_CPU; + mem->lock_usage = UMP_NOT_LOCKED; _mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW); DBG_MSG(3, ("UMP memory created. ID: %u, size: %lu\n", mem->secure_id, mem->size_bytes)); @@ -165,6 +167,7 @@ _mali_osk_errcode_t _ump_ukk_allocate( _ump_uk_allocate_s *user_interaction ) } new_allocation->size_bytes = UMP_SIZE_ALIGN(user_interaction->size); /* Page align the size */ + new_allocation->lock_usage = UMP_NOT_LOCKED; /* Now, ask the active memory backend to do the actual memory allocation */ if (!device.backend->allocate( device.backend->ctx, new_allocation ) ) @@ -176,7 +179,7 @@ _mali_osk_errcode_t _ump_ukk_allocate( _ump_uk_allocate_s *user_interaction ) _mali_osk_free(session_memory_element); return _MALI_OSK_ERR_INVALID_FUNC; } - + new_allocation->hw_device = _UMP_UK_USED_BY_CPU; new_allocation->ctx = device.backend->ctx; new_allocation->release_func = device.backend->release; @@ -195,6 +198,7 @@ _mali_osk_errcode_t _ump_ukk_allocate( _ump_uk_allocate_s *user_interaction ) return _MALI_OSK_ERR_OK; } + UMP_KERNEL_API_EXPORT ump_dd_status_code ump_dd_meminfo_set(ump_dd_handle memh, void* args) { ump_dd_mem * mem; @@ -255,4 +259,3 @@ UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_get_from_vaddr(unsigned long v return (ump_dd_handle)mem; } - diff --git a/drivers/media/video/samsung/ump/common/ump_kernel_types.h b/drivers/media/video/samsung/ump/common/ump_kernel_types.h index ca03dec..fdacd86 100644 --- a/drivers/media/video/samsung/ump/common/ump_kernel_types.h +++ b/drivers/media/video/samsung/ump/common/ump_kernel_types.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -14,6 +14,22 @@ #include "ump_kernel_interface.h" #include "mali_osk.h" + +typedef enum +{ + UMP_USED_BY_CPU = 0, + UMP_USED_BY_MALI = 1, + UMP_USED_BY_UNKNOWN_DEVICE= 100, +} ump_hw_usage; + +typedef enum +{ + UMP_NOT_LOCKED = 0, + UMP_READ = 1, + UMP_READ_WRITE = 3, +} ump_lock_usage; + + /* * This struct is what is "behind" a ump_dd_handle */ @@ -28,6 +44,8 @@ typedef struct ump_dd_mem void * ctx; void * backend_info; int is_cached; + ump_hw_usage hw_device; + ump_lock_usage lock_usage; } ump_dd_mem; diff --git a/drivers/media/video/samsung/ump/common/ump_osk.h b/drivers/media/video/samsung/ump/common/ump_osk.h index bd9254b..dabdc7f 100644 --- a/drivers/media/video/samsung/ump/common/ump_osk.h +++ b/drivers/media/video/samsung/ump/common/ump_osk.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -18,7 +18,8 @@ #include <mali_osk.h> #include <ump_kernel_memory_backend.h> -#include <ump_uk_types.h> +#include "ump_uk_types.h" +#include "ump_kernel_common.h" #ifdef __cplusplus extern "C" @@ -39,7 +40,7 @@ _mali_osk_errcode_t _ump_osk_mem_mapregion_map( ump_memory_allocation * descript void _ump_osk_mem_mapregion_term( ump_memory_allocation * descriptor ); -void _ump_osk_msync( ump_dd_mem * mem, ump_uk_msync_op op, u32 start, u32 address, u32 size); +void _ump_osk_msync( ump_dd_mem * mem, void * virt, u32 offset, u32 size, ump_uk_msync_op op, ump_session_data * session_data ); void _ump_osk_mem_mapregion_get( ump_dd_mem ** mem, unsigned long vaddr); diff --git a/drivers/media/video/samsung/ump/common/ump_uk_types.h b/drivers/media/video/samsung/ump/common/ump_uk_types.h index 2bac454..4fd1ef7 100644 --- a/drivers/media/video/samsung/ump/common/ump_uk_types.h +++ b/drivers/media/video/samsung/ump/common/ump_uk_types.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. + * Copyright (C) 2010, 2012 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. @@ -45,12 +45,11 @@ typedef enum _UMP_IOC_MAP_MEM, /* not used in Linux */ _UMP_IOC_UNMAP_MEM, /* not used in Linux */ _UMP_IOC_MSYNC, -#ifdef CONFIG_ION_EXYNOS + _UMP_IOC_CACHE_OPERATIONS_CONTROL, + _UMP_IOC_SWITCH_HW_USAGE, + _UMP_IOC_LOCK, + _UMP_IOC_UNLOCK, _UMP_IOC_ION_IMPORT, -#endif -#ifdef CONFIG_DMA_SHARED_BUFFER - _UMP_IOC_DMABUF_IMPORT, -#endif }_ump_uk_functions; typedef enum @@ -64,9 +63,30 @@ typedef enum { _UMP_UK_MSYNC_CLEAN = 0, _UMP_UK_MSYNC_CLEAN_AND_INVALIDATE = 1, + _UMP_UK_MSYNC_INVALIDATE = 2, + _UMP_UK_MSYNC_FLUSH_L1 = 3, _UMP_UK_MSYNC_READOUT_CACHE_ENABLED = 128, } ump_uk_msync_op; +typedef enum +{ + _UMP_UK_CACHE_OP_START = 0, + _UMP_UK_CACHE_OP_FINISH = 1, +} ump_uk_cache_op_control; + +typedef enum +{ + _UMP_UK_READ = 1, + _UMP_UK_READ_WRITE = 3, +} ump_uk_lock_usage; + +typedef enum +{ + _UMP_UK_USED_BY_CPU = 0, + _UMP_UK_USED_BY_MALI = 1, + _UMP_UK_USED_BY_UNKNOWN_DEVICE= 100, +} ump_uk_user; + /** * Get API version ([in,out] u32 api_version, [out] u32 compatible) */ @@ -88,25 +108,14 @@ typedef struct _ump_uk_allocate_s ump_uk_alloc_constraints constraints; /**< Only input to Devicedriver */ } _ump_uk_allocate_s; -#ifdef CONFIG_ION_EXYNOS typedef struct _ump_uk_ion_import_s { void *ctx; /**< [in,out] user-kernel context (trashed on output) */ - int ion_fd; + int ion_fd; /**< ion_fd */ u32 secure_id; /**< Return value from DD to Userdriver */ u32 size; /**< Input and output. Requested size; input. Returned size; output */ ump_uk_alloc_constraints constraints; /**< Only input to Devicedriver */ } _ump_uk_ion_import_s; -#endif - -#ifdef CONFIG_DMA_SHARED_BUFFER -struct ump_uk_dmabuf { - void *ctx; - int fd; - size_t size; - uint32_t ump_handle; -}; -#endif /** * SIZE_GET ([in] u32 secure_id, [out]size ) @@ -156,10 +165,38 @@ typedef struct _ump_uk_msync_s u32 size; /**< [in] size to flush */ ump_uk_msync_op op; /**< [in] flush operation */ u32 cookie; /**< [in] cookie stored with reference to the kernel mapping internals */ - u32 secure_id; /**< [in] cookie stored with reference to the kernel mapping internals */ + u32 secure_id; /**< [in] secure_id that identifies the ump buffer */ u32 is_cached; /**< [out] caching of CPU mappings */ } _ump_uk_msync_s; +typedef struct _ump_uk_cache_operations_control_s +{ + void *ctx; /**< [in,out] user-kernel context (trashed on output) */ + ump_uk_cache_op_control op; /**< [in] cache operations start/stop */ +} _ump_uk_cache_operations_control_s; + + +typedef struct _ump_uk_switch_hw_usage_s +{ + void *ctx; /**< [in,out] user-kernel context (trashed on output) */ + u32 secure_id; /**< [in] secure_id that identifies the ump buffer */ + ump_uk_user new_user; /**< [in] cookie stored with reference to the kernel mapping internals */ + +} _ump_uk_switch_hw_usage_s; + +typedef struct _ump_uk_lock_s +{ + void *ctx; /**< [in,out] user-kernel context (trashed on output) */ + u32 secure_id; /**< [in] secure_id that identifies the ump buffer */ + ump_uk_lock_usage lock_usage; +} _ump_uk_lock_s; + +typedef struct _ump_uk_unlock_s +{ + void *ctx; /**< [in,out] user-kernel context (trashed on output) */ + u32 secure_id; /**< [in] secure_id that identifies the ump buffer */ +} _ump_uk_unlock_s; + #ifdef __cplusplus } #endif diff --git a/drivers/media/video/samsung/ump/common/ump_ukk.h b/drivers/media/video/samsung/ump/common/ump_ukk.h index db48cd6..4e6bb86 100644 --- a/drivers/media/video/samsung/ump/common/ump_ukk.h +++ b/drivers/media/video/samsung/ump/common/ump_ukk.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -44,6 +44,14 @@ void _ump_ukk_unmap_mem( _ump_uk_unmap_mem_s *args ); void _ump_ukk_msync( _ump_uk_msync_s *args ); +void _ump_ukk_cache_operations_control(_ump_uk_cache_operations_control_s* args); + +void _ump_ukk_switch_hw_usage(_ump_uk_switch_hw_usage_s *args ); + +void _ump_ukk_lock(_ump_uk_lock_s *args ); + +void _ump_ukk_unlock(_ump_uk_unlock_s *args ); + u32 _ump_ukk_report_memory_usage( void ); #ifdef __cplusplus diff --git a/drivers/media/video/samsung/ump/include/ump_kernel_interface.h b/drivers/media/video/samsung/ump/include/ump_kernel_interface.h index ba81a07..f84d237 100644 --- a/drivers/media/video/samsung/ump/include/ump_kernel_interface.h +++ b/drivers/media/video/samsung/ump/include/ump_kernel_interface.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010, 2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff --git a/drivers/media/video/samsung/ump/include/ump_kernel_interface_ref_drv.h b/drivers/media/video/samsung/ump/include/ump_kernel_interface_ref_drv.h index 3efe165..36c5c9d 100644 --- a/drivers/media/video/samsung/ump/include/ump_kernel_interface_ref_drv.h +++ b/drivers/media/video/samsung/ump/include/ump_kernel_interface_ref_drv.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010, 2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff --git a/drivers/media/video/samsung/ump/include/ump_kernel_interface_vcm.h b/drivers/media/video/samsung/ump/include/ump_kernel_interface_vcm.h index a784241..5ff4155 100644 --- a/drivers/media/video/samsung/ump/include/ump_kernel_interface_vcm.h +++ b/drivers/media/video/samsung/ump/include/ump_kernel_interface_vcm.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff --git a/drivers/media/video/samsung/ump/include/ump_kernel_platform.h b/drivers/media/video/samsung/ump/include/ump_kernel_platform.h index 1b5af40..339e967 100644 --- a/drivers/media/video/samsung/ump/include/ump_kernel_platform.h +++ b/drivers/media/video/samsung/ump/include/ump_kernel_platform.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010, 2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff --git a/drivers/media/video/samsung/ump/linux/license/gpl/ump_kernel_license.h b/drivers/media/video/samsung/ump/linux/license/gpl/ump_kernel_license.h index 17b930d..50a021c 100644 --- a/drivers/media/video/samsung/ump/linux/license/gpl/ump_kernel_license.h +++ b/drivers/media/video/samsung/ump/linux/license/gpl/ump_kernel_license.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff --git a/drivers/media/video/samsung/ump/linux/ump_ioctl.h b/drivers/media/video/samsung/ump/linux/ump_ioctl.h index 50ef9df..1d49b4d 100644 --- a/drivers/media/video/samsung/ump/linux/ump_ioctl.h +++ b/drivers/media/video/samsung/ump/linux/ump_ioctl.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -19,7 +19,7 @@ extern "C" #include <linux/types.h> #include <linux/ioctl.h> -#include "../common/ump_uk_types.h" +#include <ump_uk_types.h> #ifndef __user #define __user @@ -39,16 +39,20 @@ extern "C" #define UMP_IOC_ALLOCATE _IOWR(UMP_IOCTL_NR, _UMP_IOC_ALLOCATE, _ump_uk_allocate_s) #define UMP_IOC_RELEASE _IOR(UMP_IOCTL_NR, _UMP_IOC_RELEASE, _ump_uk_release_s) #define UMP_IOC_SIZE_GET _IOWR(UMP_IOCTL_NR, _UMP_IOC_SIZE_GET, _ump_uk_size_get_s) -#define UMP_IOC_MSYNC _IOW(UMP_IOCTL_NR, _UMP_IOC_MSYNC, _ump_uk_size_get_s) +#define UMP_IOC_MSYNC _IOW(UMP_IOCTL_NR, _UMP_IOC_MSYNC, _ump_uk_msync_s) #ifdef CONFIG_ION_EXYNOS #define UMP_IOC_ION_IMPORT _IOW(UMP_IOCTL_NR, _UMP_IOC_ION_IMPORT, _ump_uk_ion_import_s) #endif - #ifdef CONFIG_DMA_SHARED_BUFFER #define UMP_IOC_DMABUF_IMPORT _IOW(UMP_IOCTL_NR, _UMP_IOC_DMABUF_IMPORT,\ struct ump_uk_dmabuf) #endif +#define UMP_IOC_CACHE_OPERATIONS_CONTROL _IOW(UMP_IOCTL_NR, _UMP_IOC_CACHE_OPERATIONS_CONTROL, _ump_uk_cache_operations_control_s) +#define UMP_IOC_SWITCH_HW_USAGE _IOW(UMP_IOCTL_NR, _UMP_IOC_SWITCH_HW_USAGE, _ump_uk_switch_hw_usage_s) +#define UMP_IOC_LOCK _IOW(UMP_IOCTL_NR, _UMP_IOC_LOCK, _ump_uk_lock_s) +#define UMP_IOC_UNLOCK _IOW(UMP_IOCTL_NR, _UMP_IOC_UNLOCK, _ump_uk_unlock_s) + #ifdef __cplusplus } #endif diff --git a/drivers/media/video/samsung/ump/linux/ump_kernel_linux.c b/drivers/media/video/samsung/ump/linux/ump_kernel_linux.c index 69f55c5..58cef54 100644 --- a/drivers/media/video/samsung/ump/linux/ump_kernel_linux.c +++ b/drivers/media/video/samsung/ump/linux/ump_kernel_linux.c @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -42,7 +42,7 @@ struct ion_client *ion_client_ump = NULL; #endif /* Module parameter to control log level */ -int ump_debug_level = 3; +int ump_debug_level = 2; module_param(ump_debug_level, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); /* rw-rw-r-- */ MODULE_PARM_DESC(ump_debug_level, "Higher number, more dmesg output"); @@ -55,7 +55,9 @@ MODULE_PARM_DESC(ump_major, "Device major number"); static char ump_dev_name[] = "ump"; /* should be const, but the functions we call requires non-cost */ +#if UMP_LICENSE_IS_GPL static struct dentry *ump_debugfs_dir = NULL; +#endif /* * The data which we attached to each virtual memory mapping request we get. @@ -90,7 +92,7 @@ static int ump_file_ioctl(struct inode *inode, struct file *filp, unsigned int c #endif static int ump_file_mmap(struct file * filp, struct vm_area_struct * vma); -#ifdef CONFIG_VIDEO_MALI400MP_R2P3 +#if defined(CONFIG_VIDEO_MALI400MP) || defined(CONFIG_VIDEO_MALI400MP_R3P0) || defined(CONFIG_VIDEO_MALI400MP_R2P3) extern int map_errcode( _mali_osk_errcode_t err ); #endif @@ -171,6 +173,7 @@ int ump_kernel_device_initialize(void) { int err; dev_t dev = 0; +#if UMP_LICENSE_IS_GPL ump_debugfs_dir = debugfs_create_dir(ump_dev_name, NULL); if (ERR_PTR(-ENODEV) == ump_debugfs_dir) { @@ -180,6 +183,7 @@ int ump_kernel_device_initialize(void) { debugfs_create_file("memory_usage", 0400, ump_debugfs_dir, NULL, &ump_memory_usage_fops); } +#endif if (0 == ump_major) { @@ -257,8 +261,10 @@ void ump_kernel_device_terminate(void) /* free major */ unregister_chrdev_region(dev, 1); +#if UMP_LICENSE_IS_GPL if(ump_debugfs_dir) debugfs_remove_recursive(ump_debugfs_dir); +#endif } /* @@ -369,6 +375,22 @@ static int ump_file_ioctl(struct inode *inode, struct file *filp, unsigned int c err = ump_msync_wrapper((u32 __user *)argument, session_data); break; + case UMP_IOC_CACHE_OPERATIONS_CONTROL: + err = ump_cache_operations_control_wrapper((u32 __user *)argument, session_data); + break; + + case UMP_IOC_SWITCH_HW_USAGE: + err = ump_switch_hw_usage_wrapper((u32 __user *)argument, session_data); + break; + + case UMP_IOC_LOCK: + err = ump_lock_wrapper((u32 __user *)argument, session_data); + break; + + case UMP_IOC_UNLOCK: + err = ump_unlock_wrapper((u32 __user *)argument, session_data); + break; + default: DBG_MSG(1, ("No handler for IOCTL. cmd: 0x%08x, arg: 0x%08lx\n", cmd, arg)); err = -EFAULT; @@ -377,7 +399,6 @@ static int ump_file_ioctl(struct inode *inode, struct file *filp, unsigned int c return err; } - #ifndef CONFIG_VIDEO_MALI400MP_R2P3 #ifndef CONFIG_VIDEO_MALI400MP #ifndef CONFIG_VIDEO_MALI400MP_R3P0 @@ -399,7 +420,6 @@ int map_errcode( _mali_osk_errcode_t err ) #endif #endif #endif - /* * Handle from OS to map specified virtual memory to specified UMP memory. */ @@ -431,6 +451,8 @@ static int ump_file_mmap(struct file * filp, struct vm_area_struct * vma) vma->vm_flags = vma->vm_flags | VM_SHARED | VM_MAYSHARE ; DBG_MSG(3, ("UMP Map function: Forcing the CPU to use cache\n")); } + /* By setting this flag, during a process fork; the child process will not have the parent UMP mappings */ + vma->vm_flags |= VM_DONTCOPY; DBG_MSG(4, ("UMP vma->flags: %x\n", vma->vm_flags )); diff --git a/drivers/media/video/samsung/ump/linux/ump_kernel_linux.h b/drivers/media/video/samsung/ump/linux/ump_kernel_linux.h index b93c814e..ef68040 100644 --- a/drivers/media/video/samsung/ump/linux/ump_kernel_linux.h +++ b/drivers/media/video/samsung/ump/linux/ump_kernel_linux.h @@ -1,18 +1,18 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef __UMP_KERNEL_H__ -#define __UMP_KERNEL_H__ +#ifndef __UMP_KERNEL_LINUX_H__ +#define __UMP_KERNEL_LINUX_H__ int ump_kernel_device_initialize(void); void ump_kernel_device_terminate(void); -#endif /* __UMP_KERNEL_H__ */ +#endif /* __UMP_KERNEL_LINUX_H__ */ diff --git a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_dedicated.c b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_dedicated.c index 4e6c9b5..82c16cc 100644 --- a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_dedicated.c +++ b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_dedicated.c @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -52,6 +52,7 @@ static void block_allocator_shutdown(ump_memory_backend * backend); static int block_allocator_allocate(void* ctx, ump_dd_mem * mem); static void block_allocator_release(void * ctx, ump_dd_mem * handle); static inline u32 get_phys(block_allocator * allocator, block_info * block); +static u32 block_allocator_stat(struct ump_memory_backend *backend); @@ -104,6 +105,7 @@ ump_memory_backend * ump_block_allocator_create(u32 base_address, u32 size) backend->allocate = block_allocator_allocate; backend->release = block_allocator_release; backend->shutdown = block_allocator_shutdown; + backend->stat = block_allocator_stat; backend->pre_allocate_physical_check = NULL; backend->adjust_to_mali_phys = NULL; backend->get = NULL; @@ -220,6 +222,7 @@ static int block_allocator_allocate(void* ctx, ump_dd_mem * mem) mem->backend_info = last_allocated; up(&allocator->mutex); + mem->is_cached=0; return 1; } @@ -272,3 +275,13 @@ static inline u32 get_phys(block_allocator * allocator, block_info * block) { return allocator->base + ((block - allocator->all_blocks) * UMP_BLOCK_SIZE); } + +static u32 block_allocator_stat(struct ump_memory_backend *backend) +{ + block_allocator *allocator; + BUG_ON(!backend); + allocator = (block_allocator*)backend->ctx; + BUG_ON(!allocator); + + return (allocator->num_blocks - allocator->num_free)* UMP_BLOCK_SIZE; +} diff --git a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_dedicated.h b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_dedicated.h index fa4bdcc..4f7180e 100644 --- a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_dedicated.h +++ b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_dedicated.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -20,4 +20,3 @@ ump_memory_backend * ump_block_allocator_create(u32 base_address, u32 size); #endif /* __UMP_KERNEL_MEMORY_BACKEND_DEDICATED_H__ */ - diff --git a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_os.c b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_os.c index 07fbd3f..2d81546 100644 --- a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_os.c +++ b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_os.c @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -136,16 +136,16 @@ static int os_allocate(void* ctx, ump_dd_mem * descriptor) return 0; /* failure */ } - while (left > 0 && ((info->num_pages_allocated + pages_allocated) < info->num_pages_max)) + while (left > 0) { struct page * new_page; if (is_cached) { - new_page = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN ); + new_page = alloc_page(GFP_HIGHUSER | __GFP_ZERO | __GFP_REPEAT | __GFP_NOWARN); } else { - new_page = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN | __GFP_COLD); + new_page = alloc_page(GFP_HIGHUSER | __GFP_ZERO | __GFP_REPEAT | __GFP_NOWARN | __GFP_COLD); } if (NULL == new_page) { @@ -182,9 +182,7 @@ static int os_allocate(void* ctx, ump_dd_mem * descriptor) if (left) { - MSG_ERR(("Failed to allocate needed pages\n")); - MSG_ERR(("UMP memory allocated: %d kB Configured maximum OS memory usage: %d kB\n", - (pages_allocated * _MALI_OSK_CPU_PAGE_SIZE)/1024, (info->num_pages_max* _MALI_OSK_CPU_PAGE_SIZE)/1024)); + DBG_MSG(1, ("Failed to allocate needed pages\n")); while(pages_allocated) { diff --git a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_os.h b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_os.h index f924705..b638562d 100644 --- a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_os.h +++ b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_os.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -20,4 +20,3 @@ ump_memory_backend * ump_os_memory_backend_create(const int max_allocation); #endif /* __UMP_KERNEL_MEMORY_BACKEND_OS_H__ */ - diff --git a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_vcm.c b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_vcm.c index de7f212..46797ea 100644 --- a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_vcm.c +++ b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_vcm.c @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -66,9 +66,9 @@ ump_memory_backend * ump_vcm_memory_backend_create(const int max_allocation) { return NULL; } - + info->num_vcm_blocks = 0; - + sema_init(&info->mutex, 1); @@ -85,7 +85,7 @@ ump_memory_backend * ump_vcm_memory_backend_create(const int max_allocation) backend->shutdown = vcm_memory_backend_destroy; backend->pre_allocate_physical_check = NULL; backend->adjust_to_mali_phys = NULL; - + backend->get = vcm_res_get; backend->set = vcm_attr_set; @@ -128,8 +128,8 @@ static int ump_vcm_allocate(void *ctx, ump_dd_mem * descriptor) ump_vcm->dev_id = (int)descriptor->backend_info & ~UMP_REF_DRV_UK_CONSTRAINT_USE_CACHE; - if(ump_vcm->dev_id == UMP_REF_DRV_UK_CONSTRAINT_NONE) { /* None */ - ump_vcm->dev_id = UMP_REF_DRV_UK_VCM_DEV_G2D; /* this ID is G2D */ + if(ump_vcm->dev_id == UMP_REF_DRV_UK_CONSTRAINT_NONE) { /* None */ + ump_vcm->dev_id = UMP_REF_DRV_UK_VCM_DEV_G2D; /* this ID is G2D */ } else if(ump_vcm->dev_id == UMP_REF_DRV_UK_CONSTRAINT_PHYSICALLY_LINEAR) { /* Physical Linear */ return 0; @@ -137,7 +137,7 @@ static int ump_vcm_allocate(void *ctx, ump_dd_mem * descriptor) else { /* Other VCM */ ump_vcm->dev_id -= 2; } - + DBG_MSG(5, ("Device ID for VCM : %d\n", ump_vcm->dev_id)); ump_vcm->vcm = vcm_find_vcm(ump_vcm->dev_id); @@ -146,7 +146,7 @@ static int ump_vcm_allocate(void *ctx, ump_dd_mem * descriptor) return 0; } descriptor->backend_info = (void*)ump_vcm; - + if (down_interruptible(&info->mutex)) { DBG_MSG(1, ("Failed to get mutex in ump_vcm_allocate\n")); return 0; /* failure */ @@ -168,7 +168,7 @@ static int vcm_mem_allocator(vcm_allocator *info, ump_dd_mem *descriptor) struct ump_vcm *ump_vcm; ump_vcm = (struct ump_vcm*)descriptor->backend_info; - + ump_vcm->vcm_res = vcm_make_binding(ump_vcm->vcm, descriptor->size_bytes, ump_vcm->dev_id, 0); @@ -288,5 +288,3 @@ static void vcm_attr_set(ump_dd_mem *mem, void *args) return; } - - diff --git a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_vcm.h b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_vcm.h index 62f6d12..c1ead0d 100644 --- a/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_vcm.h +++ b/drivers/media/video/samsung/ump/linux/ump_kernel_memory_backend_vcm.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff --git a/drivers/media/video/samsung/ump/linux/ump_memory_backend.c b/drivers/media/video/samsung/ump/linux/ump_memory_backend.c index f2a6bd6..821ac27 100644 --- a/drivers/media/video/samsung/ump/linux/ump_memory_backend.c +++ b/drivers/media/video/samsung/ump/linux/ump_memory_backend.c @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -17,7 +17,6 @@ #include "ump_kernel_common.h" #include "ump_kernel_memory_backend_os.h" #include "ump_kernel_memory_backend_dedicated.h" -#include "ump_kernel_memory_backend_vcm.h" /* Configure which dynamic memory allocator to use */ int ump_backend = ARCH_UMP_BACKEND_DEFAULT; diff --git a/drivers/media/video/samsung/ump/linux/ump_osk_atomics.c b/drivers/media/video/samsung/ump/linux/ump_osk_atomics.c index ef1902e..77be0c9 100644 --- a/drivers/media/video/samsung/ump/linux/ump_osk_atomics.c +++ b/drivers/media/video/samsung/ump/linux/ump_osk_atomics.c @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff --git a/drivers/media/video/samsung/ump/linux/ump_osk_low_level_mem.c b/drivers/media/video/samsung/ump/linux/ump_osk_low_level_mem.c index 17af2bd..b38c714 100644 --- a/drivers/media/video/samsung/ump/linux/ump_osk_low_level_mem.c +++ b/drivers/media/video/samsung/ump/linux/ump_osk_low_level_mem.c @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -27,6 +27,7 @@ #include <linux/slab.h> #include <asm/memory.h> +#include <asm/uaccess.h> /* to verify pointers from user space */ #include <asm/cacheflush.h> #include <linux/dma-mapping.h> @@ -301,108 +302,140 @@ static void _ump_osk_msync_with_virt(ump_dd_mem * mem, ump_uk_msync_op op, u32 s return; } -void _ump_osk_msync( ump_dd_mem * mem, ump_uk_msync_op op, u32 start, u32 address, u32 size) +static void level1_cache_flush_all(void) +{ + DBG_MSG(4, ("UMP[xx] Flushing complete L1 cache\n")); + __cpuc_flush_kern_all(); +} + +void _ump_osk_msync( ump_dd_mem * mem, void * virt, u32 offset, u32 size, ump_uk_msync_op op, ump_session_data * session_data ) { int i; - u32 start_p, end_p; - ump_dd_physical_block *block; + const void *start_v, *end_v; - DBG_MSG(3, - ("Flushing nr of blocks: %u. First: paddr: 0x%08x vaddr: 0x%08x size:%dB\n", - mem->nr_blocks, mem->block_array[0].addr, - phys_to_virt(mem->block_array[0].addr), - mem->block_array[0].size)); - -#ifndef USING_DMA_FLUSH - if (address) { - if ((address >= start) - && ((address + size) <= start + mem->size_bytes)) { - if (size >= SZ_64K) { - flush_all_cpu_caches(); - } else if (op == _UMP_UK_MSYNC_CLEAN_AND_INVALIDATE) - dmac_flush_range((void *)address, - (void *)(address + size - 1)); - else - dmac_map_area((void *)address, size, - DMA_TO_DEVICE); -#ifdef CONFIG_CACHE_L2X0 - if (size >= SZ_1M) - outer_clean_all(); + /* Flush L1 using virtual address, the entire range in one go. + * Only flush if user space process has a valid write mapping on given address. */ + if( (mem) && (virt!=NULL) && (access_ok(VERIFY_WRITE, virt, size)) ) + { + start_v = (void *)virt; + end_v = (void *)(start_v + size - 1); + /* There is no dmac_clean_range, so the L1 is always flushed, + * also for UMP_MSYNC_CLEAN. */ + dmac_flush_range(start_v, end_v); + DBG_MSG(3, ("UMP[%02u] Flushing CPU L1 Cache. Cpu address: %x-%x\n", mem->secure_id, start_v,end_v)); + } + else + { + if (session_data) + { + if (op == _UMP_UK_MSYNC_FLUSH_L1 ) + { + DBG_MSG(4, ("UMP Pending L1 cache flushes: %d\n", session_data->has_pending_level1_cache_flush)); + session_data->has_pending_level1_cache_flush = 0; + level1_cache_flush_all(); + return; + } else - _ump_osk_msync_with_virt(mem, op, start, address, size); -#endif - return; + { + if (session_data->cache_operations_ongoing) + { + session_data->has_pending_level1_cache_flush++; + DBG_MSG(4, ("UMP[%02u] Defering the L1 flush. Nr pending:%d\n", mem->secure_id, session_data->has_pending_level1_cache_flush) ); + } + else + { + /* Flushing the L1 cache for each switch_user() if ump_cache_operations_control(START) is not called */ + level1_cache_flush_all(); + } + } + } + else + { + DBG_MSG(4, ("Unkown state %s %d\n", __FUNCTION__, __LINE__)); + level1_cache_flush_all(); } } - if ((op == _UMP_UK_MSYNC_CLEAN_AND_INVALIDATE)) { - if ((mem->size_bytes >= SZ_1M)) { - flush_all_cpu_caches(); -#ifdef CONFIG_CACHE_L2X0 - outer_flush_all(); -#endif - return; - } else if ((mem->size_bytes >= SZ_64K)) { - flush_all_cpu_caches(); -#ifdef CONFIG_CACHE_L2X0 - for (i = 0; i < mem->nr_blocks; i++) { - block = &mem->block_array[i]; - start_p = (u32) block->addr; - end_p = start_p + block->size - 1; - outer_flush_range(start_p, end_p); - } -#endif - return; + if ( NULL == mem ) return; + + if ( mem->size_bytes==size) + { + DBG_MSG(3, ("UMP[%02u] Flushing CPU L2 Cache\n",mem->secure_id)); + } + else + { + DBG_MSG(3, ("UMP[%02u] Flushing CPU L2 Cache. Blocks:%u, TotalSize:%u. FlushSize:%u Offset:0x%x FirstPaddr:0x%08x\n", + mem->secure_id, mem->nr_blocks, mem->size_bytes, size, offset, mem->block_array[0].addr)); + } + + + /* Flush L2 using physical addresses, block for block. */ + for (i=0 ; i < mem->nr_blocks; i++) + { + u32 start_p, end_p; + ump_dd_physical_block *block; + block = &mem->block_array[i]; + + if(offset >= block->size) + { + offset -= block->size; + continue; } - } else { - if ((mem->size_bytes >= SZ_1M)) { - flush_all_cpu_caches(); -#ifdef CONFIG_CACHE_L2X0 - outer_clean_all(); -#endif - return; - } else if ((mem->size_bytes >= SZ_64K)) { - flush_all_cpu_caches(); -#ifdef CONFIG_CACHE_L2X0 - for (i = 0; i < mem->nr_blocks; i++) { - block = &mem->block_array[i]; - start_p = (u32) block->addr; + + if(offset) + { + start_p = (u32)block->addr + offset; + /* We'll zero the offset later, after using it to calculate end_p. */ + } + else + { + start_p = (u32)block->addr; + } + + if(size < block->size - offset) + { + end_p = start_p + size - 1; + size = 0; + } + else + { + if(offset) + { + end_p = start_p + (block->size - offset - 1); + size -= block->size - offset; + offset = 0; + } + else + { end_p = start_p + block->size - 1; - outer_clean_range(start_p, end_p); + size -= block->size; } -#endif - return; } - } -#endif - for (i = 0; i < mem->nr_blocks; i++) { - /* TODO: Find out which flush method is best of 1)Dma OR 2)Normal flush functions */ - /*#define USING_DMA_FLUSH */ -#ifdef USING_DMA_FLUSH - DEBUG_ASSERT((PAGE_SIZE == mem->block_array[i].size)); - dma_map_page(NULL, - pfn_to_page(mem->block_array[i]. - addr >> PAGE_SHIFT), 0, PAGE_SIZE, - DMA_BIDIRECTIONAL); - /*dma_unmap_page(NULL, mem->block_array[i].addr, PAGE_SIZE, DMA_BIDIRECTIONAL); */ -#else - block = &mem->block_array[i]; - start_p = (u32) block->addr; - end_p = start_p + block->size - 1; - if (op == _UMP_UK_MSYNC_CLEAN_AND_INVALIDATE) { - dmac_flush_range(phys_to_virt(start_p), - phys_to_virt(end_p)); - outer_flush_range(start_p, end_p); - } else { - dmac_map_area(phys_to_virt(start_p), block->size, - DMA_TO_DEVICE); - outer_clean_range(start_p, end_p); + switch(op) + { + case _UMP_UK_MSYNC_CLEAN: + outer_clean_range(start_p, end_p); + break; + case _UMP_UK_MSYNC_CLEAN_AND_INVALIDATE: + outer_flush_range(start_p, end_p); + break; + case _UMP_UK_MSYNC_INVALIDATE: + outer_inv_range(start_p, end_p); + break; + default: + break; + } + + if(0 == size) + { + /* Nothing left to flush. */ + break; } -#endif } -} + return; +} void _ump_osk_mem_mapregion_get( ump_dd_mem ** mem, unsigned long vaddr) { diff --git a/drivers/media/video/samsung/ump/linux/ump_osk_misc.c b/drivers/media/video/samsung/ump/linux/ump_osk_misc.c index 12066eb..1f1118e 100644 --- a/drivers/media/video/samsung/ump/linux/ump_osk_misc.c +++ b/drivers/media/video/samsung/ump/linux/ump_osk_misc.c @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff --git a/drivers/media/video/samsung/ump/linux/ump_ukk_ref_wrappers.c b/drivers/media/video/samsung/ump/linux/ump_ukk_ref_wrappers.c index 3e355c0..405bdca 100644 --- a/drivers/media/video/samsung/ump/linux/ump_ukk_ref_wrappers.c +++ b/drivers/media/video/samsung/ump/linux/ump_ukk_ref_wrappers.c @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff --git a/drivers/media/video/samsung/ump/linux/ump_ukk_ref_wrappers.h b/drivers/media/video/samsung/ump/linux/ump_ukk_ref_wrappers.h index 7bd4660..8e3c0fc 100644 --- a/drivers/media/video/samsung/ump/linux/ump_ukk_ref_wrappers.h +++ b/drivers/media/video/samsung/ump/linux/ump_ukk_ref_wrappers.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ diff --git a/drivers/media/video/samsung/ump/linux/ump_ukk_wrappers.c b/drivers/media/video/samsung/ump/linux/ump_ukk_wrappers.c index 8b73ca8..e5c5903 100644 --- a/drivers/media/video/samsung/ump/linux/ump_ukk_wrappers.c +++ b/drivers/media/video/samsung/ump/linux/ump_ukk_wrappers.c @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -138,9 +138,9 @@ int ump_size_get_wrapper(u32 __user * argument, struct ump_session_data * sessi } /* - * IOCTL operation; Return size for specified UMP memory. + * IOCTL operation; Do cache maintenance on specified UMP memory. */ - int ump_msync_wrapper(u32 __user * argument, struct ump_session_data * session_data) +int ump_msync_wrapper(u32 __user * argument, struct ump_session_data * session_data) { _ump_uk_msync_s user_interaction; @@ -171,3 +171,136 @@ int ump_size_get_wrapper(u32 __user * argument, struct ump_session_data * sessi return 0; /* success */ } +int ump_cache_operations_control_wrapper(u32 __user * argument, struct ump_session_data * session_data) +{ + _ump_uk_cache_operations_control_s user_interaction; + + /* Sanity check input parameters */ + if (NULL == argument || NULL == session_data) + { + MSG_ERR(("NULL parameter in ump_ioctl_size_get()\n")); + return -ENOTTY; + } + + if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) + { + MSG_ERR(("copy_from_user() in ump_ioctl_cache_operations_control()\n")); + return -EFAULT; + } + + user_interaction.ctx = (void *) session_data; + + _ump_ukk_cache_operations_control((_ump_uk_cache_operations_control_s*) &user_interaction ); + + user_interaction.ctx = NULL; + +#if 0 /* No data to copy back */ + if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) + { + MSG_ERR(("copy_to_user() failed in ump_ioctl_cache_operations_control()\n")); + return -EFAULT; + } +#endif + return 0; /* success */ +} + +int ump_switch_hw_usage_wrapper(u32 __user * argument, struct ump_session_data * session_data) +{ + _ump_uk_switch_hw_usage_s user_interaction; + + /* Sanity check input parameters */ + if (NULL == argument || NULL == session_data) + { + MSG_ERR(("NULL parameter in ump_ioctl_size_get()\n")); + return -ENOTTY; + } + + if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) + { + MSG_ERR(("copy_from_user() in ump_ioctl_switch_hw_usage()\n")); + return -EFAULT; + } + + user_interaction.ctx = (void *) session_data; + + _ump_ukk_switch_hw_usage( &user_interaction ); + + user_interaction.ctx = NULL; + +#if 0 /* No data to copy back */ + if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) + { + MSG_ERR(("copy_to_user() failed in ump_ioctl_switch_hw_usage()\n")); + return -EFAULT; + } +#endif + return 0; /* success */ +} + +int ump_lock_wrapper(u32 __user * argument, struct ump_session_data * session_data) +{ + _ump_uk_lock_s user_interaction; + + /* Sanity check input parameters */ + if (NULL == argument || NULL == session_data) + { + MSG_ERR(("NULL parameter in ump_ioctl_size_get()\n")); + return -ENOTTY; + } + + if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) + { + MSG_ERR(("copy_from_user() in ump_ioctl_switch_hw_usage()\n")); + return -EFAULT; + } + + user_interaction.ctx = (void *) session_data; + + _ump_ukk_lock( &user_interaction ); + + user_interaction.ctx = NULL; + +#if 0 /* No data to copy back */ + if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) + { + MSG_ERR(("copy_to_user() failed in ump_ioctl_switch_hw_usage()\n")); + return -EFAULT; + } +#endif + + return 0; /* success */ +} + +int ump_unlock_wrapper(u32 __user * argument, struct ump_session_data * session_data) +{ + _ump_uk_unlock_s user_interaction; + + /* Sanity check input parameters */ + if (NULL == argument || NULL == session_data) + { + MSG_ERR(("NULL parameter in ump_ioctl_size_get()\n")); + return -ENOTTY; + } + + if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) + { + MSG_ERR(("copy_from_user() in ump_ioctl_switch_hw_usage()\n")); + return -EFAULT; + } + + user_interaction.ctx = (void *) session_data; + + _ump_ukk_unlock( &user_interaction ); + + user_interaction.ctx = NULL; + +#if 0 /* No data to copy back */ + if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) + { + MSG_ERR(("copy_to_user() failed in ump_ioctl_switch_hw_usage()\n")); + return -EFAULT; + } +#endif + + return 0; /* success */ +} diff --git a/drivers/media/video/samsung/ump/linux/ump_ukk_wrappers.h b/drivers/media/video/samsung/ump/linux/ump_ukk_wrappers.h index 4892c31..99b790d 100644 --- a/drivers/media/video/samsung/ump/linux/ump_ukk_wrappers.h +++ b/drivers/media/video/samsung/ump/linux/ump_ukk_wrappers.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2010 ARM Limited. All rights reserved. - * + * Copyright (C) 2010-2012 ARM Limited. All rights reserved. + * * This program is free software and is provided to you under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. - * + * * A copy of the licence is included with the program, and can also be obtained from Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -30,6 +30,10 @@ int ump_get_api_version_wrapper(u32 __user * argument, struct ump_session_data * int ump_release_wrapper(u32 __user * argument, struct ump_session_data * session_data); int ump_size_get_wrapper(u32 __user * argument, struct ump_session_data * session_data); int ump_msync_wrapper(u32 __user * argument, struct ump_session_data * session_data); +int ump_cache_operations_control_wrapper(u32 __user * argument, struct ump_session_data * session_data); +int ump_switch_hw_usage_wrapper(u32 __user * argument, struct ump_session_data * session_data); +int ump_lock_wrapper(u32 __user * argument, struct ump_session_data * session_data); +int ump_unlock_wrapper(u32 __user * argument, struct ump_session_data * session_data); #ifdef __cplusplus |