Beispiel #1
0
/*
 * make sure USB_CLK is running at 60 MHz +/- 1000 Hz
 */
static int fsl_check_usbclk(void)
{
	unsigned long freq;

	usb_ahb_clk = clk_get(NULL, "usb_ahb_clk");
	if (clk_enable(usb_ahb_clk)) {
		if (cpu_is_mx6())
			return 0; /* there is no ahb clock at mx6 */
		printk(KERN_ERR "clk_enable(usb_ahb_clk) failed\n");
		return -EINVAL;
	}
	clk_put(usb_ahb_clk);

	usb_clk = clk_get(NULL, "usb_clk");
	if (clk_enable(usb_clk)) {
		if (cpu_is_mx6())
			return 0; /* there is usb_clk at mx6 */
		printk(KERN_ERR "clk_enable(usb_clk) failed\n");
		return -EINVAL;
	}
	freq = clk_get_rate(usb_clk);
	clk_put(usb_clk);
	if ((freq < 59999000) || (freq > 60001000)) {
		printk(KERN_ERR "USB_CLK=%lu, should be 60MHz\n", freq);
		return -1;
	}

	return 0;
}
Beispiel #2
0
static int imx6_mmu_init(void)
{
    void __iomem *l2x0_base = IOMEM(0x00a02000);
    u32 val;

    if (!cpu_is_mx6())
        return 0;

    /* Configure the L2 PREFETCH and POWER registers */
    val = readl(l2x0_base + L310_PREFETCH_CTRL);
    val |= 0x70800000;

    /*
     * The L2 cache controller(PL310) version on the i.MX6D/Q is r3p1-50rel0
     * The L2 cache controller(PL310) version on the i.MX6DL/SOLO/SL is r3p2
     * But according to ARM PL310 errata: 752271
     * ID: 752271: Double linefill feature can cause data corruption
     * Fault Status: Present in: r3p0, r3p1, r3p1-50rel0. Fixed in r3p2
     * Workaround: The only workaround to this erratum is to disable the
     * double linefill feature. This is the default behavior.
     */
    if (cpu_is_mx6q())
        val &= ~(1 << 30 | 1 << 23);

    writel(val, l2x0_base + L310_PREFETCH_CTRL);

    l2x0_init(l2x0_base, 0x0, ~0UL);

    return 0;
}
static enum filetype imx_bbu_expected_filetype(void)
{
	if (cpu_is_mx8mq() ||
	    cpu_is_mx7()   ||
	    cpu_is_mx6()   ||
	    cpu_is_vf610() ||
	    cpu_is_mx53())
		return filetype_imx_image_v2;

	return filetype_imx_image_v1;
}
static int set_cpu_freq(int op)
{
	int ret = 0;

	if (cpu_is_mx6())
		ret = mx6_set_cpu_freq(op);
	else
		ret = mx5_set_cpu_freq(op);

	cpufreq_trig_needed = 1;
	old_op = op;
	return ret;
}
Beispiel #5
0
static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
{
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct pltfm_imx_data *imx_data = pltfm_host->priv;

	/* fake CARD_PRESENT flag on mx25/35 */
	u32 val = readl(host->ioaddr + reg);

	/*
	 * mx6q: SDHCI_PRESENT_STATE bit 16, CINST is not functional on SD3.
	 * So move the section up, and check GPIO for card presence again in
	 * the following block.
	 */
	if (reg == SDHCI_PRESENT_STATE && cpu_is_mx6()) {
		u32 fsl_prss = readl(host->ioaddr + SDHCI_PRESENT_STATE);
		/* save the least 20 bits */
		val |= fsl_prss & 0x000FFFFF;
		/* move dat[0-3] line signal bits */
		val |= (fsl_prss & 0x0F000000) >> 4;
		/* move cmd line signal bits */
		val |= (fsl_prss & 0x00800000) << 1;
	}
/*!
 * This is the probe routine for the DVFS driver.
 *
 * @param   pdev   The platform device structure
 *
 * @return         The function returns 0 on success
 */
static int __devinit mxc_dvfs_core_probe(struct platform_device *pdev)
{
	int err = 0;
	struct resource *res;

	printk(KERN_INFO "mxc_dvfs_core_probe\n");
	dvfs_dev = &pdev->dev;
	dvfs_data = pdev->dev.platform_data;

	INIT_DELAYED_WORK(&dvfs_core_handler, dvfs_core_work_handler);

	pll1_sw_clk = clk_get(NULL, "pll1_sw_clk");
	if (IS_ERR(pll1_sw_clk)) {
		printk(KERN_INFO "%s: failed to get pll1_sw_clk\n", __func__);
		return PTR_ERR(pll1_sw_clk);
	}

	cpu_clk = clk_get(NULL, dvfs_data->clk1_id);
	if (IS_ERR(cpu_clk)) {
		printk(KERN_ERR "%s: failed to get cpu clock\n", __func__);
		return PTR_ERR(cpu_clk);
	}
	if (!cpu_is_mx6()) {
		dvfs_clk = clk_get(NULL, dvfs_data->clk2_id);
		if (IS_ERR(dvfs_clk)) {
			printk(KERN_ERR "%s: failed to get dvfs clock\n", __func__);
			return PTR_ERR(dvfs_clk);
		}
	}
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (res == NULL) {
		err = -ENODEV;
		goto err1;
	}
	dvfs_data->membase = ioremap(res->start, res->end - res->start + 1);
	/*
	 * Request the DVFS interrupt
	 */
	dvfs_data->irq = platform_get_irq(pdev, 0);
	if (dvfs_data->irq < 0) {
		err = dvfs_data->irq;
		goto err2;
	}

	/* request the DVFS interrupt */
	err = request_irq(dvfs_data->irq, dvfs_irq, IRQF_SHARED, "dvfs",
			  dvfs_dev);
	if (err) {
		printk(KERN_ERR
		       "DVFS: Unable to attach to DVFS interrupt,err = %d",
		       err);
		goto err2;
	}

	dvfs_core_setpoint = get_dvfs_core_op(&dvfs_core_op);
	if (dvfs_core_setpoint == NULL) {
		printk(KERN_ERR "No dvfs_core working point table defined\n");
		goto err3;
	}

	clk_enable(dvfs_clk);
	err = init_dvfs_controller();
	if (err) {
		printk(KERN_ERR "DVFS: Unable to initialize DVFS");
		return err;
	}
	clk_disable(dvfs_clk);

	err = sysfs_create_file(&pdev->dev.kobj, &dev_attr_enable.attr);
	if (err) {
		printk(KERN_ERR
		       "DVFS: Unable to register sysdev entry for DVFS");
		goto err3;
	}

	err = sysfs_create_file(&dvfs_dev->kobj, &dev_attr_show_regs.attr);
	if (err) {
		printk(KERN_ERR
		       "DVFS: Unable to register sysdev entry for DVFS");
		goto err3;
	}

	/* Set the current working point. */
	cpu_op_tbl = get_cpu_op(&cpu_op_nr);
	old_op = 0;
	curr_op = 0;
	dvfs_core_resume = 0;
	cpufreq_trig_needed = 0;

	return err;
err3:
	free_irq(dvfs_data->irq, dvfs_dev);
err2:
	iounmap(dvfs_data->membase);
err1:
	dev_err(&pdev->dev, "Failed to probe DVFS CORE\n");
	return err;
}
static int start_dvfs(void)
{
	u32 reg, cpu_rate;
	unsigned long flags;

	if (dvfs_core_is_active)
		return 0;

	spin_lock_irqsave(&mxc_dvfs_core_lock, flags);

	clk_enable(dvfs_clk);

	/* get current working point */
	cpu_rate = clk_get_rate(cpu_clk);
	curr_op = cpu_op_nr - 1;
	do {
		if (cpu_rate <= cpu_op_tbl[curr_op].cpu_rate)
			break;
	} while (--curr_op >= 0);
	old_op = curr_op;

	dvfs_load_config(curr_op);

	if (curr_op == 0)
		maxf = 1;
	else
		maxf = 0;
	if (curr_op == (cpu_op_nr - 1))
		minf = 1;
	else
		minf = 0;

	/* config reg GPC_CNTR */
	reg = __raw_readl(gpc_base + dvfs_data->gpc_cntr_offset);

	reg &= ~MXC_GPCCNTR_GPCIRQM;
	/* GPCIRQ=1, select ARM IRQ */
	reg |= MXC_GPCCNTR_GPCIRQ_ARM;
	/* ADU=1, select ARM domain */
	if (!cpu_is_mx6())
		reg |= MXC_GPCCNTR_ADU;
	__raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset);

	/* Set PREDIV bits */
	reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR);
	reg = (reg & ~(dvfs_data->prediv_mask));
	reg |= (dvfs_data->prediv_val) << (dvfs_data->prediv_offset);
	__raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR);

	/* Enable DVFS interrupt */
	reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR);
	/* FSVAIM=0 */
	reg = (reg & ~MXC_DVFSCNTR_FSVAIM);

	/* Set MAXF, MINF */
	reg = (reg & ~(MXC_DVFSCNTR_MAXF_MASK
				| MXC_DVFSCNTR_MINF_MASK));
	reg |= 1 << MXC_DVFSCNTR_MAXF_OFFSET;

	/* Select ARM domain */
	reg |= MXC_DVFSCNTR_DVFIS;
	/* Enable DVFS frequency adjustment interrupt */
	reg = (reg & ~MXC_DVFSCNTR_FSVAIM);
	/* Set load tracking buffer register source */
	reg = (reg & ~MXC_DVFSCNTR_LTBRSR_MASK);
	reg |= DVFS_LTBRSR;
	/* Set DIV3CK */
	reg = (reg & ~(dvfs_data->div3ck_mask));
	reg |= (dvfs_data->div3ck_val) << (dvfs_data->div3ck_offset);
	__raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR);

	/* Enable DVFS */
	if (cpu_is_mx6()) {
		unsigned long cpu_wfi = 0;
		int num_cpus = num_possible_cpus();
		reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_EMAC);
		/* Need to enable DVFS tracking for each core that is active */
		do {
			if (cpu_active(num_cpus))
				set_bit(num_cpus, &cpu_wfi);
		} while (num_cpus--);
		reg |= cpu_wfi << 9;
		__raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_EMAC);
	} else {
		reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR);
		reg |= MXC_DVFSCNTR_DVFEN;
		__raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR);
	}

	dvfs_core_is_active = 1;

	spin_unlock_irqrestore(&mxc_dvfs_core_lock, flags);

	printk(KERN_DEBUG "DVFS is started\n");
	return 0;
}
Beispiel #8
0
int usbotg_init(struct platform_device *pdev)
{
	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
	struct fsl_xcvr_ops *xops;

	pr_debug("%s: pdev=0x%p  pdata=0x%p\n", __func__, pdev, pdata);

	xops = fsl_usb_get_xcvr(pdata->transceiver);
	if (!xops) {
		printk(KERN_ERR "DR transceiver ops missing\n");
		return -EINVAL;
	}
	pdata->xcvr_ops = xops;
	pdata->xcvr_type = xops->xcvr_type;
	pdata->pdev = pdev;

	if (fsl_check_usbclk() != 0)
		return -EINVAL;
	if (!mxc_otg_used) {
		if (cpu_is_mx50())
			/* Turn on AHB CLK for OTG*/
			USB_CLKONOFF_CTRL &= ~OTG_AHBCLK_OFF;

		pr_debug("%s: grab pins\n", __func__);
		if (pdata->gpio_usb_active && pdata->gpio_usb_active())
			return -EINVAL;
		if (xops->init)
			xops->init(xops);
		if (!(cpu_is_mx6())) {
			UOG_PORTSC1 = UOG_PORTSC1 & ~PORTSC_PHCD;


			if (xops->xcvr_type == PORTSC_PTS_SERIAL) {
				if (pdata->operating_mode == FSL_USB2_DR_HOST) {
					otg_set_serial_host();
					/* need reset */
					UOG_USBCMD |= UCMD_RESET;
					msleep(100);
				} else if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
					otg_set_serial_peripheral();
				otg_set_serial_xcvr();
			} else if (xops->xcvr_type == PORTSC_PTS_ULPI) {
				otg_set_ulpi_xcvr();
			} else if (xops->xcvr_type == PORTSC_PTS_UTMI) {
				otg_set_utmi_xcvr();
			}
		} else {
#ifdef CONFIG_ARCH_MX6
			if (machine_is_mx6q_arm2())
				USB_OTG_CTRL &= ~UCTRL_OVER_CUR_POL;
			else if (machine_is_mx6q_sabrelite())
				USB_OTG_CTRL |= UCTRL_OVER_CUR_POL;
			USB_OTG_CTRL |= UCTRL_OVER_CUR_DIS;
#endif
		}
	}

	if (usb_register_remote_wakeup(pdev))
		pr_debug("DR is not a wakeup source.\n");

	mxc_otg_used++;
	pr_debug("%s: success\n", __func__);
	return 0;
}
Beispiel #9
0
int fsl_usb_host_init(struct platform_device *pdev)
{
	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
	struct fsl_xcvr_ops *xops;

	pr_debug("%s: pdev=0x%p  pdata=0x%p\n", __func__, pdev, pdata);

	xops = fsl_usb_get_xcvr(pdata->transceiver);
	if (!xops) {
		printk(KERN_ERR "%s transceiver ops missing\n", pdata->name);
		return -EINVAL;
	}
	pdata->xcvr_ops = xops;
	pdata->xcvr_type = xops->xcvr_type;
	pdata->pdev = pdev;

	if (fsl_check_usbclk() != 0)
		return -EINVAL;

	pr_debug("%s: grab pins\n", __func__);
	if (pdata->gpio_usb_active && pdata->gpio_usb_active())
		return -EINVAL;

	if (cpu_is_mx50())
		/* Turn on AHB CLK for H1*/
		USB_CLKONOFF_CTRL &= ~H1_AHBCLK_OFF;

	/* enable board power supply for xcvr */
	if (pdata->xcvr_pwr) {
		if (pdata->xcvr_pwr->regu1)
			regulator_enable(pdata->xcvr_pwr->regu1);
		if (pdata->xcvr_pwr->regu2)
			regulator_enable(pdata->xcvr_pwr->regu2);
	}

	if (xops->init)
		xops->init(xops);

	if (usb_register_remote_wakeup(pdev))
		pr_debug("%s port is not a wakeup source.\n", pdata->name);
	if (!(cpu_is_mx6())) {
		if (xops->xcvr_type == PORTSC_PTS_SERIAL) {
			if (cpu_is_mx35()) {
				usbh2_set_serial_xcvr();
				/* Close the internal 60Mhz */
				USBCTRL &= ~UCTRL_XCSH2;
			} else if (cpu_is_mx25())
				usbh2_set_serial_xcvr();
			else
				usbh1_set_serial_xcvr();
		} else if (xops->xcvr_type == PORTSC_PTS_ULPI) {
			if (!strcmp("Host 1", pdata->name))
				usbh1_set_ulpi_xcvr();
			if (!strcmp("Host 2", pdata->name))
				usbh2_set_ulpi_xcvr();
		} else if (xops->xcvr_type == PORTSC_PTS_UTMI) {
			usbh1_set_utmi_xcvr();
		}
	} else {
#ifdef CONFIG_ARCH_MX6
		if (!strcmp("Host 1", pdata->name)) {
			if (machine_is_mx6q_arm2())
				USB_H1_CTRL &= ~UCTRL_OVER_CUR_POL;
			else if (machine_is_mx6q_sabrelite())
				USB_H1_CTRL |= UCTRL_OVER_CUR_POL;
			USB_H1_CTRL |= UCTRL_OVER_CUR_DIS;

			if (machine_is_cm_fx6())
				USB_H1_CTRL |= UCTRL_PWR_POL;
		}
#endif
	}

	pr_debug("%s: %s success\n", __func__, pdata->name);
	return 0;
}
Beispiel #10
0
int32_t encoder_open(struct encode *enc)
{
    EncHandle handle = { 0 };
    EncOpenParam encop = { 0 };
    RetCode ret;

    /* Fill up parameters for encoding */
    encop.bitstreamBuffer = enc->phy_bsbuf_addr;
    encop.bitstreamBufferSize = STREAM_BUF_SIZE;
    encop.bitstreamFormat = enc->codecctrl->format;
    encop.mapType = enc->codecctrl->mapType;
    encop.linear2TiledEnable = enc->linear2TiledEnable;

    /* width and height in command line means source image size */
    if (enc->codecctrl->width && enc->codecctrl->height) {
        enc->src_picwidth = enc->codecctrl->width;
        enc->src_picheight = enc->codecctrl->height;
    }

    /* enc_width and enc_height in command line means encoder output size */
    if (enc->codecctrl->enc_width && enc->codecctrl->enc_height) {
        enc->enc_picwidth = enc->codecctrl->enc_width;
        enc->enc_picheight = enc->codecctrl->enc_height;
    } else {
        enc->enc_picwidth = enc->src_picwidth;
        enc->enc_picheight = enc->src_picheight;
    }

    /* If rotation angle is 90 or 270, pic width and height are swapped */
    if (enc->codecctrl->rot_angle == 90 || enc->codecctrl->rot_angle == 270) {
        encop.picWidth = enc->enc_picheight;
        encop.picHeight = enc->enc_picwidth;
    } else {
        encop.picWidth = enc->enc_picwidth;
        encop.picHeight = enc->enc_picheight;
    }

    /*Note: Frame rate cannot be less than 15fps per H.263 spec */
    encop.frameRateInfo = frameRateInfo = 30;
    encop.bitRate = enc->codecctrl->bitrate;
    encop.gopSize = enc->codecctrl->gop;
    encop.slicemode.sliceMode = 0;  /* 0: 1 slice per picture; 1: Multiple slices per picture */
    encop.slicemode.sliceSizeMode = 0;  /* 0: silceSize defined by bits; 1: sliceSize defined by MB number */
    encop.slicemode.sliceSize = 4000;   /* Size of a slice in bits or MB numbers */

    encop.initialDelay = 0;
    encop.vbvBufferSize = 0;    /* 0 = ignore 8 */
    encop.intraRefresh = 0;
    encop.sliceReport = 0;
    encop.mbReport = 0;
    encop.mbQpReport = 0;
    encop.rcIntraQp = -1;
    encop.userQpMax = 0;
    encop.userQpMin = 0;
    encop.userQpMinEnable = 0;
    encop.userQpMaxEnable = 0;

    encop.IntraCostWeight = 0;
    encop.MEUseZeroPmv = 0;
    /* (3: 16x16, 2:32x16, 1:64x32, 0:128x64, H.263(Short Header : always 3) */
    encop.MESearchRange = 3;

    encop.userGamma = (uint32_t) (0.75 * 32768);    /*  (0*32768 <= gamma <= 1*32768) */
    encop.RcIntervalMode = 1;   /* 0:normal, 1:frame_level, 2:slice_level, 3: user defined Mb_level */
    encop.MbInterval = 0;
    encop.avcIntra16x16OnlyModeEnable = 0;

    encop.ringBufferEnable = enc->ringBufferEnable = 0;
    encop.dynamicAllocEnable = 0;
    encop.chromaInterleave = enc->codecctrl->chromaInterleave;

    if (enc->codecctrl->format == STD_MPEG4) {
        encop.EncStdParam.mp4Param.mp4_dataPartitionEnable = 0;
        enc->mp4_dataPartitionEnable = encop.EncStdParam.mp4Param.mp4_dataPartitionEnable;
        encop.EncStdParam.mp4Param.mp4_reversibleVlcEnable = 0;
        encop.EncStdParam.mp4Param.mp4_intraDcVlcThr = 0;
        encop.EncStdParam.mp4Param.mp4_hecEnable = 0;
        encop.EncStdParam.mp4Param.mp4_verid = 2;
    } else if (enc->codecctrl->format == STD_H263) {
        encop.EncStdParam.h263Param.h263_annexIEnable = 0;
        encop.EncStdParam.h263Param.h263_annexJEnable = 1;
        encop.EncStdParam.h263Param.h263_annexKEnable = 0;
        encop.EncStdParam.h263Param.h263_annexTEnable = 0;
    } else if (enc->codecctrl->format == STD_AVC) {
        encop.EncStdParam.avcParam.avc_constrainedIntraPredFlag = 0;
        encop.EncStdParam.avcParam.avc_disableDeblk = 1;
        encop.EncStdParam.avcParam.avc_deblkFilterOffsetAlpha = 6;
        encop.EncStdParam.avcParam.avc_deblkFilterOffsetBeta = 0;
        encop.EncStdParam.avcParam.avc_chromaQpOffset = 10;
        encop.EncStdParam.avcParam.avc_audEnable = 0;
        if (cpu_is_mx6()) {
            encop.EncStdParam.avcParam.interview_en = 0;
            encop.EncStdParam.avcParam.paraset_refresh_en = enc->mvc_paraset_refresh_en = 0;
            encop.EncStdParam.avcParam.prefix_nal_en = 0;
            encop.EncStdParam.avcParam.mvc_extension = enc->codecctrl->mp4_h264Class;
            enc->mvc_extension = enc->codecctrl->mp4_h264Class;
            encop.EncStdParam.avcParam.avc_frameCroppingFlag = 0;
            encop.EncStdParam.avcParam.avc_frameCropLeft = 0;
            encop.EncStdParam.avcParam.avc_frameCropRight = 0;
            encop.EncStdParam.avcParam.avc_frameCropTop = 0;
            encop.EncStdParam.avcParam.avc_frameCropBottom = 0;
            if (enc->codecctrl->rot_angle != 90 &&
                enc->codecctrl->rot_angle != 270 && enc->enc_picheight == 1080) {
                /*
                 * In case of AVC encoder, when we want to use
                 * unaligned display width frameCroppingFlag
                 * parameters should be adjusted to displayable
                 * rectangle
                 */
                encop.EncStdParam.avcParam.avc_frameCroppingFlag = 1;
                encop.EncStdParam.avcParam.avc_frameCropBottom = 8;
            }

        } else {
            encop.EncStdParam.avcParam.avc_fmoEnable = 0;
            encop.EncStdParam.avcParam.avc_fmoType = 0;
            encop.EncStdParam.avcParam.avc_fmoSliceNum = 1;
            encop.EncStdParam.avcParam.avc_fmoSliceSaveBufSize = 32;    /* FMO_SLICE_SAVE_BUF_SIZE */
        }
    }

    ret = VPU_EncOpen(&handle, &encop);
    if (ret != RETCODE_SUCCESS) {
        err_msg("Encoder open failed %d\n", ret);
        return -1;
    }

    enc->handle = handle;
    return 0;
}
Beispiel #11
0
int32_t encoder_allocate_framebuffer(struct encode *enc)
{
    EncHandle handle = enc->handle;
    int32_t i, enc_stride, src_stride, src_fbid;
    int32_t totalfb, minfbcount, srcfbcount, extrafbcount;
    RetCode ret;
    FrameBuffer *fb;
    PhysicalAddress subSampBaseA = 0, subSampBaseB = 0;
    struct frame_buf **pfbpool;
    EncExtBufInfo extbufinfo = { 0 };
    int32_t enc_fbwidth, enc_fbheight, src_fbwidth, src_fbheight;

    minfbcount = enc->minFrameBufferCount;
    srcfbcount = 1;

    enc_fbwidth = (enc->enc_picwidth + 15) & ~15;
    enc_fbheight = (enc->enc_picheight + 15) & ~15;
    src_fbwidth = (enc->src_picwidth + 15) & ~15;
    src_fbheight = (enc->src_picheight + 15) & ~15;

    if (cpu_is_mx6()) {
        if (enc->codecctrl->format == STD_AVC && enc->mvc_extension)    /* MVC */
            extrafbcount = 2 + 2;   /* Subsamp [2] + Subsamp MVC [2] */
        else if (enc->codecctrl->format == STD_MJPG)
            extrafbcount = 0;
        else
            extrafbcount = 2;   /* Subsamp buffer [2] */
    } else
        extrafbcount = 0;

    enc->totalfb = totalfb = minfbcount + extrafbcount + srcfbcount;

    /* last framebuffer is used as src frame in the test */
    enc->src_fbid = src_fbid = totalfb - 1;

    fb = enc->fb = calloc(totalfb, sizeof(FrameBuffer));
    if (fb == NULL) {
        err_msg("Failed to allocate enc->fb\n");
        return -1;
    }

    pfbpool = enc->pfbpool = calloc(totalfb, sizeof(struct frame_buf *));
    if (pfbpool == NULL) {
        err_msg("Failed to allocate enc->pfbpool\n");
        free(fb);
        return -1;
    }

    if (enc->codecctrl->mapType == LINEAR_FRAME_MAP) {
        /* All buffers are linear */
        for (i = 0; i < minfbcount + extrafbcount; i++) {
            pfbpool[i] = framebuf_alloc(enc->codecctrl->format, enc->mjpg_fmt,
                                        enc_fbwidth, enc_fbheight, 0);
            if (pfbpool[i] == NULL) {
                goto err1;
            }
        }
    } else {
        /* Encoded buffers are tiled */
        for (i = 0; i < minfbcount; i++) {
            pfbpool[i] = tiled_framebuf_alloc(enc->codecctrl->format, enc->mjpg_fmt,
                                              enc_fbwidth, enc_fbheight, 0,
                                              enc->codecctrl->mapType);
            if (pfbpool[i] == NULL)
                goto err1;
        }
        /* sub frames are linear */
        for (i = minfbcount; i < minfbcount + extrafbcount; i++) {
            pfbpool[i] = framebuf_alloc(enc->codecctrl->format, enc->mjpg_fmt,
                                        enc_fbwidth, enc_fbheight, 0);
            if (pfbpool[i] == NULL)
                goto err1;
        }
    }

    for (i = 0; i < minfbcount + extrafbcount; i++) {
        fb[i].myIndex = i;
        fb[i].bufY = pfbpool[i]->addrY;
        fb[i].bufCb = pfbpool[i]->addrCb;
        fb[i].bufCr = pfbpool[i]->addrCr;
        fb[i].strideY = pfbpool[i]->strideY;
        fb[i].strideC = pfbpool[i]->strideC;
    }

    if (cpu_is_mx6() && (enc->codecctrl->format != STD_MJPG)) {
        subSampBaseA = fb[minfbcount].bufY;
        subSampBaseB = fb[minfbcount + 1].bufY;
        if (enc->codecctrl->format == STD_AVC && enc->mvc_extension) {  /* MVC */
            extbufinfo.subSampBaseAMvc = fb[minfbcount + 2].bufY;
            extbufinfo.subSampBaseBMvc = fb[minfbcount + 3].bufY;
        }
    }

    /* Must be a multiple of 16 */
    if (enc->codecctrl->rot_angle == 90 || enc->codecctrl->rot_angle == 270)
        enc_stride = (enc->enc_picheight + 15) & ~15;
    else
        enc_stride = (enc->enc_picwidth + 15) & ~15;
    src_stride = (enc->src_picwidth + 15) & ~15;

    extbufinfo.scratchBuf = enc->scratchBuf;
    ret = VPU_EncRegisterFrameBuffer(handle, fb, minfbcount, enc_stride, src_stride,
                                     subSampBaseA, subSampBaseB, &extbufinfo);
    if (ret != RETCODE_SUCCESS) {
        err_msg("Register frame buffer failed\n");
        goto err1;
    }

    {
        /* Allocate a single frame buffer for source frame */
        pfbpool[src_fbid] = framebuf_alloc(enc->codecctrl->format, enc->mjpg_fmt,
                                           src_fbwidth, src_fbheight, 0);
        if (pfbpool[src_fbid] == NULL) {
            err_msg("failed to allocate single framebuf\n");
            goto err1;
        }

        fb[src_fbid].myIndex = enc->src_fbid;
        fb[src_fbid].bufY = pfbpool[src_fbid]->addrY;
        fb[src_fbid].bufCb = pfbpool[src_fbid]->addrCb;
        fb[src_fbid].bufCr = pfbpool[src_fbid]->addrCr;
        fb[src_fbid].strideY = pfbpool[src_fbid]->strideY;
        fb[src_fbid].strideC = pfbpool[src_fbid]->strideC;
    }

    return 0;

  err1:
    for (i = 0; i < totalfb; i++) {
        framebuf_free(pfbpool[i]);
    }

    free(fb);
    free(pfbpool);
    return -1;
}