|
@@ -960,3 +960,119 @@ marvel_agp_configure(alpha_agp_info *agp)
|
|
|
* The agpgart_be code has not programmed the card yet,
|
|
|
* so we can still tweak mode here.
|
|
|
*/
|
|
|
+ agp_pll = io7->csrs->POx_RST[IO7_AGP_PORT].csr;
|
|
|
+ switch(IO7_PLL_RNGB(agp_pll)) {
|
|
|
+ case 0x4: /* 2x only */
|
|
|
+ /*
|
|
|
+ * The PLL is only programmed for 2x, so adjust the
|
|
|
+ * rate to 2x, if necessary.
|
|
|
+ */
|
|
|
+ if (agp->mode.bits.rate != 2)
|
|
|
+ new_rate = 2;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 0x6: /* 1x / 4x */
|
|
|
+ /*
|
|
|
+ * The PLL is programmed for 1x or 4x. Don't go faster
|
|
|
+ * than requested, so if the requested rate is 2x, use 1x.
|
|
|
+ */
|
|
|
+ if (agp->mode.bits.rate == 2)
|
|
|
+ new_rate = 1;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default: /* ??????? */
|
|
|
+ /*
|
|
|
+ * Don't know what this PLL setting is, take the requested
|
|
|
+ * rate, but warn the user.
|
|
|
+ */
|
|
|
+ printk("%s: unknown PLL setting RNGB=%lx (PLL6_CTL=%016lx)\n",
|
|
|
+ __func__, IO7_PLL_RNGB(agp_pll), agp_pll);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Set the new rate, if necessary.
|
|
|
+ */
|
|
|
+ if (new_rate) {
|
|
|
+ printk("Requested AGP Rate %dX not compatible "
|
|
|
+ "with PLL setting - using %dX\n",
|
|
|
+ agp->mode.bits.rate,
|
|
|
+ new_rate);
|
|
|
+
|
|
|
+ agp->mode.bits.rate = new_rate;
|
|
|
+ }
|
|
|
+
|
|
|
+ printk("Enabling AGP on hose %d: %dX%s RQ %d\n",
|
|
|
+ agp->hose->index, agp->mode.bits.rate,
|
|
|
+ agp->mode.bits.sba ? " - SBA" : "", agp->mode.bits.rq);
|
|
|
+
|
|
|
+ csrs->AGP_CMD.csr = agp->mode.lw;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+marvel_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *mem)
|
|
|
+{
|
|
|
+ struct marvel_agp_aperture *aper = agp->aperture.sysdata;
|
|
|
+ return iommu_bind(aper->arena, aper->pg_start + pg_start,
|
|
|
+ mem->page_count, mem->pages);
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+marvel_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *mem)
|
|
|
+{
|
|
|
+ struct marvel_agp_aperture *aper = agp->aperture.sysdata;
|
|
|
+ return iommu_unbind(aper->arena, aper->pg_start + pg_start,
|
|
|
+ mem->page_count);
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned long
|
|
|
+marvel_agp_translate(alpha_agp_info *agp, dma_addr_t addr)
|
|
|
+{
|
|
|
+ struct marvel_agp_aperture *aper = agp->aperture.sysdata;
|
|
|
+ unsigned long baddr = addr - aper->arena->dma_base;
|
|
|
+ unsigned long pte;
|
|
|
+
|
|
|
+ if (addr < agp->aperture.bus_base ||
|
|
|
+ addr >= agp->aperture.bus_base + agp->aperture.size) {
|
|
|
+ printk("%s: addr out of range\n", __func__);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ pte = aper->arena->ptes[baddr >> PAGE_SHIFT];
|
|
|
+ if (!(pte & 1)) {
|
|
|
+ printk("%s: pte not valid\n", __func__);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ return (pte >> 1) << PAGE_SHIFT;
|
|
|
+}
|
|
|
+
|
|
|
+struct alpha_agp_ops marvel_agp_ops =
|
|
|
+{
|
|
|
+ .setup = marvel_agp_setup,
|
|
|
+ .cleanup = marvel_agp_cleanup,
|
|
|
+ .configure = marvel_agp_configure,
|
|
|
+ .bind = marvel_agp_bind_memory,
|
|
|
+ .unbind = marvel_agp_unbind_memory,
|
|
|
+ .translate = marvel_agp_translate
|
|
|
+};
|
|
|
+
|
|
|
+alpha_agp_info *
|
|
|
+marvel_agp_info(void)
|
|
|
+{
|
|
|
+ struct pci_controller *hose;
|
|
|
+ io7_ioport_csrs *csrs;
|
|
|
+ alpha_agp_info *agp;
|
|
|
+ struct io7 *io7;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Find the first IO7 with an AGP card.
|
|
|
+ *
|
|
|
+ * FIXME -- there should be a better way (we want to be able to
|
|
|
+ * specify and what if the agp card is not video???)
|
|
|
+ */
|
|
|
+ hose = NULL;
|
|
|
+ for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; ) {
|
|
|
+ struct pci_controller *h;
|
|
|
+ vuip addr;
|