/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.driver.video.ati.radeon;
import org.jnode.driver.video.vgahw.DisplayMode;
import org.jnode.util.NumberUtils;
/**
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
final class CrtcRegs implements RadeonConstants {
private final int crtcIndex;
private int crtc_h_total_disp;
private int crtc_h_sync_strt_wid;
private int crtc_v_total_disp;
private int crtc_v_sync_strt_wid;
private int crtc_pitch;
private int crtc_gen_cntl;
private int crtc_ext_cntl;
private int dac_cntl;
private int crtc_offset;
private int crtc_offset_cntl;
private int crtc_more_cntl;
/**
* Initialize this instance.
*
* @param crtcIndex
*/
public CrtcRegs(int crtcIndex) {
if ((crtcIndex < 0) || (crtcIndex > 1)) {
throw new IllegalArgumentException("Invalid crtcIndex");
}
this.crtcIndex = crtcIndex;
}
/**
* Initialize from a given IO.
*/
public void saveFromVGA(RadeonVgaIO io) {
if (crtcIndex == 0) {
this.crtc_gen_cntl = io.getReg32(CRTC_GEN_CNTL);
this.crtc_ext_cntl = io.getReg32(CRTC_EXT_CNTL);
this.dac_cntl = io.getReg32(DAC_CNTL);
this.crtc_h_total_disp = io.getReg32(CRTC_H_TOTAL_DISP);
this.crtc_h_sync_strt_wid = io.getReg32(CRTC_H_SYNC_STRT_WID);
this.crtc_v_total_disp = io.getReg32(CRTC_V_TOTAL_DISP);
this.crtc_v_sync_strt_wid = io.getReg32(CRTC_V_SYNC_STRT_WID);
this.crtc_offset = io.getReg32(CRTC_OFFSET);
this.crtc_offset_cntl = io.getReg32(CRTC_OFFSET_CNTL);
this.crtc_pitch = io.getReg32(CRTC_PITCH);
this.crtc_more_cntl = io.getReg32(CRTC_MORE_CNTL);
} else {
this.crtc_gen_cntl = io.getReg32(CRTC2_GEN_CNTL);
this.crtc_h_total_disp = io.getReg32(CRTC2_H_TOTAL_DISP);
this.crtc_h_sync_strt_wid = io.getReg32(CRTC2_H_SYNC_STRT_WID);
this.crtc_v_total_disp = io.getReg32(CRTC2_V_TOTAL_DISP);
this.crtc_v_sync_strt_wid = io.getReg32(CRTC2_V_SYNC_STRT_WID);
this.crtc_offset = io.getReg32(CRTC2_OFFSET);
this.crtc_offset_cntl = io.getReg32(CRTC2_OFFSET_CNTL);
this.crtc_pitch = io.getReg32(CRTC2_PITCH);
}
}
/**
* Save this state to VGA.
*/
public final void restoreToVGA(RadeonVgaIO io) {
if (crtcIndex == 0) {
io.setReg32(CRTC_GEN_CNTL, crtc_gen_cntl);
io.setRegP32(CRTC_EXT_CNTL, crtc_ext_cntl, CRTC_VSYNC_DIS | CRTC_HSYNC_DIS |
CRTC_DISPLAY_DIS);
// io.setRegP32(DAC_CNTL, dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING);
io.setReg32(DAC_CNTL, dac_cntl);
io.setReg32(CRTC_H_TOTAL_DISP, crtc_h_total_disp);
io.setReg32(CRTC_H_SYNC_STRT_WID, crtc_h_sync_strt_wid);
io.setReg32(CRTC_V_TOTAL_DISP, crtc_v_total_disp);
io.setReg32(CRTC_V_SYNC_STRT_WID, crtc_v_sync_strt_wid);
io.setReg32(CRTC_OFFSET, crtc_offset);
io.setReg32(CRTC_OFFSET_CNTL, crtc_offset_cntl);
io.setReg32(CRTC_PITCH, crtc_pitch);
io.setReg32(CRTC_MORE_CNTL, crtc_more_cntl);
} else {
io.setRegP32(CRTC2_GEN_CNTL, crtc_gen_cntl, CRTC2_VSYNC_DIS | CRTC2_HSYNC_DIS |
CRTC2_DISP_DIS | CRTC2_CRT2_ON);
io.setReg32(CRTC2_H_TOTAL_DISP, crtc_h_total_disp);
io.setReg32(CRTC2_H_SYNC_STRT_WID, crtc_h_sync_strt_wid);
io.setReg32(CRTC2_V_TOTAL_DISP, crtc_v_total_disp);
io.setReg32(CRTC2_V_SYNC_STRT_WID, crtc_v_sync_strt_wid);
io.setReg32(CRTC2_OFFSET, crtc_offset);
io.setReg32(CRTC2_OFFSET_CNTL, crtc_offset_cntl);
io.setReg32(CRTC2_PITCH, crtc_pitch);
}
}
/**
* Set this state up for a given configuration;
*
* @param config
* @param io
*/
final void calcForConfiguration(RadeonConfiguration config, PLLInfo pllInfo, RadeonVgaIO io,
FBInfo fbinfo) {
final DisplayMode mode = config.getDisplayMode();
final int bpp = config.getBitsPerPixel();
final int xres = mode.getWidth();
final int yres = mode.getHeight();
int hSyncStart = mode.getHsyncStart();
int hSyncEnd = mode.getHsyncEnd();
int hTotal = mode.getHTotal();
int vSyncStart = mode.getVsyncStart();
int vSyncEnd = mode.getVsyncEnd();
int vTotal = mode.getVTotal();
final int hsync_wid = Math.min(0x3f, Math.max(1, (hSyncEnd - hSyncStart) / 8));
final int vsync_wid = Math.min(0x1f, Math.max(1, vSyncEnd - vSyncStart));
final int hsync_start = mode.getHsyncStart() - 8 /* + hsync_fudge */;
final int h_sync_pol = 0;
final int v_sync_pol = 0;
final int format = getFormat(bpp);
// newmode.crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) |
// (((mode->xres / 8) - 1) << 16));
//
// newmode.crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) |
// (hsync_wid << 16) | (h_sync_pol << 23));
//
// newmode.crtc_v_total_disp = ((vTotal - 1) & 0xffff) |
// ((mode->yres - 1) << 16);
//
// newmode.crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) |
// (vsync_wid << 16) | (v_sync_pol << 23));
//
// newmode.crtc_pitch = (mode->xres_virtual >> 3);
// newmode.crtc_pitch |= (newmode.crtc_pitch << 16);
this.crtc_h_total_disp = ((hTotal / 8 - 1) & 0x3ff) | ((xres / 8 - 1) << 16);
this.crtc_h_sync_strt_wid =
((hsync_start & 0x1fff) | (hsync_wid << 16) | (h_sync_pol << 23));
this.crtc_v_total_disp = ((vTotal - 1) & 0xffff) | ((yres - 1) << 16);
this.crtc_v_sync_strt_wid =
(((vSyncStart - 1) & 0xfff) | (vsync_wid << 16) | (v_sync_pol << 23));
this.crtc_pitch = roundVWidth(xres, bpp >> 3) / 8;
this.crtc_pitch |= (this.crtc_pitch << 16);
this.crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN | CRTC_CRT_ON;
this.crtc_gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN | (format << 8);
this.dac_cntl |= (DAC_MASK_ALL | DAC_VGA_ADR_EN | DAC_8BIT_EN);
// disable flat panel auto-centering
// (if we have a CRT on CRTC1, this must be disabled;
// if we have a flat panel on CRTC1, we setup CRTC manually, not
// using the auto-centre, automatic-sync-override magic)
this.crtc_more_cntl = 0;
}
private final int getFormat(int bpp) {
final int format;
switch (bpp) {
case 4:
format = 1;
break;
case 8:
format = 2;
break;
case 15:
format = 3;
break; /* 555 */
case 16:
format = 4;
break; /* 565 */
case 24:
format = 5;
break; /* RGB */
case 32:
format = 6;
break; /* xRGB */
default:
throw new IllegalArgumentException("Invalid bpp " + bpp);
}
return format;
}
/**
* round virtual width up to next valid size
*/
static int roundVWidth(int virtual_width, int bpp) {
// we have to make both the CRTC and the accelerator happy:
// - the CRTC wants virtual width in pixels to be a multiple of 8
// - the accelerator expects width in bytes to be a multiple of 64
// to put that together, width (in bytes) must be a multiple of the
// least
// common nominator of bytes-per-pixel*8 (CRTC) and 64 (accelerator);
// if bytes-per-pixel is a power of two and less than 8, the LCM is 64;
// almost all colour depth satisfy that apart from 24 bit; in this case,
// the LCM is 64*3=192
// after dividing by bytes-per-pixel we get pixels: in first case,
// width must be multiple of 64/bytes-per-pixel; in second case,
// width must be multiple of 64*3/3=64
if (bpp != 3) {
return (virtual_width + 64 / bpp - 1) & ~(64 / bpp - 1);
} else {
return (virtual_width + 63) & ~63;
}
}
/**
* @return Returns the crtc_h_sync_strt_wid.
*/
final int getCrtc_h_sync_strt_wid() {
return crtc_h_sync_strt_wid;
}
/**
* @return Returns the crtc_h_total_disp.
*/
final int getCrtc_h_total_disp() {
return crtc_h_total_disp;
}
/**
* @return Returns the crtc_v_sync_strt_wid.
*/
final int getCrtc_v_sync_strt_wid() {
return crtc_v_sync_strt_wid;
}
/**
* @return Returns the crtc_v_total_disp.
*/
final int getCrtc_v_total_disp() {
return crtc_v_total_disp;
}
public String toString() {
return "crtc_h_total_disp:" + crtc_h_total_disp + ", crtc_h_sync_strt_wid:" +
crtc_h_sync_strt_wid + ", crtc_v_total_disp:" + crtc_v_total_disp +
", crtc_v_sync_strt_wid:" + crtc_v_sync_strt_wid + ", crtc_pitch:0x" +
NumberUtils.hex(crtc_pitch) + ", crtc_gen_cntl:0x" +
NumberUtils.hex(crtc_gen_cntl) + ", crtc_ext_cntl:0x" +
NumberUtils.hex(crtc_ext_cntl) + ", dac_cntl:0x" + NumberUtils.hex(dac_cntl) +
", crtc_offset:" + crtc_offset + ", crtc_offset_cntl:0x" +
NumberUtils.hex(crtc_offset_cntl) + ", crtc_more_cntl:0x" +
NumberUtils.hex(crtc_more_cntl);
}
}