/*---------------------------------------------------------------------------
 * acc_i2c_set_base_address
 *
 * This routine sets the base address of the I2C bus
 *---------------------------------------------------------------------------
 */
unsigned short
acc_i2c_set_base_address(unsigned char busnum, short adr)
{
    unsigned short ab_base_addr;

    /* Get Super I/O Index and Data registers */
    if (!sio_set_index_data_reg())
        return (0);

    /* Configure LDN to current ACB */
    if (busnum == 1)
        sio_write_reg(LDN, ACB1_LDN);
    if (busnum == 2)
        sio_write_reg(LDN, ACB2_LDN);

    if (adr == -1) {
        /* Get ACCESS.bus base address */
        ab_base_addr = sio_read_reg(BASE_ADR_MSB_REG);
        ab_base_addr = ab_base_addr << 8;
        ab_base_addr |= sio_read_reg(BASE_ADR_LSB_REG);
        if (ab_base_addr != 0)
            return ab_base_addr;
        else
            adr = (busnum == 1 ? ACB1_BASE : ACB2_BASE);
    }

    /* Set ACCESS.bus base address */
    sio_write_reg(BASE_ADR_LSB_REG, (unsigned char) (adr & 0xFF));
    sio_write_reg(BASE_ADR_MSB_REG, (unsigned char) (adr >> 8));

    return adr;
}
Ejemplo n.º 2
0
static void fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool is_level)
{
	sio_write_reg(pdata, LDN, pdata->index);

	switch (pdata->pid) {
	case CHIP_ID_F81866:
		sio_write_mask_reg(pdata, F81866_FIFO_CTRL, F81866_IRQ_MODE1,
				   0);
		/* fall through */
	case CHIP_ID_F81865:
		sio_write_mask_reg(pdata, F81866_IRQ_MODE, F81866_IRQ_SHARE,
				   F81866_IRQ_SHARE);
		sio_write_mask_reg(pdata, F81866_IRQ_MODE, F81866_IRQ_MODE0,
				   is_level ? 0 : F81866_IRQ_MODE0);
		break;

	case CHIP_ID_F81216AD:
	case CHIP_ID_F81216H:
	case CHIP_ID_F81216:
		sio_write_mask_reg(pdata, FINTEK_IRQ_MODE, IRQ_SHARE,
				   IRQ_SHARE);
		sio_write_mask_reg(pdata, FINTEK_IRQ_MODE, IRQ_MODE_MASK,
				   is_level ? IRQ_LEVEL_LOW : IRQ_EDGE_HIGH);
		break;
	}
}
Ejemplo n.º 3
0
static int fintek_8250_rs485_config(struct uart_port *port,
			      struct serial_rs485 *rs485)
{
	uint8_t config = 0;
	struct fintek_8250 *pdata = port->private_data;

	if (!pdata)
		return -EINVAL;

	if (rs485->flags & SER_RS485_ENABLED)
		memset(rs485->padding, 0, sizeof(rs485->padding));
	else
		memset(rs485, 0, sizeof(*rs485));

	rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
			SER_RS485_RTS_AFTER_SEND;

	if (rs485->delay_rts_before_send) {
		rs485->delay_rts_before_send = 1;
		config |= TXW4C_IRA;
	}

	if (rs485->delay_rts_after_send) {
		rs485->delay_rts_after_send = 1;
		config |= RXW4C_IRA;
	}

	if ((!!(rs485->flags & SER_RS485_RTS_ON_SEND)) ==
			(!!(rs485->flags & SER_RS485_RTS_AFTER_SEND)))
		rs485->flags &= SER_RS485_ENABLED;
	else
		config |= RS485_URA;

	if (rs485->flags & SER_RS485_RTS_ON_SEND)
		config |= RTS_INVERT;

	if (fintek_8250_enter_key(pdata->base_port, pdata->key))
		return -EBUSY;

	sio_write_reg(pdata, LDN, pdata->index);
	sio_write_reg(pdata, RS485, config);
	fintek_8250_exit_key(pdata->base_port);

	port->rs485 = *rs485;

	return 0;
}
Ejemplo n.º 4
0
static void sio_write_mask_reg(struct fintek_8250 *pdata, u8 reg, u8 mask,
			       u8 data)
{
	u8 tmp;

	tmp = (sio_read_reg(pdata, reg) & ~mask) | (mask & data);
	sio_write_reg(pdata, reg, tmp);
}
Ejemplo n.º 5
0
static int probe_setup_port(struct fintek_8250 *pdata,
					struct uart_8250_port *uart)
{
	static const u16 addr[] = {0x4e, 0x2e};
	static const u8 keys[] = {0x77, 0xa0, 0x87, 0x67};
	struct irq_data *irq_data;
	bool level_mode = false;
	int i, j, k, min, max;

	for (i = 0; i < ARRAY_SIZE(addr); i++) {
		for (j = 0; j < ARRAY_SIZE(keys); j++) {
			pdata->base_port = addr[i];
			pdata->key = keys[j];

			if (fintek_8250_enter_key(addr[i], keys[j]))
				continue;
			if (fintek_8250_check_id(pdata) ||
			    fintek_8250_get_ldn_range(pdata, &min, &max)) {
				fintek_8250_exit_key(addr[i]);
				continue;
			}

			for (k = min; k < max; k++) {
				u16 aux;

				sio_write_reg(pdata, LDN, k);
				aux = sio_read_reg(pdata, IO_ADDR1);
				aux |= sio_read_reg(pdata, IO_ADDR2) << 8;
				if (aux != uart->port.iobase)
					continue;

				pdata->index = k;

				irq_data = irq_get_irq_data(uart->port.irq);
				if (irq_data)
					level_mode =
						irqd_is_level_type(irq_data);

				fintek_8250_set_irq_mode(pdata, level_mode);
				fintek_8250_set_max_fifo(pdata);
				fintek_8250_goto_highspeed(uart, pdata);

				fintek_8250_exit_key(addr[i]);

				return 0;
			}

			fintek_8250_exit_key(addr[i]);
		}
	}

	return -ENODEV;
}
Ejemplo n.º 6
0
static void fintek_8250_goto_highspeed(struct uart_8250_port *uart,
			      struct fintek_8250 *pdata)
{
	sio_write_reg(pdata, LDN, pdata->index);

	switch (pdata->pid) {
	case CHIP_ID_F81866: /* set uart clock for high speed serial mode */
		sio_write_mask_reg(pdata, F81866_UART_CLK,
			F81866_UART_CLK_MASK,
			F81866_UART_CLK_14_769MHZ);

			uart->port.uartclk = 921600 * 16;
		break;
	default: /* leave clock speed untouched */
		break;
	}
}
Ejemplo n.º 7
0
void vgatv_tvout_mode(unsigned long tvout_mode)
{
	unsigned long cr;
	
	sio_read_reg(SIO_CR, &cr);

	// set requested mode
	switch (tvout_mode)
	{
		case FS460_TVOUT_MODE_CVBS_YC:
			cr &= ~SIO_CR_OFMT;
		break;

		case FS460_TVOUT_MODE_RGB:
			cr |= SIO_CR_OFMT;
		break;
	}

	sio_write_reg(SIO_CR, cr);
}
Ejemplo n.º 8
0
void vgatv_nco(unsigned long tv_std, unsigned long vga_mode, int use_nco)
{
	unsigned long cr, misc;
	int m, n;
	unsigned long ncon, ncod;
	int k;
	
	k = map_tvstd_to_index(tv_std);

	// initialize m, n to make compiler happy
	m = 512;
	n = 128;

	// if M/N mode is selected, make sure it's attainable
	if (!use_nco)
	{
		if ((g_specs.vga_htotal <= 0) || (g_specs.vga_vtotal <= 0))
			use_nco = 1;
		else
		{
			m = g_specs.vga_vtotal;
			if ((m < 500) || (m > 1200))
				use_nco = 1;

			n = g_specs.tv_htotal * g_specs.tv_vtotal / g_specs.vga_htotal;

			if (g_specs.tv_htotal * g_specs.tv_vtotal != (n * g_specs.vga_htotal))
				use_nco = 1;
		}
	}

	// read and store CR.
	sio_read_reg(SIO_CR, &cr);

	// make sure NCO_EN (enable latch) bit is clear
	cr &= ~SIO_CR_NCO_EN;
	sio_write_reg(SIO_CR, cr);

	// clear NCO_LOADX.
	sio_read_reg(SIO_MISC, &misc);
	misc &= ~(SIO_MISC_NCO_LOAD1 + SIO_MISC_NCO_LOAD0);
	sio_write_reg(SIO_MISC, misc);

 	if (use_nco)
	{
		if (FS460_VGA_MODE_1024X768 == vga_mode)
		{
			// setup for M and N load (Nco_load=1).
			misc |= (SIO_MISC_NCO_LOAD0);
			sio_write_reg(SIO_MISC, misc);

			// M and N.
			sio_write_reg(SIO_NCONL, 1024-2);
			sio_write_reg(SIO_NCODL, 128-1);

			// latch M/N in.
			cr |= SIO_CR_NCO_EN;
			sio_write_reg(SIO_CR, cr);
			cr &= ~SIO_CR_NCO_EN;
			sio_write_reg(SIO_CR, cr);
			
			// setup ncon and ncod load (Nco_load=0).
			misc &= ~(SIO_MISC_NCO_LOAD1 + SIO_MISC_NCO_LOAD0);
			sio_write_reg(SIO_MISC, misc);

			// NCON
			ncon = (unsigned long)g_specs.vga_vtotal * g_specs.vga_htotal / 2;
			sio_write_reg(SIO_NCONH, ncon >> 16);
			sio_write_reg(SIO_NCONL, ncon & 0xffff);

			// NCOD
			ncod = (unsigned long)g_specs.tv_vtotal * g_specs.vga_htotal * 4;
			sio_write_reg(SIO_NCODH, ncod >> 16);
			sio_write_reg(SIO_NCODL, ncod & 0xffff);
		}
		else
		{
Ejemplo n.º 9
0
void vgatv_position(
	unsigned long tv_std,
	unsigned long vga_mode,
	int left,
	int top,
	int width,
	int height)
{
	int k;
	unsigned int vga_index;
	unsigned long vsc;
	unsigned short ffolat;
	int vga_pixels,pre_pixels;
	int hscale_256ths;
	int hsc;
	int iho, ivo, ihw;
	int limit;

	// basic minimums
	if (width < 100)
		width = 100;
	if (height < 100)
		height = 100;

	// tv_std is valid.
	k = map_tvstd_to_index(tv_std);

	// store tv width and lines
	g_specs.tv_htotal = tvsetup.tv_width[k];
	g_specs.tv_vtotal = tvsetup.tv_lines[k];

	// determine vga mode index
	for (vga_index = 0; vga_index < sizeof(scantable) / sizeof(*scantable); vga_index++)
	{
		if (scantable[vga_index].mode == vga_mode)
			break;
	}
	if (vga_index >= sizeof(scantable) / sizeof(*scantable))
		return;

	// vga pixels is vga width, except in 1024x768, where it's half that.
	vga_pixels = g_specs.vga_hactive;
	if (1024 == vga_pixels)
		vga_pixels /= 2;

	if (g_specs.vga_vtotal_specified)
	{
		// use the provided vtotal
		g_specs.vga_vtotal = g_specs.vga_vtotal_specified;
	}
	else
	{
		// calculate vga vtotal based on requested height
		// vga v_total is (vga vactive) * (tv vtotal) / (user-selected height)
		// this also sets vertical scaling
		g_specs.vga_vtotal = ((2 * g_specs.vga_vactive * g_specs.tv_vtotal / height) + 1) / 2;
	}

	// limit vga_vtotal to slightly less than twice tv_vtotal, to limit scaling to slightly more than 1/2
	if (g_specs.vga_vtotal > 2 * g_specs.tv_vtotal - 10)
		g_specs.vga_vtotal = 2 * g_specs.tv_vtotal - 10;
	// minimum ten lines of vertical blank in VGA
	if (g_specs.vga_vtotal < g_specs.vga_vactive + 10)
		g_specs.vga_vtotal = g_specs.vga_vactive + 10;

	// vertical upscaling not supported
	if (g_specs.vga_vtotal < g_specs.tv_vtotal)
		g_specs.vga_vtotal = g_specs.tv_vtotal;

	TRACE((
		"vga hactive is %u, vactive is %u, htotal is %u, vtotal is %u\n",
		g_specs.vga_hactive,
		g_specs.vga_vactive,
		g_specs.vga_htotal,
		g_specs.vga_vtotal))

	// place hsync halfway from vga_hactive to htotal, width 64
	// also make it even
	// (so that hsync is never within ten pixels of active video, htotal must always exceed hactive by at least 84.)
	g_specs.vga_hsyncw = 64;
	g_specs.vga_hsync = (g_specs.vga_htotal + g_specs.vga_hactive - g_specs.vga_hsyncw) / 2;
	g_specs.vga_hsync &= ~1;

	// center v_sync halfway from vga_vactive to vga vtotal, height 2 lines
	g_specs.vga_vsyncw = 2;
	g_specs.vga_vsync = (g_specs.vga_vtotal + g_specs.vga_vactive - g_specs.vga_vsyncw) / 2;

	TRACE((
		"vga hsync is %u to %u, vsync is %u to %u.\n",
		g_specs.vga_hsync,
		g_specs.vga_hsync + g_specs.vga_hsyncw,
		g_specs.vga_vsync,
		g_specs.vga_vsync + g_specs.vga_vsyncw))

	// calculate vertical scaling based on ratio of vtotals
	vsc = 0xFFFF & ((0x10000 * g_specs.tv_vtotal / g_specs.vga_vtotal) - 0x10000);
	TRACE(("vsc = 0x%04x, tv_vtotal = %d, vga_vtotal = %d\n", vsc, g_specs.tv_vtotal, g_specs.vga_vtotal))
	sio_write_reg(SIO_VSC, (int)vsc);

	// calculate ivo
	ivo = calc_ivo(top, vsc);

	// range check
	if (ivo < 0)
		ivo = 0;

	// maximum ivo
	limit = (g_specs.vga_vtotal - g_specs.vga_vsync) + (g_specs.tv_vtotal - tvsetup.tv_active_lines[k]) * g_specs.vga_vtotal / g_specs.tv_vtotal;
	if (ivo > limit)
		ivo = limit;

	// program IVO
	sio_write_reg(SIO_IVO, ivo);

	// hscale
	hscale_256ths = (((2 * 256 * width) / vga_pixels) + 1) / 2;
	TRACE(("width is %u, hscale_256ths = %u\n",width, hscale_256ths))

	// determine hsc where hscale = (1 + hsc/128)
	hsc = ((hscale_256ths + 1) / 2) - 128;
	TRACE(("hsc = %d\n",hsc))
	if (hsc >= 0)
	{
		// maximum upscale is 0x7F, which is about double
		if (hsc > 0x7F)
			hsc = 0x7F;
		sio_write_reg(SIO_HSC, hsc << 8);
	}
	else
	{
		// minimum downscale is -63, which is just over 1/2
		if (hsc < -63)
			hsc = -63;
		sio_write_reg(SIO_HSC, 0xFF & hsc);
	}
			
	// recalculate hscale for future formulas
	hscale_256ths = 256 + (hsc * 2);
	TRACE(("recalculated hscale_256ths = %u\n",hscale_256ths))

	// iho is the number of VGA pixels to skip before starting active tv video
	// iho starts counting at the start of hsync
	// account for negative rounding
	iho = 2 * left * 256 / hscale_256ths;
	if (iho < 0)
		iho = (iho - 1) / 2;
	else
		iho = (iho + 1) / 2;
	iho = (g_specs.vga_htotal - g_specs.vga_hsync) * vga_pixels / g_specs.vga_hactive - iho;

	// range check
	if (iho < 0)
		iho = 0;
	if (iho > g_specs.vga_htotal - g_specs.vga_hsync + vga_pixels)
		iho = g_specs.vga_htotal - g_specs.vga_hsync + vga_pixels;

	// program IHO
	TRACE(("iho = %u\n",iho))
	sio_write_reg(SIO_IHO, iho);

	// input horizontal width.
	//
	// pre_pixels = (htotal - hsync) * (vga_pixels / vga_hactive)
	// input horizontal width is vga pixels + pre_pixels - iho
	// additionally, ihw cannot exceed tv width / hscale
	// and if hsc is negative, (ihw)(-hsc/128) cannot exceed ~250.
	// and ihw should be even.
	pre_pixels = (int)((long)(g_specs.vga_htotal - g_specs.vga_hsync) * vga_pixels / g_specs.vga_hactive);
	ihw = min((vga_pixels + pre_pixels - iho),(720 * 256 / hscale_256ths));
	if (hsc < 0)
		ihw = (int)min(ihw,252L * 128 / (-hsc));
	ihw &= ~1;
	TRACE(("ihw = %u\n",ihw))
	sio_write_reg(SIO_IHW, ihw);

	// FIFO latency must advance with IVO in order to keep up with the scaler.
	// The amount to advance with each line is proportional to the inverse of the fraction
	// of the line taken by the scaler.  Offsetting ivo by 2 makes the line drop logic work out
	// right.
	// If the next higher IVO was promoted because it would be skipped, then the
	// FIFO latency for this IVO should be calculated as IVO+1.  I don't know why,
	// it just does.
	// There appears to be a fudge factor proportional to the scaling.  Again, I don't know why.
	// There is also an adjustment for horizontal position, related to IHO and HSC.  The equation
	// uses left instead of IHO because it was already tuned for left=40.  Probably some of
	// the fudge factor could be explained away by using IHO directly.
	// If VSC is 0, this equation blows up.  At this condition FIFO latency is not really
	// relevant anyway, so just program an intermediate value like 0x40.
	{
		int use_ivo;

		if (vsc)
		{
			if ((0xFFFF & ((ivo + 1) * (0x10000 - vsc))) > (0xFFFF & ((ivo + 2) * (0x10000 - vsc))))
				use_ivo = ivo + 1;
			else
				use_ivo = ivo;

			ffolat = (unsigned short)(62 - ((0x10000 - vsc) / 305) +
				(720 * (0x7F & ((use_ivo + 2) * (0x10000 - vsc) / 512)) / 858) -
				((left - 40) * 256 / hscale_256ths / 4));
		}
		else
		{
			ffolat = 0x40;
		}
		TRACE(("FFOLAT = %u\n", ffolat))
		sio_write_reg(SIO_FFO_LAT, ffolat);
	}

	TRACE(("freq=%ukHz\n",g_specs.vga_htotal * g_specs.vga_vtotal * 27000 / g_specs.tv_htotal / g_specs.tv_vtotal))
}
Ejemplo n.º 10
0
void vgatv_tv_std(unsigned long tv_std, unsigned int cp_trigger_bits)
{
	int k;
	unsigned short reg34;
	unsigned long cr, w;
	unsigned long l;

	// verify supported standard.
	k = map_tvstd_to_index(tv_std);
	if (k < 0)
		return;

	// store tv width and lines
	g_specs.tv_htotal = tvsetup.tv_width[k];
	g_specs.tv_vtotal = tvsetup.tv_lines[k];

	// set PAL or NTSC in CR register
	sio_read_reg(SIO_CR, &cr);
	cr &= ~SIO_CR_656_PAL_NTSC;
	cr |= tvsetup.cr[k];
	sio_write_reg(SIO_CR, cr);

	// setup the encoder.
	l = tvsetup.chroma_freq[k];
	enc_write_reg(ENC_CHROMA_FREQ, (int)(l & 0x00ff));
	enc_write_reg(ENC_CHROMA_FREQ+1, (int)((l>>8) & 0x00ff));
	enc_write_reg(ENC_CHROMA_FREQ+2, (int)((l>>16) & 0x00ff));
	enc_write_reg(ENC_CHROMA_FREQ+3, (int)((l>>24) & 0x00ff));

	enc_write_reg(ENC_CHROMA_PHASE, tvsetup.chroma_phase[k]);
	enc_write_reg(ENC_REG05, 0x00);		// reg 0x05
	enc_write_reg(ENC_REG06, 0x89);		// reg 0x06
	enc_write_reg(ENC_REG07, 0x00);		// reg 0x07
	enc_write_reg(ENC_HSYNCWIDTH, tvsetup.hsync_width[k]);
	enc_write_reg(ENC_BURSTWIDTH, tvsetup.burst_width[k]);
	enc_write_reg(ENC_BACKPORCH, tvsetup.back_porch[k]);
	enc_write_reg(ENC_CB_BURSTLEVEL, tvsetup.cb_burst_level[k]);
	enc_write_reg(ENC_CR_BURSTLEVEL, tvsetup.cr_burst_level[k]);
	enc_write_reg(ENC_SLAVEMODE, 0x01);	// slave mode
	if (cp_trigger_bits == 0)
		w = w10bit2z(tvsetup.blank_level[k]);
	else
		w = w10bit2z((unsigned short)(tvsetup.blank_level[k]-tvsetup.hamp_offset[k]));
	enc_write_reg(ENC_BLANKLEVEL, w & 0x00ff);
	enc_write_reg(ENC_BLANKLEVEL+1, w >> 8);

	enc_write_reg(ENC_TINT, 0x00);			// tint
	enc_write_reg(ENC_BREEZEWAY, tvsetup.breeze_way[k]);
	enc_write_reg(ENC_FRONTPORCH, tvsetup.front_porch[k]);
	enc_write_reg(ENC_FIRSTVIDEOLINE, tvsetup.firstline[k]);	// firstvideoline
	reg34 =
		(tvsetup.pal_mode[k] << 6) |
		(tvsetup.sys625_50[k] << 4) |
		(tvsetup.sys625_50[k] << 3) |
		(tvsetup.cphase_rst[k] << 1) |
		(tvsetup.vsync5[k]);
	enc_write_reg(ENC_REG34, reg34);		// reg 0x34
	enc_write_reg(ENC_SYNCLEVEL, tvsetup.sync_level[k]);
	if (cp_trigger_bits == 0)
		w = w10bit2z(tvsetup.vbi_blank_level[k]);
	else
		w = w10bit2z((unsigned short)(tvsetup.vbi_blank_level[k]-1));
	enc_write_reg(ENC_VBI_BLANKLEVEL, w & 0x00ff);
	enc_write_reg(ENC_VBI_BLANKLEVEL+1, w >> 8);
}
Ejemplo n.º 11
0
void vgatv_vga_mode(unsigned long vga_mode, unsigned long tv_std, int htotal, int vtotal)
{
	static struct
	{
		 unsigned long mode;
		int	width;
		int lines;
	} vgaparams[] =
	{
		{FS460_VGA_MODE_640X480, 640, 480},
		{FS460_VGA_MODE_720X487, 720, 480},
		{FS460_VGA_MODE_720X576, 720, 576},
		{FS460_VGA_MODE_800X600, 800, 600},
		{FS460_VGA_MODE_1024X768, 1024, 768},
	};

	unsigned long cr, misc, byp;
	unsigned int i;

	g_specs.vga_hactive = 0;
	g_specs.vga_vactive = 0;
	g_specs.vga_htotal = 0;
	g_specs.vga_hdiv = 1;

	for (i = 0; i < sizeof(vgaparams) / sizeof(*vgaparams); i++)
	{
		if (vga_mode == vgaparams[i].mode)
		{
			g_specs.vga_hactive = vgaparams[i].width;
			g_specs.vga_vactive = vgaparams[i].lines;

			get_vga_htotal(vga_mode, tv_std);

			// override if specified
			if (htotal)
				g_specs.vga_htotal = htotal;
			g_specs.vga_vtotal_specified = vtotal;
			if (vtotal)
				g_specs.vga_vtotal = vtotal;

			// set divisor for div2 mode
			switch(vga_mode)
			{
				case FS460_VGA_MODE_1024X768:
					g_specs.vga_hdiv = 2;
				break;
			}

			break;
		}
	}
	if (!g_specs.vga_hactive)
		return;

	// clock mux decimator and vga dual.
	sio_read_reg(SIO_CR, &cr);
	sio_read_reg(SIO_MISC, &misc);
	sio_read_reg(SIO_BYP, &byp);

	if (vga_mode == FS460_VGA_MODE_1024X768)
	{
		// XGA
		cr |= SIO_CR_UIM_DEC;
		misc |= SIO_MISC_VGACKDIV;
		byp |= (SIO_BYP_HDS | SIO_BYP_CAC);
	}
	else
	{
		// VGA,SVGA
		cr &= ~SIO_CR_UIM_DEC;
		misc &= ~SIO_MISC_VGACKDIV;
		byp &= ~(SIO_BYP_HDS | SIO_BYP_CAC);
	}

	sio_write_reg(SIO_CR, cr);
	sio_write_reg(SIO_MISC, misc);
	sio_write_reg(SIO_BYP, byp);
}