Exemplo n.º 1
0
void WriteSeqReg(uint8 index, uint8 value)
{
    if (gInfo.sharedInfo->chipType == S3_TRIO64) {
        WritePIO_8(0x3c4, index);
        WritePIO_8(0x3c5, value);
    } else {
        OUTREG8(0x83c4, index);
        OUTREG8(0x83c5, value);
    }
}
Exemplo n.º 2
0
void WriteSeqReg(uint8 index, uint8 value, uint8 mask)
{
    // Write a value to a Sequencer reg using a mask.  The mask selects the
    // bits to be modified.

    if (gInfo.sharedInfo->chipType == S3_TRIO64) {
        WritePIO_8(0x3c4, index);
        WritePIO_8(0x3c5, (ReadPIO_8(0x3c5) & ~mask) | (value & mask));
    } else {
        OUTREG8(0x83c4, index);
        OUTREG8(0x83c5, (INREG8(0x83c5) & ~mask) | (value & mask));
    }
}
Exemplo n.º 3
0
status_t
Mach64_SetDisplayMode(const DisplayModeEx& mode)
{
	// The code to actually configure the display.
	// All the error checking must be done in ProposeDisplayMode(),
	// and assume that the mode values we get here are acceptable.

	SharedInfo& si = *gInfo.sharedInfo;

	if (si.displayType == MT_VGA) {
		// Chip is connected to a monitor via a VGA connector.

		SetCrtcRegisters(mode);
		SetClockRegisters(mode);

		if (si.chipType >= MACH64_264VTB)
			SetDSPRegisters(mode);

	} else {
		// Chip is connected to a laptop LCD monitor; or via a DVI interface.

		uint16 vesaMode = GetVesaModeNumber(display_mode(mode), mode.bitsPerPixel);
		if (vesaMode == 0)
			return B_BAD_VALUE;

		status_t status = ioctl(gInfo.deviceFileDesc, ATI_SET_VESA_DISPLAY_MODE,
				&vesaMode, sizeof(vesaMode));
		if (status != B_OK)
			return status;
	}

	Mach64_AdjustFrame(mode);

	// Initialize the palette so that the various color depths will display
	// the correct colors.

	OUTREGM(DAC_CNTL, DAC_8BIT_EN, DAC_8BIT_EN);
	OUTREG8(DAC_MASK, 0xff);
	OUTREG8(DAC_W_INDEX, 0);		// initial color index

	for (int i = 0; i < 256; i++) {
		OUTREG8(DAC_DATA, i);
		OUTREG8(DAC_DATA, i);
		OUTREG8(DAC_DATA, i);
	}

	Mach64_EngineInit(mode);

	return B_OK;
}
Exemplo n.º 4
0
//------------------------------------------------------------------------------
//
VOID OALTimerSetCount(UINT32 count)
{
    UINT32        retVal   = 0;
    UINT32        setDelay = 0;
    SH4_TMU_REGS *pTMURegs = OALPAtoUA(SH4_REG_PA_TMU);

    // Stop Timer
    OUTREG8(&pTMURegs->TSTR, INREG8(&pTMURegs->TSTR) & ~TMU_TSTR_STR0);

    // Update the count
    OUTREG32(&pTMURegs->TCNT0, count + setDelay - 1);

    // Start Timer
    OUTREG8(&pTMURegs->TSTR, INREG8(&pTMURegs->TSTR) | TMU_TSTR_STR0);
}
Exemplo n.º 5
0
//------------------------------------------------------------------------------
//
//  Function:  BSPIntrActiveIrq
//
//  This function is called from interrupt handler to give BSP chance to 
//  translate IRQ in case of secondary interrupt controller.
//
UINT32 BSPIntrActiveIrq(UINT32 irq)
{
    UINT8 data;
    UINT32 doneIrq;

    OALMSG(OAL_INTR&&OAL_VERBOSE, (L"+BSPIntrActiveIrq(%d)\r\n", irq));

    switch(irq)
    {
    case IRQ_GPIO:
        // Check whether alarm happen
        if(OALRTCAlarmIntrHandler() == FALSE) {
            irq = OAL_INTR_IRQ_UNDEFINED;
        }
        // Acknowledge GPIO interrupt
        OUTREG32(&g_pVRC5477Regs->GIUINSTAT, 0xffffffff);
        // Re-enable IRQ_GPIO interrupt on VRC5477
        doneIrq = IRQ_GPIO;
        OALIntrDoneIrqs(1, &doneIrq);
        break;
    case IRQ_INTC:
        // Read PIC1 interrupt
        OUTREG8(&g_pPIC1Regs->ctrl, 0x0E);
        data = INREG8(&g_pPIC1Regs->data) & 0x07;
        if (data != 2) {
            irq = IRQ_PIC_0 + data;
            SETREG8(&g_pPIC1Regs->mask, 1 << data);
        } else {
            // Read PIC2 interrupt
            OUTREG8(&g_pPIC2Regs->ctrl, 0x0E);
            data = INREG8(&g_pPIC2Regs->data) & 0x07;
            irq = IRQ_PIC_8 + data;
            SETREG8(&g_pPIC2Regs->mask, 1 << data);
            // End interrupt on PIC2
            OUTREG8(&g_pPIC2Regs->ctrl, 0x20);
        }
        // End interrupt on PIC1
        OUTREG8(&g_pPIC1Regs->ctrl, 0x20);

        // Re-enable IRQ_INTC interrupt on VRC5477
        doneIrq = IRQ_INTC;
        OALIntrDoneIrqs(1, &doneIrq);
        break;
    }

    OALMSG(OAL_INTR&&OAL_VERBOSE, (L"-BSPIntrActiveIrq(%d)\r\n", irq));
    return irq;
}
Exemplo n.º 6
0
//------------------------------------------------------------------------------
//
//  Function:  OALIntrEnableIrq/BSPIntrEnableIrq
//
//  This function enable interrupt identified by IRQ. If implementation uses
//  platform callbacks it will call BSPIntrEnableIrq before IRQ is enabled in
//  hardware. The BSPIntrEnableIrq returns IRQ used for interrupt controller
//  chaining.
//
BOOL OALIntrEnableIrqs(UINT32 count, const UINT32 *pIrqs)
{
    UINT32           irq, i;
    BOOL             retVal     = TRUE;
    SH4_RTC_REGS *pRTCRegs = OALPAtoUA(SH4_REG_PA_RTC);
    OALMSG(OAL_INTR&&OAL_VERBOSE, (L"+OALIntrEnableIrqs(%d, 0x%08x)\r\n", count, pIrqs));

    for(i = 0; i < count; i++)
    {
#ifndef OAL_BSP_CALLBACKS
        irq = pIrqs[i];
#else
        // Give the BSP a chance to enable the irq
        irq = BSPIntrEnableIrq(pIrqs[i]);
#endif
        if(irq == OAL_INTR_IRQ_UNDEFINED) continue;

        switch(irq)
        {
        case IRQ_RTC_ATI:
            OUTREG8(&pRTCRegs->RCR1, INREG8(&pRTCRegs->RCR1) | RTC_RCR1_AIE);
            OALMSG(OAL_INTR&&OAL_VERBOSE, (L"INFO: IRQ_RTC_ATI Enabled\r\n"));
            break;

        default:
            OALMSG(OAL_ERROR, (L"ERROR: Unable to enable IRQ %d\r\n", irq));
            retVal = FALSE;
        }
    }

    OALMSG(OAL_INTR&&OAL_VERBOSE, (L"-OALIntrEnableIrqs(rc = %d)\r\n", retVal));
    return retVal;
}
Exemplo n.º 7
0
void WriteReg8(uint32 addr, uint8 value)
{
    if (gInfo.sharedInfo->chipType == S3_TRIO64)
        WritePIO(addr, 1, value);
    else
        OUTREG8(addr, value);
}
Exemplo n.º 8
0
//------------------------------------------------------------------------------
//
//  Function:  OALIntrDisableIrq/BSPIntrDisableIrq
//
//  This function disable interrupt identified by IRQ. If implementation uses
//  platform callbacks it will call BSPIntrDisableIrq before IRQ is disabled in
//  hardware. The BSPIntrEnableIrq returns IRQ used for interrupt controller
//  chaining if it is suitable to disable it.
//
VOID OALIntrDisableIrqs(UINT32 count, const UINT32 *pIrqs)
{
    UINT32 irq, i;
    SH4_RTC_REGS *pRTCRegs = OALPAtoUA(SH4_REG_PA_RTC);
    OALMSG(OAL_INTR&&OAL_VERBOSE, (L"+OALIntrDisableIrqs(%d, 0x%08x)\r\n", count, pIrqs));

    for(i = 0; i < count; i++)
    {
#ifndef OAL_BSP_CALLBACKS
        irq = pIrqs[i];
#else
        irq = BSPIntrDisableIrq(pIrqs[i]);
#endif
        if(irq == OAL_INTR_IRQ_UNDEFINED) continue;

        switch(irq)
        {
        case IRQ_RTC_ATI:
            OUTREG8(&pRTCRegs->RCR1, INREG8(&pRTCRegs->RCR1) & ~RTC_RCR1_AIE);
            OALMSG(OAL_INTR&&OAL_VERBOSE, (L"INFO: IRQ_RTC_ATI Disabled\r\n"));
            break;

        default:
            OALMSG(OAL_ERROR, (L"ERROR: Unable to disable IRQ %d\r\n", irq));
        }
    }

    OALMSG(OAL_INTR&&OAL_VERBOSE, (L"-OALIntrDisableIrqs()\r\n"));
}
Exemplo n.º 9
0
void WriteMiscOutReg(uint8 value)
{
    if (gInfo.sharedInfo->chipType == S3_TRIO64)
        WritePIO_8(0x3c2, value);
    else
        OUTREG8(0x83c2, value);
}
Exemplo n.º 10
0
//------------------------------------------------------------------------------
//
//  Function:  OALIntrDoneIrq/BSPIntrDoneIrq
//
//  This function finish interrupt identified by IRQ. If implementation uses
//  platform callbacks it will call BSPIntrDoneIrq before IRQ is enabled in
//  hardware. The BSPIntrDoneIrq returns IRQ used for interrupt controller
//  chaining if it is suitable to finish it. In most cases implementation will
//  for both function will be similar to OALIntrEnableIrq/BSPIntrEnableIrq.
//
VOID OALIntrDoneIrqs(UINT32 count, const UINT32 *pIrqs)
{
    UINT32 irq, i;
    SH4_RTC_REGS *pRTCRegs = OALPAtoUA(SH4_REG_PA_RTC);

    OALMSG(OAL_VERBOSE&&OAL_FUNC, (L"+OALIntrDoneIrqs(%d, 0x%08x)\r\n", count, pIrqs));

    for(i = 0; i < count; i++)
    {
#ifndef OAL_BSP_CALLBACKS
        irq = pIrqs[i];
#else
        irq = BSPIntrDoneIrq(pIrqs[i]);
#endif
        if(irq == OAL_INTR_IRQ_UNDEFINED) continue;

        switch(irq)
        {
        case IRQ_RTC_ATI:
            // Clear alarm flag but do not reenable interrupt for the RTC Alarm
            // since that will happen the next time OEMSetAlarmTime is called
            OUTREG8(&pRTCRegs->RCR1, (INREG8(&pRTCRegs->RCR1) & ~(RTC_RCR1_AF)));
            break;

        default:
            OALMSG(OAL_ERROR, (L"ERROR: Unable to disable IRQ %d\r\n", irq));
        }
    }

    OALMSG(OAL_VERBOSE&&OAL_FUNC, (L"-OALIntrDoneIrqs()\r\n"));
}
Exemplo n.º 11
0
void serial_setbrg (void)
{	
	unsigned short UART_DIVISOR_LATCH = DEVICE_CLOCK / 16 / DEBUG_UART_BAUDRATE;
	SETREG8( (DEBUG_UART_BASE + UART_ULCR_OFFSET), ULCR_DLAB );	
	OUTREG8( (DEBUG_UART_BASE + UART_UDLLR_OFFSET), UART_DIVISOR_LATCH & 0xFF );
	OUTREG8( (DEBUG_UART_BASE + UART_UDLHR_OFFSET), (UART_DIVISOR_LATCH >> 8) & 0xFF );
	CLRREG8( (DEBUG_UART_BASE + UART_ULCR_OFFSET), ULCR_DLAB );
}
Exemplo n.º 12
0
void serial_putc (const char c)
{
#if 1
	if (c == '\n') serial_putc ('\r');
	/* Wait for fifo to shift out some bytes */
	while ( !(INREG8((DEBUG_UART_BASE + UART_ULSR_OFFSET))&ULSR_TDRQ ) );
	OUTREG8((DEBUG_UART_BASE + UART_UTHR_OFFSET), c); 	
#endif
}
Exemplo n.º 13
0
//------------------------------------------------------------------------------
//
//  Function:  OEMWriteDebugByte
//
//  Write byte to debug serial port.
//
VOID OEMWriteDebugByte(UINT8 ch)
{
    VRC5477_REGS *pVRC5477Regs = OALPAtoUA(VRC5477_REG_PA);

    // wait FIFO empty
    while (!(INREG8(&pVRC5477Regs->UARTLSR0) & UART_LSR_THRE));
    // send
    OUTREG8(&pVRC5477Regs->UARTTHR0, ch);
}
/*
 * This routine could be implemented by taking the addresses
 * written to the GATT, and flushing them individually.  However
 * currently it just flushes the whole table.  Which is probably
 * more efficent, since agp_memory blocks can be a large number of
 * entries.
 */
static void serverworks_tlbflush(struct agp_memory *temp)
{
	OUTREG8(serverworks_private.registers, SVWRKS_POSTFLUSH, 1);
	while(INREG8(serverworks_private.registers, SVWRKS_POSTFLUSH) == 1)
		cpu_relax();

	OUTREG32(serverworks_private.registers, SVWRKS_DIRFLUSH, 1);
	while(INREG32(serverworks_private.registers, SVWRKS_DIRFLUSH) == 1)
		cpu_relax();
}
Exemplo n.º 15
0
uint8 ReadSeqReg(uint8 index)
{
    if (gInfo.sharedInfo->chipType == S3_TRIO64) {
        WritePIO_8(0x3c4, index);
        return ReadPIO_8(0x3c5);
    }

    OUTREG8(0x83c4, index);
    return INREG8(0x83c5);
}
Exemplo n.º 16
0
//------------------------------------------------------------------------------
// Start timer 2 (parameter - interrupt interval in micro-seconds)
//------------------------------------------------------------------------------
void SHxStartTimer2 (DWORD dwUSec)
{
    DWORD dwCount;
    volatile SH4_TMU_REGS *pTMURegs = OALPAtoUA(SH4_REG_PA_TMU);    

    if (!dwUSec) {
        //
        // Use default rate (1 MS)
        //
        dwUSec = 1000;

    } else if (dwUSec < 20) {
        //
        // Rate specified: at least 20us
        //
        dwUSec = 20;
    }
    
    dwCount = (dwUSec * g_oalTimer.countsPerMSec) / 1000;

    //
    // Init timer2 and enable timer2 interrupt
    //

    // make sure timer2 is topped
    OUTREG8(&pTMURegs->TSTR, INREG8(&pTMURegs->TSTR) & ~TMU_TSTR_STR2);

    // initialize timer constant and count register
    OUTREG32(&pTMURegs->TCOR2, dwCount);
    OUTREG32(&pTMURegs->TCNT2, dwCount);

    // enable timer2 interrupts
    // Enable underflow interrupts
    OUTREG16(&pTMURegs->TCR2, INREG16(&pTMURegs->TCR2) | TMU_TCR_UNIE);
    // Clear any pending interrupts
    OUTREG16(&pTMURegs->TCR2, INREG16(&pTMURegs->TCR2) & ~TMU_TCR_UNF);

    // start timer2
    OUTREG8(&pTMURegs->TSTR, INREG8(&pTMURegs->TSTR) | TMU_TSTR_STR2);

}
Exemplo n.º 17
0
void
Mach64_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags)
{
	// Set the indexed color palette for 8-bit color depth mode.

	(void)flags;		// avoid compiler warning for unused arg

	if (gInfo.sharedInfo->displayMode.space != B_CMAP8)
		return ;

	OUTREG8(DAC_MASK, 0xff);
	OUTREG8(DAC_W_INDEX, first);		// initial color index

	while (count--) {
		OUTREG8(DAC_DATA, colorData[0]);	// red
		OUTREG8(DAC_DATA, colorData[1]);	// green
		OUTREG8(DAC_DATA, colorData[2]);	// blue

		colorData += 3;
	}
}
Exemplo n.º 18
0
status_t
Rage128_SetDisplayMode(const DisplayModeEx& mode)
{
	// The code to actually configure the display.
	// All the error checking must be done in ProposeDisplayMode(),
	// and assume that the mode values we get here are acceptable.

	DisplayParams params;		// where computed parameters are saved

	if (gInfo.sharedInfo->displayType == MT_VGA) {
		// Chip is connected to a monitor via a VGA connector.

		if ( ! CalculateCrtcRegisters(mode, params))
			return B_BAD_VALUE;

		if ( ! CalculatePLLRegisters(mode, params))
			return B_BAD_VALUE;

		if ( ! CalculateDDARegisters(mode, params))
			return B_BAD_VALUE;

		SetRegisters(params);

	} else {
		// Chip is connected to a laptop LCD monitor; or via a DVI interface.

		uint16 vesaMode = GetVesaModeNumber(display_mode(mode), mode.bitsPerPixel);
		if (vesaMode == 0)
			return B_BAD_VALUE;

		if (ioctl(gInfo.deviceFileDesc, ATI_SET_VESA_DISPLAY_MODE,
				&vesaMode, sizeof(vesaMode)) != B_OK)
			return B_ERROR;
	}

	Rage128_AdjustFrame(mode);

	// Initialize the palette so that color depths > 8 bits/pixel will display
	// the correct colors.

	// Select primary monitor and enable 8-bit color.
	OUTREGM(R128_DAC_CNTL, R128_DAC_8BIT_EN,
		R128_DAC_PALETTE_ACC_CTL | R128_DAC_8BIT_EN);
	OUTREG8(R128_PALETTE_INDEX, 0);		// set first color index

	for (int i = 0; i < 256; i++)
		OUTREG(R128_PALETTE_DATA, (i << 16) | (i << 8) | i );

	Rage128_EngineInit(mode);

	return B_OK;
}
Exemplo n.º 19
0
void WriteIndexedColor(uint8 index, uint8 red, uint8 green, uint8 blue)
{
    // Write an indexed color.  Argument index is the index (0-255) of the
    // color, and arguments red, green, & blue are the components of the color.

    // Note that although the Trio64V+ chip supports MMIO in nearly all areas,
    // it does not support MMIO for setting indexed colors;  thus, use PIO to
    // set the indexed color.

    if (gInfo.sharedInfo->chipType == S3_TRIO64
            || gInfo.sharedInfo->chipType == S3_TRIO64_VP) {
        WritePIO_8(0x3c8, index);	// color index
        WritePIO_8(0x3c9, red);
        WritePIO_8(0x3c9, green);
        WritePIO_8(0x3c9, blue);
    } else {
        OUTREG8(0x83c8, index);		// color index
        OUTREG8(0x83c9, red);
        OUTREG8(0x83c9, green);
        OUTREG8(0x83c9, blue);
    }
}
Exemplo n.º 20
0
//------------------------------------------------------------------------------
//
//  Function:  VRC5477Uart1Send
//
UINT16 VRC5477Uart1Send(UINT8 *pData, UINT16 size)
{
    VRC5477_REGS *pVRC5477Regs = OALPAtoUA(VRC5477_REG_PA);

    // This should not happen, but to be sure
    if (size == 0) return 0;
    // Wait FIFO empty
    while (!(INREG8(&pVRC5477Regs->UARTLSR1) & UART_LSR_THRE));
    // Send
    OUTREG8(&pVRC5477Regs->UARTTHR1, *pData);
    // We send only one char per call
    return 1;
}
Exemplo n.º 21
0
int serial_init (void)
{
	serial_setgpio();

	OUTREG8( (DEBUG_UART_BASE + UART_UIER_OFFSET), 0 );
	CLRREG8( (DEBUG_UART_BASE + UART_UFCR_OFFSET), UFCR_UME );	
	CLRREG8( (DEBUG_UART_BASE + UART_UISR_OFFSET), (UISR_RCVEIR|UISR_XMITIR) );
	SETREG8( (DEBUG_UART_BASE + UART_ULCR_OFFSET), (ULCR_WLS_8BITS|ULCR_SBLS_1BIT) );
	serial_setbrg();
	SETREG8( (DEBUG_UART_BASE + UART_UFCR_OFFSET), (UFCR_FME | UFCR_RFRT | UFCR_TFRT | UFCR_UME | UFCR_RDTR_15) );

	return 0;
}
Exemplo n.º 22
0
static int serverworks_configure(void)
{
	struct aper_size_info_lvl2 *current_size;
	u32 temp;
	u8 enable_reg;
	u16 cap_reg;

	current_size = A_SIZE_LVL2(agp_bridge->current_size);

	/* Get the memory mapped registers */
	pci_read_config_dword(agp_bridge->dev, serverworks_private.mm_addr_ofs, &temp);
	temp = (temp & PCI_BASE_ADDRESS_MEM_MASK);
	serverworks_private.registers = (volatile u8 *) ioremap(temp, 4096);
	if (!serverworks_private.registers) {
		printk (KERN_ERR PFX "Unable to ioremap() memory.\n");
		return -ENOMEM;
	}

	OUTREG8(serverworks_private.registers, SVWRKS_GART_CACHE, 0x0a);

	OUTREG32(serverworks_private.registers, SVWRKS_GATTBASE, 
		 agp_bridge->gatt_bus_addr);

	cap_reg = INREG16(serverworks_private.registers, SVWRKS_COMMAND);
	cap_reg &= ~0x0007;
	cap_reg |= 0x4;
	OUTREG16(serverworks_private.registers, SVWRKS_COMMAND, cap_reg);

	pci_read_config_byte(serverworks_private.svrwrks_dev,
			     SVWRKS_AGP_ENABLE, &enable_reg);
	enable_reg |= 0x1; /* Agp Enable bit */
	pci_write_config_byte(serverworks_private.svrwrks_dev,
			      SVWRKS_AGP_ENABLE, enable_reg);
	serverworks_tlbflush(NULL);

	agp_bridge->capndx = pci_find_capability(serverworks_private.svrwrks_dev, PCI_CAP_ID_AGP);

	/* Fill in the mode register */
	pci_read_config_dword(serverworks_private.svrwrks_dev,
			      agp_bridge->capndx+PCI_AGP_STATUS, &agp_bridge->mode);

	pci_read_config_byte(agp_bridge->dev, SVWRKS_CACHING, &enable_reg);
	enable_reg &= ~0x3;
	pci_write_config_byte(agp_bridge->dev, SVWRKS_CACHING, enable_reg);

	pci_read_config_byte(agp_bridge->dev, SVWRKS_FEATURE, &enable_reg);
	enable_reg |= (1<<6);
	pci_write_config_byte(agp_bridge->dev,SVWRKS_FEATURE, enable_reg);

	return 0;
}
Exemplo n.º 23
0
//------------------------------------------------------------------------------
//
//  Function:   VRC5477Uart1Init
//
//  Initialize debug serial port
//
BOOL VRC5477Uart1Init(KITL_SERIAL_INFO *pInfo)
{
    BOOL rc = FALSE;
    VRC5477_REGS *pVRC5477Regs = OALPAtoUA(VRC5477_REG_PA);
    UINT16 divider;
    UINT8 lcr;

    // Check if config paramters are supportable
    if (
        pInfo->baudRate < 9600 || pInfo->baudRate > 115200 ||
        pInfo->dataBits != 8 || pInfo->stopBits == 0 || pInfo->parity > 2
    ) goto cleanUp;

    // Input frequency is 1.8462MHz
    divider = (1846200/pInfo->baudRate + 7)/16;

    // Get LCR
    lcr = UART_LCR_8BIT;
    if (pInfo->stopBits > 1) lcr |= UART_LCR_2STP;
    if (pInfo->parity > 0) {
        lcr |= UART_LCR_PE;
        if (pInfo->parity > 1) lcr |= UART_LCR_EP;
    }
    
    // Disable interrupts
    OUTREG8(&pVRC5477Regs->UARTIER1, 0);

    // Set baud rate
    OUTREG8(&pVRC5477Regs->UARTLCR1, UART_LCR_DLAB);
    OUTREG8(&pVRC5477Regs->UARTDLL1, (UINT8)divider);
    OUTREG8(&pVRC5477Regs->UARTDLM1, (UINT8)(divider >> 8));

    // 8 bit, 1 stop bit, no parity
    OUTREG8(&pVRC5477Regs->UARTLCR1, lcr);

    // Enable&reset FIFOs
    OUTREG8(&pVRC5477Regs->UARTFCR1, UART_FCR_EN|UART_FCR_RRST|UART_FCR_TRST);

    // Set DTR&RTS signals
    OUTREG8(&pVRC5477Regs->UARTMCR1, UART_MCR_DTR|UART_MCR_RTS);

    // Clear comm errors
    INREG8(&pVRC5477Regs->UARTLSR1);

    // Best size is full KITL_MTU...
    pInfo->bestSize = KITL_MTU;

    // Done
    rc = TRUE;
    
cleanUp:
    return rc;
}
Exemplo n.º 24
0
void
Rage128_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags)
{
	// Set the indexed color palette for 8-bit color depth mode.

	(void)flags;		// avoid compiler warning for unused arg

	if (gInfo.sharedInfo->displayMode.space != B_CMAP8)
		return ;

	// Select primary monitor and enable 8-bit color.
	OUTREGM(R128_DAC_CNTL, R128_DAC_8BIT_EN,
		R128_DAC_PALETTE_ACC_CTL | R128_DAC_8BIT_EN);
	OUTREG8(R128_PALETTE_INDEX, first);		// set first color index

	while (count--) {
		OUTREG(R128_PALETTE_DATA, ((colorData[0] << 16)	// red
								 | (colorData[1] << 8)	// green
								 |  colorData[2]));		// blue
		colorData += 3;
	}
}
Exemplo n.º 25
0
/*
 * This routine could be implemented by taking the addresses
 * written to the GATT, and flushing them individually.  However
 * currently it just flushes the whole table.  Which is probably
 * more efficent, since agp_memory blocks can be a large number of
 * entries.
 */
static void serverworks_tlbflush(struct agp_memory *temp)
{
	unsigned long end;

	OUTREG8(serverworks_private.registers, SVWRKS_POSTFLUSH, 0x01);
	end = jiffies + 3*HZ;
	while(INREG8(serverworks_private.registers, 
		     SVWRKS_POSTFLUSH) == 0x01) {
		if((signed)(end - jiffies) <= 0) {
			printk(KERN_ERR PFX "Posted write buffer flush took more"
			       "then 3 seconds\n");
		}
	}
	OUTREG32(serverworks_private.registers, SVWRKS_DIRFLUSH, 0x00000001);
	end = jiffies + 3*HZ;
	while(INREG32(serverworks_private.registers, 
		     SVWRKS_DIRFLUSH) == 0x00000001) {
		if((signed)(end - jiffies) <= 0) {
			printk(KERN_ERR PFX "TLB flush took more"
			       "then 3 seconds\n");
		}
	}
}
Exemplo n.º 26
0
//------------------------------------------------------------------------------
//
//  Function:  VRC5477Uart1Recv
//
UINT16 VRC5477Uart1Recv(UINT8 *pData, UINT16 size)
{
    VRC5477_REGS *pVRC5477Regs = OALPAtoUA(VRC5477_REG_PA);
    UINT8 status;
    UINT16 count;

    count = 0;
    while (count < size) {
        // Get line status
        status = INREG8(&pVRC5477Regs->UARTLSR1);
        // If there ara no data, break loop
        if ((status & UART_LSR_DR) == 0) break;
        // On error clear FIFOs and break loop
        if ((status & 0x0E) != 0) {
            OUTREG8(&pVRC5477Regs->UARTFCR1, 0x07);
            count = 0;
            break;
        }
        // Get data
        *pData++ = INREG8(&pVRC5477Regs->UARTRBR1);
        count++;
    }        
    return count;
}
Exemplo n.º 27
0
//------------------------------------------------------------------------------
//
//  Function:  OEMInitDebugSerial
//
//  Initialize debug serial port
//
BOOL OEMDebugInit()
{
    VRC5477_REGS *pVRC5477Regs = OALPAtoUA(VRC5477_REG_PA);

    // Set baud rate
    OUTREG8(&pVRC5477Regs->UARTLCR0, UART_LCR_DLAB);
    OUTREG8(&pVRC5477Regs->UARTDLL0, BSP_UART_DSIUDLL);
    OUTREG8(&pVRC5477Regs->UARTDLM0, BSP_UART_DSIUDLM);

    // 8 bit, 1 stop bit, no parity
    OUTREG8(&pVRC5477Regs->UARTLCR0, UART_LCR_8BIT);

    // Enable FIFO
    OUTREG8(&pVRC5477Regs->UARTFCR0, UART_FCR_EN);

    // Pool
    OUTREG8(&pVRC5477Regs->UARTIER0, 0);

    // Set DTR/RTS signals
    OUTREG8(&pVRC5477Regs->UARTMCR0, UART_MCR_DTR|UART_MCR_RTS);

    return TRUE;
}
Exemplo n.º 28
0
static void SetClockRegisters(const DisplayModeEx& mode)
{
	SharedInfo& si = *gInfo.sharedInfo;
	M64_Params& params = si.m64Params;

	int p;
	int postDiv;
	bool extendedDiv = false;
	uint32 pixelClock = mode.timing.pixel_clock;

	if (pixelClock > params.maxPixelClock)
		pixelClock = params.maxPixelClock;

	double q = ((pixelClock / 10.0) * params.refDivider) / (2.0 * params.refFreq);

	if (si.chipType >= MACH64_264VTB) {
		if (q > 255) {
			TRACE("SetClockRegisters(): Warning: q > 255\n");
			q = 255;
			p = 0;
			postDiv = 1;
		} else if (q > 127.5) {
			p = 0;
			postDiv = 1;
		} else if (q > 85) {
			p = 1;
			postDiv = 2;
		} else if (q > 63.75) {
			p = 0;
			postDiv = 3;
			extendedDiv = true;
		} else if (q > 42.5) {
			p = 2;
			postDiv = 4;
		} else if (q > 31.875) {
			p = 2;
			postDiv = 6;
			extendedDiv = true;
		} else if (q > 21.25) {
			p = 3;
			postDiv = 8;
		} else if (q >= 10.6666666667) {
			p = 3;
			postDiv = 12;
			extendedDiv = true;
		} else {
			TRACE("SetClockRegisters(): Warning: q < 10.66666667\n");
			p = 3;
			postDiv = 12;
			extendedDiv = true;
		}
	} else {
		if (q > 255) {
			TRACE("SetClockRegisters(): Warning: q > 255\n");
			q = 255;
			p = 0;
		} else if (q > 127.5)
			p = 0;
		else if (q > 63.75)
			p = 1;
		else if (q > 31.875)
			p = 2;
		else if (q >= 16)
			p = 3;
		else {
			TRACE("SetClockRegisters(): Warning: q < 16\n");
			p = 3;
		}
		postDiv = 1 << p;
	}

	uint8 fbDiv = uint8(q * postDiv);

	// With some chips such as those with ID's 4750 & 475A, the display has
	// ripples when using resolution 1440x900 at 60 Hz refresh rate.
	// Decrementing fbDiv by 1 seems to fix this problem.

	if (mode.timing.h_display == 1440 && pixelClock < 108000)
		fbDiv--;

	int clkNum = params.clockNumberToProgram;

	OUTREG8(CLOCK_CNTL, clkNum | CLOCK_STROBE);

	// Temporarily switch to accelerator mode.
	uint32 crtc_gen_cntl = INREG(CRTC_GEN_CNTL);
	if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN))
		OUTREG(CRTC_GEN_CNTL, crtc_gen_cntl | CRTC_EXT_DISP_EN);

	// Reset VCLK generator.
	uint8 vclkCntl = Mach64_GetPLLReg(PLL_VCLK_CNTL);
	Mach64_SetPLLReg(PLL_VCLK_CNTL, vclkCntl | PLL_VCLK_RESET);

	// Set post-divider.
	uint8 tmp = Mach64_GetPLLReg(PLL_VCLK_POST_DIV);
	Mach64_SetPLLReg(PLL_VCLK_POST_DIV,
		(tmp & ~(0x03 << (2 * clkNum))) | (p << (2 * clkNum)));

	// Set feedback divider.
	Mach64_SetPLLReg(PLL_VCLK0_FB_DIV + clkNum, fbDiv);

	// Set extended post-divider.
	if (si.chipType >= MACH64_264VTB) {
		tmp = Mach64_GetPLLReg(PLL_XCLK_CNTL);
		if (extendedDiv)
			Mach64_SetPLLReg(PLL_XCLK_CNTL, tmp | (0x10 << clkNum));
		else
			Mach64_SetPLLReg(PLL_XCLK_CNTL, tmp & ~(0x10 << clkNum));
	}

	// End VCLK generator reset.
	Mach64_SetPLLReg(PLL_VCLK_CNTL, vclkCntl & ~PLL_VCLK_RESET);

	snooze(5000);
	INREG8(DAC_W_INDEX);    // Clear DAC counter

	if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN))
		OUTREG(CRTC_GEN_CNTL, crtc_gen_cntl);	// Restore register

	// Save parameters that will be used for computing the DSP parameters.

	params.vClkPostDivider = postDiv;
	params.vClkFeedbackDivider = fbDiv;

	return;
}
Exemplo n.º 29
0
//------------------------------------------------------------------------------
//
//  Function:  OALPCIInit
//
BOOL OALPCIInit()
{
    VRC5477_REGS *pVRC5477Regs = OALPAtoUA(VRC5477_REG_PA);
    M1535_CFG_REGS *pM1535Regs = OALPAtoUA(BSP_REG_PA_M1535_CFG);
    OAL_PCI_LOCATION pciLoc;
    UINT32 u32;

    //----------------------------------------------------------------------
    // External PCI
    //----------------------------------------------------------------------

    // Cold reset
    OUTREG32(&pVRC5477Regs->PCICTL0H, PCI_CTRL_CRST);
    OALStall(100000);
    OUTREG32(&pVRC5477Regs->PCICTL0H, 0);
    OALStall(100000);
    
    // Setup windows
    OUTREG32(&pVRC5477Regs->PCIINIT00, BSP_PCI_INIT00);
    OUTREG32(&pVRC5477Regs->PCIW0, BSP_PCI_W0);
    OUTREG32(&pVRC5477Regs->PCIINIT10, BSP_PCI_INIT10);
    OUTREG32(&pVRC5477Regs->PCIW1, BSP_PCI_W1);

    // Setup control & arbiter registers
    OUTREG32(&pVRC5477Regs->PCICTL0L, BSP_PCI_CTL0L);
    OUTREG32(&pVRC5477Regs->PCICTL0H, BSP_PCI_CTL0H);
    OUTREG32(&pVRC5477Regs->PCIARB0L, BSP_PCI_ARB0L);
    OUTREG32(&pVRC5477Regs->PCIARB0H, BSP_PCI_ARB0H);
        
    // Setup configuration space
    OUTREG16(&pVRC5477Regs->PCICMD0, BSP_PCI_CMD0);
    OUTREG8(&pVRC5477Regs->MLTIM0, BSP_PCI_MLTIM0);
    OUTREG32(&pVRC5477Regs->BARC0, BSP_PCI_BARC0);
    OUTREG32(&pVRC5477Regs->BARM010, BSP_PCI_BARM010);
    OUTREG32(&pVRC5477Regs->BARM230, BSP_PCI_BARM230);
    OUTREG32(&pVRC5477Regs->BAR00, BSP_PCI_BAR00);
    OUTREG32(&pVRC5477Regs->BAR10, BSP_PCI_BAR10);
    OUTREG32(&pVRC5477Regs->BAR20, BSP_PCI_BAR20);
    OUTREG32(&pVRC5477Regs->BARB0, BSP_PCI_BARB0);
    OUTREG32(&pVRC5477Regs->BARP00, BSP_PCI_BARP00);
    OUTREG32(&pVRC5477Regs->BARP10, BSP_PCI_BARP10);

    //----------------------------------------------------------------------
    // Internal PCI
    //----------------------------------------------------------------------

    OUTREG32(&pVRC5477Regs->PCICTL1H, PCI_CTRL_CRST);
    OALStall(100000);
    OUTREG32(&pVRC5477Regs->PCICTL1H, 0);
    OALStall(100000);

    // Setup internal PCI windows
    OUTREG32(&pVRC5477Regs->PCIINIT01, BSP_PCI_INIT01);
    OUTREG32(&pVRC5477Regs->IOPCIW0, BSP_IOPCI_W0);
    OUTREG32(&pVRC5477Regs->PCIINIT11, BSP_PCI_INIT11);
    OUTREG32(&pVRC5477Regs->IOPCIW1, BSP_IOPCI_W1);

    // Setup control & arbiter registers
    OUTREG32(&pVRC5477Regs->PCICTL1L, BSP_PCI_CTL1L);
    OUTREG32(&pVRC5477Regs->PCICTL1H, BSP_PCI_CTL1H);
    OUTREG32(&pVRC5477Regs->PCIARB1L, BSP_PCI_ARB1L);
    OUTREG32(&pVRC5477Regs->PCIARB1H, BSP_PCI_ARB1H);
    
    // Setup configuration space
    OUTREG16(&pVRC5477Regs->PCICMD1, BSP_PCI_CMD1);
    OUTREG8(&pVRC5477Regs->MLTIM1, BSP_PCI_MLTIM1);
    OUTREG32(&pVRC5477Regs->BARC1, BSP_PCI_BARC1);
    OUTREG32(&pVRC5477Regs->BARM011, BSP_PCI_BARM011);
    OUTREG32(&pVRC5477Regs->BARM231, BSP_PCI_BARM231);
    OUTREG32(&pVRC5477Regs->BAR01, BSP_PCI_BAR01);
    OUTREG32(&pVRC5477Regs->BAR11, BSP_PCI_BAR11);
    OUTREG32(&pVRC5477Regs->BAR21, BSP_PCI_BAR21);
    OUTREG32(&pVRC5477Regs->BARB1, BSP_PCI_BARB1);
    OUTREG32(&pVRC5477Regs->BARP01, BSP_PCI_BARP01);
    OUTREG32(&pVRC5477Regs->BARP11, BSP_PCI_BARP11);

    OALStall(10000);

    //----------------------------------------------------------------------
    // ALI M1535+ South Bridge
    //----------------------------------------------------------------------
    // Is there ALI M1535+ bridge = CPU board is inserted to SG2 mother board,
    // in such case we must do some initialization --- default config address
    // lines for some ALI M1535+ internal devices colide with PCI slot config
    // address lines.
    pciLoc.bus = 0;
    pciLoc.dev = 8;
    pciLoc.fnc = 0;
    OALPCICfgRead(0, pciLoc, 0, sizeof(u32), &u32);
    if (u32 != 0x153310B9) goto cleanUp;

    //----------------------------------------------------------------------
    // PCI-ISA bridge initialize
    //----------------------------------------------------------------------

    OALLog(L"INFO: OALPCIInit: ALI M1535+ Bridge detected\r\n");

    u32 = 0x0000C119;   // I/O control, select PS2 keyboad/mouse
    OALPCICfgWrite(0, pciLoc, 0x40, sizeof(u32), &u32);
    u32 = 0x0000025D;   // Primary IDE IRQ14
    OALPCICfgWrite(0, pciLoc, 0x44, sizeof(u32), &u32);
    u32 = 0x70000009;   // Audio->IRQ6, PCI INTC->IRQ11
    OALPCICfgWrite(0, pciLoc, 0x48, sizeof(u32), &u32);
    u32 = 0x00000000;   // USB1 enable
    OALPCICfgWrite(0, pciLoc, 0x50, sizeof(u32), &u32);
    u32 = 0x00000000;   // PCSJ
    OALPCICfgWrite(0, pciLoc, 0x54, sizeof(u32), &u32);
    u32 = 0x0000007C;   // IDE IDSEL(AD15), INTR
    OALPCICfgWrite(0, pciLoc, 0x58, sizeof(u32), &u32);
    u32 = 0x00004000;   // Document recommend???
    OALPCICfgWrite(0, pciLoc, 0x6C, sizeof(u32), &u32);
    u32 = 0x002600D2;   // PMU IDSEL(AD14), USB IDSEL(AD13)
    OALPCICfgWrite(0, pciLoc, 0x70, sizeof(u32), &u32);
    u32 = 0x40801F01;   // No modem, USB INTR(IRQ09), 2nd IDE IRQ15, AC97 IDSEL(AD17)
    OALPCICfgWrite(0, pciLoc, 0x74, sizeof(u32), &u32);
    u32 = 0x00000000;   // USB2 disable
    OALPCICfgWrite(0, pciLoc, 0x7C, sizeof(u32), &u32);

    //---------------------------
    // Configure super I/O chip
    //---------------------------
    
    OUTPORT8(&pM1535Regs->config, 0x51);    // Enter config mode
    OUTPORT8(&pM1535Regs->config, 0x23);    
    
    // Enable parallel port
    OUTPORT8(&pM1535Regs->index, 0x07);
    OUTPORT8(&pM1535Regs->data,  0x03);     // Select logical device 3
    OUTPORT8(&pM1535Regs->index, 0x30);
    OUTPORT8(&pM1535Regs->data,  0x01);     // Enable device
    OUTPORT8(&pM1535Regs->index, 0x60);
    OUTPORT8(&pM1535Regs->data,  0x03);     // I/O address: 378h
    OUTPORT8(&pM1535Regs->index, 0x61);
    OUTPORT8(&pM1535Regs->data,  0x78);     // I/O address: 378h
    OUTPORT8(&pM1535Regs->index, 0x70);
    OUTPORT8(&pM1535Regs->data,  0x07);     // Irq: 7
    
    // Enable UART1
    OUTPORT8(&pM1535Regs->index, 0x07);
    OUTPORT8(&pM1535Regs->data,  0x04);     // Select logical device 4
    OUTPORT8(&pM1535Regs->index, 0x30);
    OUTPORT8(&pM1535Regs->data,  0x01);     // Enable device
    OUTPORT8(&pM1535Regs->index, 0x60);
    OUTPORT8(&pM1535Regs->data,  0x03);     // I/O address: 3F8h
    OUTPORT8(&pM1535Regs->index, 0x61);
    OUTPORT8(&pM1535Regs->data,  0xF8);     // I/O address: 3F8h
    OUTPORT8(&pM1535Regs->index, 0x70);
    OUTPORT8(&pM1535Regs->data,  0x04);     // Irq: 4
    
    // Enable UART2/INFRA
    OUTPORT8(&pM1535Regs->index, 0x07);
    OUTPORT8(&pM1535Regs->data,  0x05);     // Select logical device 5
    OUTPORT8(&pM1535Regs->index, 0x30);
    OUTPORT8(&pM1535Regs->data,  0x01);     // Enable device
    OUTPORT8(&pM1535Regs->index, 0x60);
    OUTPORT8(&pM1535Regs->data,  0x03);     // I/O address: 3E8h
    OUTPORT8(&pM1535Regs->index, 0x61);
    OUTPORT8(&pM1535Regs->data,  0xE8);     // I/O address: 3E8h
    OUTPORT8(&pM1535Regs->index, 0x70);
    OUTPORT8(&pM1535Regs->data,  0x05);     // Irq: 5
    
    // Enable PS/2 controller
    OUTPORT8(&pM1535Regs->index, 0x07);
    OUTPORT8(&pM1535Regs->data,  0x07);     // Select logical device 7.
    OUTPORT8(&pM1535Regs->index, 0x30);
    OUTPORT8(&pM1535Regs->data,  0x01);     // Enable device
    OUTPORT8(&pM1535Regs->index, 0x70);
    OUTPORT8(&pM1535Regs->data,  0x01);     // Irq: 1 - keyboard
    OUTPORT8(&pM1535Regs->index, 0x72);
    OUTPORT8(&pM1535Regs->data,  0x0C);     // Irq: 12 - mouse
    
    // Enable UART3
    OUTPORT8(&pM1535Regs->index, 0x07);
    OUTPORT8(&pM1535Regs->data,  0x0B);     // Select logical device 11
    OUTPORT8(&pM1535Regs->index, 0x30);
    OUTPORT8(&pM1535Regs->data,  0x01);     // Enable device
    OUTPORT8(&pM1535Regs->index, 0x60);
    OUTPORT8(&pM1535Regs->data,  0x02);     // I/O address: 2F8h
    OUTPORT8(&pM1535Regs->index, 0x61);
    OUTPORT8(&pM1535Regs->data,  0xF8);     // I/O address: 2F8h
    OUTPORT8(&pM1535Regs->index, 0x70);
    OUTPORT8(&pM1535Regs->data,  0x03);     // Irq: 3
    
    // Exit config mode
    OUTPORT8(&pM1535Regs->config, 0xBB);
  
cleanUp:
    return TRUE;
}
Exemplo n.º 30
0
//------------------------------------------------------------------------------
//
//  Function:  BSPIntrInit
//
//  This function is called from OALIntrInit to initialize secondary interrupt
//  controller.
//
BOOL BSPIntrInit()
{
    UINT8 *pPIC1Edge, *pPIC2Edge;
    UINT32 irq;
    
    OALMSG(OAL_INTR&&OAL_FUNC, (L"+BSPIntrInit\r\n"));

    // Add static mapping for on chip devices...
    OALIntrStaticTranslate(SYSINTR_FIRMWARE + 0, IRQ_UART1);   // UART1

    // Add GPIO static mapping for RTC alarm
    OALIntrStaticTranslate(SYSINTR_RTC_ALARM, IRQ_GPIO);
    // And enable it (it will not occur until it is set in OEMSetAlarmTime)
    irq = IRQ_GPIO; OALIntrEnableIrqs(1, &irq);


    // Get and save uncached virtual addresses for VRC5477 and PIC1/PIC2
    g_pVRC5477Regs = OALPAtoUA(VRC5477_REG_PA);
    g_pPIC1Regs = OALPAtoUA(BSP_REG_PA_M1535_PIC1);
    g_pPIC2Regs = OALPAtoUA(BSP_REG_PA_M1535_PIC2);

    // M1535+ INTR uses positive logic (active on high), set VRC5477
    CLRPORT32(&g_pVRC5477Regs->INTPPES0, 1 << 4);

    // We have to enable PCI interrupts
    irq = IRQ_INTA; OALIntrEnableIrqs(1, &irq);
    irq = IRQ_INTB; OALIntrEnableIrqs(1, &irq);
    irq = IRQ_INTC; OALIntrEnableIrqs(1, &irq);
    irq = IRQ_INTD; OALIntrEnableIrqs(1, &irq);

    // PIC1/PIC2 edge registers are needed only for initialization
    pPIC1Edge = OALPAtoUA(BSP_REG_PA_M1535_EDGE1);
    pPIC2Edge = OALPAtoUA(BSP_REG_PA_M1535_EDGE2);
    
    // Initialize the 8259 PIC1
    OUTREG8(&g_pPIC1Regs->ctrl, 0x11);          // ICW1, cascade & ICW4
    OUTREG8(&g_pPIC1Regs->mask, IRQ_PIC_0);     // ICW2, vector to 32
    OUTREG8(&g_pPIC1Regs->mask, 0x04);          // ICW3, slave on IRQ 2
    OUTREG8(&g_pPIC1Regs->mask, 0x01);          // ICW4, normal EOI
    OUTREG8(&g_pPIC1Regs->ctrl, 0x0B);          // OCW2, read IS register
    OUTREG8(&g_pPIC1Regs->mask, 0xFF);          // OCW1, all disabled
    
    // Now initialize the 8259 PIC2
    OUTREG8(&g_pPIC2Regs->ctrl, 0x11);          // ICW1, cascade & ICW4
    OUTREG8(&g_pPIC2Regs->mask, IRQ_PIC_8);     // ICW2, vector to 40
    OUTREG8(&g_pPIC2Regs->mask, 0x02);          // ICW3, we are IRQ 2
    OUTREG8(&g_pPIC2Regs->mask, 0x01);          // ICW4, normal EOI
    OUTREG8(&g_pPIC2Regs->ctrl, 0x0B);          // OCW2, read IS register
    OUTREG8(&g_pPIC2Regs->mask, 0xFF);          // OCW1, all disabled

    // IRQ0-IRQ7 Edge sensitive(IRQ2 cannot be set to level sensitive)
    OUTREG8(pPIC1Edge, 0x00);

    // IRQ9&IRQ11 level (USB host, PCI INTC), other edge sensitive
    OUTREG8(pPIC2Edge, 0x0A);

    // Enable interrupt from PIC2 on PIC1
    CLRREG8(&g_pPIC1Regs->mask, 1 << 2);

    // Set static interrupt mappings for legacy devices
    
    OALIntrStaticTranslate(SYSINTR_FIRMWARE + 8, IRQ_PIC_1);    // keyboard
    OALIntrStaticTranslate(SYSINTR_FIRMWARE + 9, IRQ_PIC_12);   // mouse

    // We are done    
    OALMSG(OAL_INTR&&OAL_FUNC, (L"-BSPIntrInit(rc = 1)\r\n"));
    return TRUE;
}