+ static unsigned int pmagbbfb_freqs[] __initdata = {
+ 130808, 119843, 104000, 92980, 74367, 72800,
+ 69197, 66000, 65000, 50350, 36000, 32000, 25175
+ };
+ struct pmagbbfb_par *par = info->par;
+ u32 count0 = 8, count1 = 8, counttc = 16 * 256 + 8;
+ u32 freq0, freq1, freqtc = get_tc_speed() / 250;
+ int i, j;
+
+ gp0_write(par, 0); /* select Osc0 */
+ for (j = 0; j < 16; j++) {
+ mb();
+ sfb_write(par, SFB_REG_TCCLK_COUNT, 0);
+ mb();
+ for (i = 0; i < 100; i++) { /* nominally max. 20.5us */
+ if (sfb_read(par, SFB_REG_TCCLK_COUNT) == 0)
+ break;
+ udelay(1);
+ }
+ count0 += sfb_read(par, SFB_REG_VIDCLK_COUNT);
+ }
+
+ gp0_write(par, 1); /* select Osc1 */
+ for (j = 0; j < 16; j++) {
+ mb();
+ sfb_write(par, SFB_REG_TCCLK_COUNT, 0);
+
+ for (i = 0; i < 100; i++) { /* nominally max. 20.5us */
+ if (sfb_read(par, SFB_REG_TCCLK_COUNT) == 0)
+ break;
+ udelay(1);
+ }
+ count1 += sfb_read(par, SFB_REG_VIDCLK_COUNT);
+ }
+
+ freq0 = (freqtc * count0 + counttc / 2) / counttc;
+ par->osc0 = freq0;
+ if (freq0 >= pmagbbfb_freqs[0] - (pmagbbfb_freqs[0] + 32) / 64 &&
+ freq0 <= pmagbbfb_freqs[0] + (pmagbbfb_freqs[0] + 32) / 64)
+ par->osc0 = pmagbbfb_freqs[0];
+
+ freq1 = (par->osc0 * count1 + count0 / 2) / count0;
+ par->osc1 = freq1;
+ for (i = 0; i < ARRAY_SIZE(pmagbbfb_freqs); i++)
+ if (freq1 >= pmagbbfb_freqs[i] -
+ (pmagbbfb_freqs[i] + 128) / 256 &&
+ freq1 <= pmagbbfb_freqs[i] +
+ (pmagbbfb_freqs[i] + 128) / 256) {
+ par->osc1 = pmagbbfb_freqs[i];
+ break;
+ }
+
+ if (par->osc0 - par->osc1 <= (par->osc0 + par->osc1 + 256) / 512 ||
+ par->osc1 - par->osc0 <= (par->osc0 + par->osc1 + 256) / 512)
+ par->osc1 = 0;
+
+ gp0_write(par, par->osc1 != 0); /* reselect OscX */
+
+ info->var.pixclock = par->osc1 ?
+ (1000000000 + par->osc1 / 2) / par->osc1 :
+ (1000000000 + par->osc0 / 2) / par->osc0;
+};
+
+
+static int __init pmagbbfb_init_one(int slot)
+{
+ char freq0[12], freq1[12];
+ struct fb_info *info;
+ struct pmagbbfb_par *par;
+ unsigned long base_addr;
+ u32 vid_base;
+
+ info = framebuffer_alloc(sizeof(struct pmagbbfb_par), NULL);
+ if (!info)
+ return -ENOMEM;
+
+ par = info->par;
+ par->slot = slot;
+ claim_tc_card(par->slot);
+
+ base_addr = get_tc_base_addr(par->slot);
+
+ par->next = root_pmagbbfb_dev;
+ root_pmagbbfb_dev = info;
+
+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
+ goto err_alloc;
+