Итак, имеем связку AT91SAM9260 + KSZ8041TL с подключением по MII. Все это работает под PowerPac TCP/IP. Пробуем запустить пример под названием OS_IP_Start.
Проблема №1: PHY не виден, вываливается сообщение типа "DRIVER: PHY not found".
Проблема №2: после решения первой, система не работает в режиме MII. Не пингуется.

Обе проблемы кроются в библиотечной функции IP_Init, которая вызывается из MainTask.
Под отладчиком видно, что она делает (привожу только значимые для нас моменты в хронологическом порядке):
- вызов IP_X_Config
- инициализация структуры IP_PHY_CONTEXT, и, в частности, переменной UseRMII
- вызов BSP_ETH_Init
- формирование сигнала NRST, который подается на PHY
- вызов _IP_PHY_Init, которая ищет доступные PHY, подключенные к процессору

Первая проблема объясняется отсутствием задержки между аппаратным сбросом PHY и доступом к его регистрам из _IP_PHY_Init.
Для DM9161, который стоит на отладочной плате от Atmel это прокатывает. А вот MICREL рекомендует выдержать паузу в 100мкс минимум.

Вторая проблема. Для использования MII документация на PowerPac TCP/IP рекомендует использовать вызов функции IP_NI_ConfigPHYMode из IP_X_Config.
IP_NI_ConfigPHYMode действительно изменяет значение UseRMII как нам нужно, но после IP_X_Config переменная принудительно устанавливается в 1 (RMII) не смотря ни на какие дефайны.
Более поздний вызов IP_NI_ConfigPHYMode (например из BSP_ETH_Init) срабатывает, но приводит к сообщению типа "too late config call".

Обе проблемы решаются написанием своей версии _IP_PHY_Init. Ниже приведен исходный текст.
CODE

#define MY_USE_RMII 0 // Будем использовать MII

void MainTask(void)
{

.....

IP_PHY_Generic.pfInit = &MY_IP_PHY_Init; // Заменяем библиотечную _IP_PHY_Init на свою перед вызовом IP_Init
IP_Init();

......

}

int MY_IP_PHY_Init(IP_PHY_CONTEXT * pContext)
{
U8 CurrAddr;
U8 LastAddr;
unsigned Data, Data1;

pContext->UseRMII = MY_USE_RMII; // Решаем проблему с MII
OS_Delay (2); // Решаем проблему с KSZ8041

LastAddr = pContext->Addr; // Считываем адрес PHY (при первом вызове должно быть 0xFF)
if (LastAddr != 0xFF) CurrAddr = LastAddr; // Видимо PHY уже был найден (MY_IP_PHY_Init уже вызывалась)
else
{
CurrAddr = 0; // Адресное пространство, в котором ищется PHY (0...31)
LastAddr = 0x1F;
}
while (1)
{
pContext->Addr = CurrAddr; // Сохраняем текущий опрашиваемый адрес
Data = pContext->pAccess->pfRead(pContext, 4); // Считываем Register 4h - Auto-Negotiation Advertisement
if ((Data & 0x1F) == 0x01) // Selector Field == 00001 (IEEE-802.3)
{
Data = pContext->pAccess->pfRead(pContext, 2); // Считываем Register 2h - PHY ID
if ((Data & 0xFFFF) != 0xFFFF) // Считалось осмысленное значение
{
Data1 = pContext->pAccess->pfRead(pContext, 2); // Повторно считываем Register 2h - PHY ID
if (Data == Data1) // Считалось корректно
{
Data1 = Data & 0xFFFF;
IP_Logf_Application("MY_DRIVER: PHY found. ID = 0x%x, Address = 0x%x", Data1, CurrAddr);
Data = pContext->pAccess->pfRead(pContext, 0); // Считываем Register 0h - Basic Control
Data &= 0xFFFF;
Data |= 0x8000; // Устанавливаем бит Software Reset
pContext->Bmcr = (U16)Data;
pContext->pAccess->pfWrite(pContext, 0, Data); // Запускаем Software Reset
while (1)
{
Data = pContext->pAccess->pfRead(pContext, 0); // Считываем Register 0h - Basic Control
if (Data & 0x8000) continue; // Ждем окончания Software Reset
else break;
}

if (Data1 == 0x181) // Этот блок только для DAVICOM
{
Data = pContext->pAccess->pfRead(pContext, 16);
Data1 = Data & 0xEFF;
if (pContext->UseRMII) Data1 |= 0x100;
if (Data != Data1)
{
pContext->pAccess->pfWrite(pContext, 16, Data1);
IP_Logf_Application("MY_DRIVER: PHY Mode selected RMII/MII incorrect. Fixed");
}
}

Data = pContext->pAccess->pfRead(pContext, 4); // Считываем Register 4h - Auto-Negotiation Advertisement
Data &= 0xEBF; // Сбрасываем FullDuplex для 10Tx и 100Tx
pContext->Anar = (U16)Data;
pContext->pAccess->pfWrite(pContext, 4, Data); // Прописываем в Register 4h - Auto-Negotiation Advertisement
pContext->Bmcr = 0x1200; // Запускаем процесс Auto-Negotiation
pContext->pAccess->pfWrite(pContext, 0, 0x1200);

break;
}
}
}

CurrAddr++;
if(CurrAddr > LastAddr)
{
IP_Warnf_Application("MY_DRIVER: No PHY found.");
break;
}
}

return 0;
}