162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Zorro Bus Services 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 1995-2003 Geert Uytterhoeven 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 762306a36Sopenharmony_ci * License. See the file COPYING in the main directory of this archive 862306a36Sopenharmony_ci * for more details. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/types.h> 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/zorro.h> 1662306a36Sopenharmony_ci#include <linux/bitops.h> 1762306a36Sopenharmony_ci#include <linux/string.h> 1862306a36Sopenharmony_ci#include <linux/platform_device.h> 1962306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <asm/byteorder.h> 2362306a36Sopenharmony_ci#include <asm/setup.h> 2462306a36Sopenharmony_ci#include <asm/amigahw.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "zorro.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci /* 3062306a36Sopenharmony_ci * Zorro Expansion Devices 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ciunsigned int zorro_num_autocon; 3462306a36Sopenharmony_cistruct zorro_dev_init zorro_autocon_init[ZORRO_NUM_AUTO] __initdata; 3562306a36Sopenharmony_cistruct zorro_dev *zorro_autocon; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci /* 3962306a36Sopenharmony_ci * Zorro bus 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistruct zorro_bus { 4362306a36Sopenharmony_ci struct device dev; 4462306a36Sopenharmony_ci struct zorro_dev devices[]; 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* 4962306a36Sopenharmony_ci * Find Zorro Devices 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistruct zorro_dev *zorro_find_device(zorro_id id, struct zorro_dev *from) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci struct zorro_dev *z; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci if (!zorro_num_autocon) 5762306a36Sopenharmony_ci return NULL; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci for (z = from ? from+1 : &zorro_autocon[0]; 6062306a36Sopenharmony_ci z < zorro_autocon+zorro_num_autocon; 6162306a36Sopenharmony_ci z++) 6262306a36Sopenharmony_ci if (id == ZORRO_WILDCARD || id == z->id) 6362306a36Sopenharmony_ci return z; 6462306a36Sopenharmony_ci return NULL; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ciEXPORT_SYMBOL(zorro_find_device); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci /* 7062306a36Sopenharmony_ci * Bitmask indicating portions of available Zorro II RAM that are unused 7162306a36Sopenharmony_ci * by the system. Every bit represents a 64K chunk, for a maximum of 8MB 7262306a36Sopenharmony_ci * (128 chunks, physical 0x00200000-0x009fffff). 7362306a36Sopenharmony_ci * 7462306a36Sopenharmony_ci * If you want to use (= allocate) portions of this RAM, you should clear 7562306a36Sopenharmony_ci * the corresponding bits. 7662306a36Sopenharmony_ci * 7762306a36Sopenharmony_ci * Possible uses: 7862306a36Sopenharmony_ci * - z2ram device 7962306a36Sopenharmony_ci * - SCSI DMA bounce buffers 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * FIXME: use the normal resource management 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ciDECLARE_BITMAP(zorro_unused_z2ram, 128); 8562306a36Sopenharmony_ciEXPORT_SYMBOL(zorro_unused_z2ram); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic void __init mark_region(unsigned long start, unsigned long end, 8962306a36Sopenharmony_ci int flag) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci if (flag) 9262306a36Sopenharmony_ci start += Z2RAM_CHUNKMASK; 9362306a36Sopenharmony_ci else 9462306a36Sopenharmony_ci end += Z2RAM_CHUNKMASK; 9562306a36Sopenharmony_ci start &= ~Z2RAM_CHUNKMASK; 9662306a36Sopenharmony_ci end &= ~Z2RAM_CHUNKMASK; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (end <= Z2RAM_START || start >= Z2RAM_END) 9962306a36Sopenharmony_ci return; 10062306a36Sopenharmony_ci start = start < Z2RAM_START ? 0x00000000 : start-Z2RAM_START; 10162306a36Sopenharmony_ci end = end > Z2RAM_END ? Z2RAM_SIZE : end-Z2RAM_START; 10262306a36Sopenharmony_ci while (start < end) { 10362306a36Sopenharmony_ci u32 chunk = start>>Z2RAM_CHUNKSHIFT; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (flag) 10662306a36Sopenharmony_ci set_bit(chunk, zorro_unused_z2ram); 10762306a36Sopenharmony_ci else 10862306a36Sopenharmony_ci clear_bit(chunk, zorro_unused_z2ram); 10962306a36Sopenharmony_ci start += Z2RAM_CHUNKSIZE; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic struct resource __init *zorro_find_parent_resource( 11562306a36Sopenharmony_ci struct platform_device *bridge, struct zorro_dev *z) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci int i; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci for (i = 0; i < bridge->num_resources; i++) { 12062306a36Sopenharmony_ci struct resource *r = &bridge->resource[i]; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (zorro_resource_start(z) >= r->start && 12362306a36Sopenharmony_ci zorro_resource_end(z) <= r->end) 12462306a36Sopenharmony_ci return r; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci return &iomem_resource; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic int __init amiga_zorro_probe(struct platform_device *pdev) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci struct zorro_bus *bus; 13462306a36Sopenharmony_ci struct zorro_dev_init *zi; 13562306a36Sopenharmony_ci struct zorro_dev *z; 13662306a36Sopenharmony_ci struct resource *r; 13762306a36Sopenharmony_ci unsigned int i; 13862306a36Sopenharmony_ci int error; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* Initialize the Zorro bus */ 14162306a36Sopenharmony_ci bus = kzalloc(struct_size(bus, devices, zorro_num_autocon), 14262306a36Sopenharmony_ci GFP_KERNEL); 14362306a36Sopenharmony_ci if (!bus) 14462306a36Sopenharmony_ci return -ENOMEM; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci zorro_autocon = bus->devices; 14762306a36Sopenharmony_ci bus->dev.parent = &pdev->dev; 14862306a36Sopenharmony_ci dev_set_name(&bus->dev, zorro_bus_type.name); 14962306a36Sopenharmony_ci error = device_register(&bus->dev); 15062306a36Sopenharmony_ci if (error) { 15162306a36Sopenharmony_ci pr_err("Zorro: Error registering zorro_bus\n"); 15262306a36Sopenharmony_ci put_device(&bus->dev); 15362306a36Sopenharmony_ci kfree(bus); 15462306a36Sopenharmony_ci return error; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci platform_set_drvdata(pdev, bus); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci pr_info("Zorro: Probing AutoConfig expansion devices: %u device%s\n", 15962306a36Sopenharmony_ci zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s"); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* First identify all devices ... */ 16262306a36Sopenharmony_ci for (i = 0; i < zorro_num_autocon; i++) { 16362306a36Sopenharmony_ci zi = &zorro_autocon_init[i]; 16462306a36Sopenharmony_ci z = &zorro_autocon[i]; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci z->rom = zi->rom; 16762306a36Sopenharmony_ci z->id = (be16_to_cpu(z->rom.er_Manufacturer) << 16) | 16862306a36Sopenharmony_ci (z->rom.er_Product << 8); 16962306a36Sopenharmony_ci if (z->id == ZORRO_PROD_GVP_EPC_BASE) { 17062306a36Sopenharmony_ci /* GVP quirk */ 17162306a36Sopenharmony_ci unsigned long magic = zi->boardaddr + 0x8000; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci z->id |= *(u16 *)ZTWO_VADDR(magic) & GVP_PRODMASK; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci z->slotaddr = zi->slotaddr; 17662306a36Sopenharmony_ci z->slotsize = zi->slotsize; 17762306a36Sopenharmony_ci sprintf(z->name, "Zorro device %08x", z->id); 17862306a36Sopenharmony_ci zorro_name_device(z); 17962306a36Sopenharmony_ci z->resource.start = zi->boardaddr; 18062306a36Sopenharmony_ci z->resource.end = zi->boardaddr + zi->boardsize - 1; 18162306a36Sopenharmony_ci z->resource.name = z->name; 18262306a36Sopenharmony_ci r = zorro_find_parent_resource(pdev, z); 18362306a36Sopenharmony_ci error = request_resource(r, &z->resource); 18462306a36Sopenharmony_ci if (error && !(z->rom.er_Type & ERTF_MEMLIST)) 18562306a36Sopenharmony_ci dev_err(&bus->dev, 18662306a36Sopenharmony_ci "Address space collision on device %s %pR\n", 18762306a36Sopenharmony_ci z->name, &z->resource); 18862306a36Sopenharmony_ci z->dev.parent = &bus->dev; 18962306a36Sopenharmony_ci z->dev.bus = &zorro_bus_type; 19062306a36Sopenharmony_ci z->dev.id = i; 19162306a36Sopenharmony_ci switch (z->rom.er_Type & ERT_TYPEMASK) { 19262306a36Sopenharmony_ci case ERT_ZORROIII: 19362306a36Sopenharmony_ci z->dev.coherent_dma_mask = DMA_BIT_MASK(32); 19462306a36Sopenharmony_ci break; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci case ERT_ZORROII: 19762306a36Sopenharmony_ci default: 19862306a36Sopenharmony_ci z->dev.coherent_dma_mask = DMA_BIT_MASK(24); 19962306a36Sopenharmony_ci break; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci z->dev.dma_mask = &z->dev.coherent_dma_mask; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* ... then register them */ 20562306a36Sopenharmony_ci for (i = 0; i < zorro_num_autocon; i++) { 20662306a36Sopenharmony_ci z = &zorro_autocon[i]; 20762306a36Sopenharmony_ci error = device_register(&z->dev); 20862306a36Sopenharmony_ci if (error) { 20962306a36Sopenharmony_ci dev_err(&bus->dev, "Error registering device %s\n", 21062306a36Sopenharmony_ci z->name); 21162306a36Sopenharmony_ci put_device(&z->dev); 21262306a36Sopenharmony_ci continue; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* Mark all available Zorro II memory */ 21762306a36Sopenharmony_ci zorro_for_each_dev(z) { 21862306a36Sopenharmony_ci if (z->rom.er_Type & ERTF_MEMLIST) 21962306a36Sopenharmony_ci mark_region(zorro_resource_start(z), 22062306a36Sopenharmony_ci zorro_resource_end(z)+1, 1); 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* Unmark all used Zorro II memory */ 22462306a36Sopenharmony_ci for (i = 0; i < m68k_num_memory; i++) 22562306a36Sopenharmony_ci if (m68k_memory[i].addr < 16*1024*1024) 22662306a36Sopenharmony_ci mark_region(m68k_memory[i].addr, 22762306a36Sopenharmony_ci m68k_memory[i].addr+m68k_memory[i].size, 22862306a36Sopenharmony_ci 0); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci return 0; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic struct platform_driver amiga_zorro_driver = { 23462306a36Sopenharmony_ci .driver = { 23562306a36Sopenharmony_ci .name = "amiga-zorro", 23662306a36Sopenharmony_ci }, 23762306a36Sopenharmony_ci}; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int __init amiga_zorro_init(void) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci return platform_driver_probe(&amiga_zorro_driver, amiga_zorro_probe); 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cimodule_init(amiga_zorro_init); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 247